peaches-book-study / effective-java

이펙티브 자바 3/E
0 stars 2 forks source link

Item 42. 익명 클래스보다는 람다를 사용하라 #41

Open byunghyunkim0 opened 3 months ago

byunghyunkim0 commented 3 months ago

Chapter : 7. 람다와 스트림

Item : 42. 익명 클래스보다는 람다를 사용하라

Assignee : byunghyunkim0


🍑 서론

// 익명 클래스의 인스턴스를 함수 객체로 사용 - 낡은 기법
// 문자열을 길이순으로 정렬할때 정렬을 위한 비교함수로 익명클래스를 사용한 예
public class Main {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("abcdef", "abc", "abcd");
        Collections.sort(words, new Comparator<String>() {
            public int compare(String s1, String s2){
                return Integer.compare(s1.length(), s2.length());
            }
        });
        System.out.println(words);
    }
}

public class Main { public static void main(String[] args) { List words = Arrays.asList("abcdef", "abc", "abcd"); // 비교자 생성 메서드 Collections.sort(words, comparingInt(String::length)); // List 인터페이스에 추가된 sort 메서드를 이용하면 더 짧아짐 words.sort(comparingInt(String::length)); System.out.println(words); } }

- 비교자 생성 메서드를 사용하면 더 간결하게 만들수 있다.

```java
// 함수 객체(람다)를 인스턴스 필드에 저장해 상수별 동작을 구현한 열거 타입
public enum Operation {
    PLUS("+", (x, y) -> x + y),
    MINUS("-", (x, y) -> x - y),
    TIMES("*", (x, y) -> x * y),
    DIVIDE("/", (x, y) -> x / y);

    private final String symbol;
    private final DoubleBinaryOperator op;

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

    @Override
    public String toString() { return symbol; }

    public abstract double apply(double x, double y) {
        return op.applyAsDouble(x, y);
    };
}
DoubleBinaryOperator
double 타입 인수 2개를 받아 double 타입 결과를 돌려줌

열거 타입에서 람다 유의사항

  1. 람다는 이름이 없고 문서화도 못한다.
    • 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야한다.
  2. 열거 타입 생성자 안의 람다는 열거 타입의 인스턴스 멤버에 접근할 수 없다.
    • 열거 타입 생성자에 넘겨지는 인수들의 타입도 컴파일타임에 추론된다.
    • 인스턴스는 런타임에 만들어지기 때문에 인스턴스 멤버에 접근할 수 없다.
      PLUS("+", (x, y) -> {
      // 컴파일 오류가 발생한다.
      System.out.println(symbol);
      return x + y;
      }),

      람다로 대체할 수 없는 부분

  3. 람다는 함수형 인터페이스에서만 쓰인다.
    public class Main {
    public static void main(String[] args) {
        // 함수형 인터페이스가 아니기때문에 컴파일 오류가 발생한다.
        Object obj = () -> System.out.println("람다식");
    }
    }
  4. 추상 클래스의 인스턴스를 만들 때는 익명 클래스를 사용해야 한다.
    
    abstract class Animal {
    abstract void sound();
    }

public class Main { public static void main(String[] args) { // Animal 추상 클래스를 익명 클래스로 구현하여 인스턴스 생성 Animal dog = new Animal() { @Override void sound() { System.out.println("멍멍"); } }; // 람다식을 사용하면 컴파일 오류 발생 Animal cat = () -> System.out.println("야옹"); dog.sound(); } }

3. 람다의 this는 바깥 인스턴스를 가리킨다.
```java
public class Main {
    private String message = "바깥 클래스의 메시지";

    public void doSomething() {
        String message = "안쪽 메시지";
        // 람다 표현식
        Runnable r = () -> System.out.println(this.message);
        r.run();
    }

    public static void main(String[] args) {
        // 바깥 클래스의 메시지가 출력된다.
        new Main().doSomething();
    }
}
public class Main {
    private String message = "바깥 메시지";
    public void doSomething() {
        // 익명 클래스 선언 및 인스턴스화
        Runnable r = new Runnable() {
            private String message = "익명 클래스의 메시지";

            @Override
            public void run() {
                System.out.println(this.message); // 익명 클래스 내부의 'this'
            }
        };
        r.run();
    }

    public static void main(String[] args) {
        new Main().doSomething(); // 익명 클래스의 메시지
    }
}

🍑 결론

람다를 쓸수있는 상황이라면 람다를 쓰도록하자

Referenced by

-