본문 바로가기
Language/Effective java

람다와 스트림

by y.j 2022. 7. 24.
728x90

익명 클래스보다는 람다를 사용하라

람다의 장점

1. 코드의 가독성이 좋아진다.

2. 매개변수 타입을 생략해도 된다.

 

익명 클래스

Collections.sort(words, new Comparator<Object>() {
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
})

람다

Collections.sort(words, 
        (s1, s2) -> Integer.compare(s1.length(), s2.length())
)

생성 메서드 활용

Collections.sort(words, comparingInt(String::length));
words.sort(comparingInt(String::length));

 

Operation enum바꿔보기

public enum Operation2 {
    PLUS("+", (x,y) -> {return x + y;}) {
        public double apply(double x, double y) {return x + y;}
    },
    MINUS("-", (x,y) -> { return x - y; }) {
        public double apply(double x, double y) {return x - y;}
    },
    TIMES("*", (x,y) -> {return x * y; }) {
        public double apply(double x, double y) {return x * y;}
    },
    DIVIDE("/", (x,y) -> { return x / y;});

    private final String symbol;
    private final DoubleBinaryOperator op;

    Operation2(String symbol, DoubleBinaryOperator op) {
        this.symbol = symbol;
        this.op = op;
    }

    public double apply(double x, double y) {
        return op.applyAsDouble(x, y);
    };

    @Override
    public String toString() {
        return fromString(symbol).toString();
    }
    public static final Map<String, Operation2> stringToEnum =
            Stream.of(values()).collect(
                    toMap(Object::toString, e->e));

    public static Optional<Operation2> fromString(String symbol) {
        return Optional.ofNullable(stringToEnum.get(symbol));
    }
}

* DoubleBinaryOperator : 기능적인 인터페이스이므로 람다 식 또는 메서드 참조의 할당 대상으로 사용한다.

 

람다의 단점

람다는 이름도 없고 문서화도 못한다. 코드 차체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야 한다. 람다의 this는 자기 자신이 아니라 바깥 인스턴스를 가르킨다.

 

 

람다보다는 메서드 참조를 사용하라

람다보다 메서드 참조가 더 가독성이 좋고 간결하게 만들 수 있다. 람다가 할 수 없는 일이라면 메서드 참조도 할 수 없다.

 

람다식

map.merge(key, 1, (count, incr) -> count + incr);

메서드 참조

map.merge(key, 1, Integer::sum);

 

반드시 메서드 참조가 더 간결한 것은 아니다.

 

메서드 참조

service.execute(GoshThisClassNameIsHumongous::action);

람다식

service.execute(() -> action());

 

메서드 참조의 유형

메서드 참조 유형 설                명 같은 기능을 하는 람다
정적   Integer::parseInt str -> Integer.parseInt(str)
한정적(인스턴스) 수신 객체를 특정함. 정적 참조와 비슷 Instant.now()::isAfter Instant then = Instant.now()
t -> then.isAfter(t)
비한정적(인스턴스) 인스턴스 메서드 참조
함수객체를 적용하는 시점에 수신 객체를 알려줌.
String::toLowerCase str -> str.toLowerCase()
클래스 생성자 팩터리 객체로 사용 TreeMap<K, V>::new () -> new TreeMap<K, V>()
배열 생성자   int[]::new len -> new int[len]

 

표준 함수형 인터페이스를 사용하라

자바가 람다를 지원하게 되면서 템플릿메서드 패턴보다는 함수객체를 받는 정적 팩터리나 생성자를 제공하는 것이 더 좋은 사례로 뽑힌다. 따라서 함수 객체를 매개변수로 받는 생성자와 메서드를 더 많이 만들어야 한다. 필요한 용도에 맞는 것이 자바에서 제공하므로 표준 함수형 인터페이스를 활용하는 것이 좋다.

인터페이스 함수 시그니처
UnaryOperator<T> T apply(T t) String::toLowerCase
BinaryOperator<T> T apply(T t1, T t2) BigInteger::add
Predicate<T> boolean test(T t) Collection::isEmpty
Function<T,R> R apply(T t) Arrays::asList
Supplier<T> T get() Instant::now
Consumer<T> void accept(T t) System.out::println

UnaryOperator<T> : interface인수가 1개인 타입, 반환값과 인수의 타입이 같다.

BinaryOperator<T> : interface인수가 2개인 타입, 반환값과 인수의 타입이 같다.

Supplier<T>            : 인수를 제공받지 않는다.

Consumer<T>         : 반환값이 존재하지 않는다.

 

함수형 인터페이스는 범주형 이름을 사용한다.

Predicate는 int, double, long에 맞춰 IntPredicate, DoublePredicate, LongPredicate가 존재한다.

Function는 SrcToResult가 이름에 각각 붙는다. LongToIntFunction.

함수형 인터페이스 개수가 많지만 범용적인 이름을 사용하려고 했으니 잘 사용하자.

 

기본 함수형 인터페이스에 박싱된 기본 타입을 넣어 사용하지는 말자.

Long같은 객체는 새로운 객체를 계속 반환하므로 메모리 낭비와 성능에 문제가 된다.

 

함수형 인터페이스를 구현할 때 신중하자.

  • 자주 쓰이며, 이름 자체가 용도를 명확히 설명해준다.
  • 반드시 따라야 하는 규약이 있다.
  • 유용한 디폴트 메서드를 제공 할 수 있다.
  • 인터페이스를 자신이 구현하는 것이 아니므로 신중하게 설계해야 한다.

 

함수형 인터페이스에는 @FunctionInterface를 꼭 붙여주자.

  • 클래스의 코드나 설명 문서를 읽을 이에게 그 인터페이스가 람다용으로 설게된 것임을 알려준다.
  • 추상 메서드를 오직 하나만 가지고 있어야 컴파일 되게 해준다.
  • 그 결과 유지보수 과정에서 누군가 실수로 메서드를 추가하지 못하게 막아준다.
  • 다중정의는 주의하자. 올바른 메서드를 알려주기 위해서 형변환해야 할 때가 많이 생긴다.

 

728x90

'Language > Effective java' 카테고리의 다른 글

람다와 스트림  (0) 2022.07.29
람다와 스트림  (0) 2022.07.26
열거 타입과 애너테이션  (0) 2022.07.23
열거 타입과 애너테이션  (0) 2022.07.20
열거 타입과 애너테이션  (0) 2022.07.18

댓글