[Java] 람다식을 더 짧게 - 메서드 참조 Method Reference공부/Java2023. 8. 2. 20:54
Table of Contents
반응형
Method Reference
- Java 8 도입
- 하나의 메서드만 호출하는 람다식은 메서드 참조로 간소화하여 표현가능하다 (전달 인자를 생략하여 코드 간결해짐)
- 구분자로 :: 사용
- 아래의 4가지 유형 있음
아래 코드는 정렬할 때 [클래스 구현 -> 람다 -> 람다 간소화 -> 정적 메서드 참조]에 대한 비교 예시이다
// 배열 선언
Person[] perons = ...
// (1) Comparator 구현 방식 (구 시대적)
class PersonAgeComparator implements Comparator<Person> {
public int compare(Person a, Person b) {
return a.age().compareTo(b.age());
}
}
Arrays.sort(persons, new PersonAgeComparator()); // 나이순 오름차순 정렬
// (2) 람다 표현식을 사용하는 경우
Arrays.sort(persons, (Person a, Person b) -> {
return a.age().compareTo(b.age();
});
// (3) 람다 표현식 간소화
Arrays.sort(persons, (a, b) -> Person.compare(a, b)); // Person 클래스 Comparable 구현했을 때
// (4) 정적 메서드 참조를 할 경우, 전달 인자 생략
Arrays.sort(persons, Person::compare);
1. Reference to a static method (정적 메서드 참조)
className::staticMethodName 형식으로 표기
임의 클래스가 있을 때
public class MethodReferenceTest {
public static <T> T mergeThing(T a, T b, BiFunction<T, T, T> merger) {
return merger.apply(a, b);
}
public static String appendStrings(String a, String b) {
return a + b;
}
public String appendString(String a, String b) {
return a + b;
}
}
예시
String t1 = "Hello";
String t2 = "World!";
String result = "HelloWorld!";
// Calling the method mergeThings with a lambda expression (람다 표현식 사용)
String lambdaResult = MethodReferenceTest.mergeThing(t1, t2, (a, b) -> a + b);
assertThat(lambdaResult).isEqualTo(result); // Ok
// *Reference to a static method (클래스 정적 메서드 참조)
String staticMethodResult = MethodReferenceTest.mergeThing(t1, t2, MethodReferenceTest::appendStrings);
assertThat(staticMethodResult).isEqualTo(result); // Ok
2. Reference to an instance method of a particular object (인스턴스 메서드 참조)
objectName::instanceMethodName 형식으로 표기
- new 키워드로 인스턴스 선언한 객체의 메서드 참조한다
- public String appendString() {..} 인스턴스 메서드 사용
예시
String t1 = "Hello";
String t2 = "World!";
String result = "HelloWorld!";
// Reference to an instance method of a particular object
MethodReferenceTest obj = new MethodReferenceTest();
String instanceMethodResult = MethodReferenceTest.mergeThing(t1, t2, obj::appendString);
assertThat(instanceMethodResult).isEqualTo(result); // Ok
3. Reference to an instance method of an arbitrary object of a particular type
ClassName::instanceMethodName 형식으로 표기
- 인스턴스 참조 유형으로 String, Integer, List 등에서 제공되는 클래스의 인스턴스 메서드 참조
예시
String t1 = "Hello";
String t2 = "World!";
String result = "HelloWorld!";
String particularTypeResult = MethodReferenceTest.mergeThing(t1, t2, String::concat); // t1.concat(t2)
assertThat(particularTypeResult).isEqualTo(result); // Ok
Integer::compareTo (오름차순 정렬)
//Integet.class
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
@Test
void instanceMethodReference() {
List<Integer> numbers = Arrays.asList(5, 3, 50, 24, 40, 2, 9, 18);
List<Integer> sorted = numbers.stream().sorted(Integer::compareTo).collect(Collectors.toList());
assertThat(sorted).containsExactly(2, 3, 5, 9, 18, 24, 40, 50);
}
String::compareToIgnoreCase (오름차순 정렬)
// String.class
public int compareToIgnoreCase(String str) {
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
@Test
void instanceMethodOfAnArbitraryObjectOfParticularType() {
String[] strings = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(strings, String::compareToIgnoreCase);
assertThat(strings)
.containsExactly("Barbara", "James", "John", "Linda", "Mary", "Michael", "Patricia", "Robert");
}
4. Reference to a constructor (생성자 참조)
className::new 형식으로 표기
- 당연히 생성자의 파라미터 개수 맞춰줘야 함
예시
class Bicycle {
String brand;
public Bicycle(String brand) { this.brand = brand; }
}
@DisplayName("")
@Test
void constructReferenceMethod2() {
List<String> bikeBrand = Arrays.asList("Giant", "Scott", "Trek", "GT");
Bicycle[] bicycles = bikeBrand.stream().map(Bicycle::new).toArray(Bicycle[]::new);
assertThat(bicycles).hasSize(4);
}
아래와 같은 추상 클래스 구현한 상속관계의 클래스가 있을 때
public abstract class Car {
protected String name;
protected String brand;
public Car(String name, String brand) {
this.name = name;
this.brand = brand;
}
public abstract void drive();
}
public class Sedan extends Car{
public Sedan(String name, String brand) {
super(name, brand);
}
@Override
public void drive() {
System.out.println(String.format("Driving a sedan %s name %s", name, brand));
}
}
public class Suv extends Car{
public Suv(String name, String brand) {
super(name, brand);
}
@Override
public void drive() {
System.out.println(String.format("Driving a Suv %s name %s", name, brand));
}
}
public class Van extends Car {
public Van(String name, String brand) {
super(name, brand);
}
@Override
public void drive() {
System.out.println(String.format("Driving a Van %s name %s", name, brand));
}
}
Map에 각 키 마다 참조를 넣어두고 사용할 수 도 있다. (패스트 캠퍼스 참고.)
@Test
void constructorMethodReferenceMap() {
// {키, name, brand}
String[][] inputs = new String[][] {
{"sedan", "Sonata", "Hyundai"},
{"van", "Sienna", "Toyota"},
{"sedan", "Model S", "Tesla"},
{"suv", "Sorento", "KIA"}
};
// BiFunction -> String, String 인자를 받아 Car 타입을 리턴
Map<String, BiFunction<String, String, Car>> constructorMap = new HashMap<>();
constructorMap.put("sedan", Sedan::new);
constructorMap.put("van", Van::new);
constructorMap.put("suv", Suv::new);
List<Car> cars = new ArrayList<>();
for(String[] input : inputs) {
cars.add(constructorMap.get(input[0]).apply(input[1], input[2]));
}
assertThat(cars).hasSize(4); // Ok
}
참고
https://fastcampus.co.kr/dev_red_lsh
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
반응형
'공부 > Java' 카테고리의 다른 글
[Java] Stream 생성 (파일 데이터 제외) (0) | 2023.08.03 |
---|---|
[Java] Stream API (0) | 2023.08.03 |
[Java] Optional 클래스 메서드 (자바의 정석) (0) | 2023.08.01 |
[Java] Iterators 인터페이스 (자바의 정석) (0) | 2023.07.31 |
[Java] Arrays 클래스 메서드 (자바의 정석) (0) | 2023.07.31 |
@leejinwoo1126 :: 천천히 하나씩
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!