티스토리 뷰

목차

1. 메소드 참조

2. 인스턴스 메소드 참조 1

3. 인스턴스 메소드 참조 2

4. 생성자 참조

5. static 메소드 참조

 

 

1. 메소드 참조

메소드 참조를 통해 기본적으로 람다식보다 조금 더 코드를 단순하게 할 수 있다.

일부 람다식을 메소드 참조로 대신하게 할 수 있다.

 

람다식으로 작성했을 때 넘어오는 인자를 그대로 메소드 참조에 사용하겠다는 약속을 기반으로

람다식 대신 메소드 참조를 사용할 수 있다.

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 3, 5, 7, 9);
    list = new ArrayList<>(list);

    // 익명 클래스
    Consumer<List<Integer>> consumer1 = new Consumer<List<Integer>>() {
        @Override
        public void accept(List<Integer> n) {
            Collections.reverse(n);
        }
    };

    // 람다
    Consumer<List<Integer>> consumer2 = n -> Collections.reverse(n);

    // 메소드 참조
    // accept() 의 인자를 Collections.reverse() 의 인자로 사용하도록 약속
    Consumer<List<Integer>> consumer3 = Collections::reverse;

//    consumer1.accept(list);
//    consumer2.accept(list);
    consumer3.accept(list);

    list.forEach(System.out::println);
}

 

2. 인스턴스 메소드 참조 1

1) effectively final

지역변수를 통한 메소드 호출이 외부에서 실행되기 때문에

지역변수가 변경되면 외부에서 호출하는 메소드의 결과가 달라질 수 있다.

따라서, 해당 지역변수를 사실상 상수(effectively final)일 때만 람다식, 메소드 참조가 가능하도록 제한을 둔다.

다른 값으로 변경되면 컴파일 에러 발생.

class JustSort {
    public void sort(List<?> lst) {
        Collections.reverse(lst);
    }
}

class ArrangeList3 {
    public static void main(String[] args) {
        List<Integer> ls = Arrays.asList(1, 3, 5, 7, 9);
        ls = new ArrayList<>(ls);
        JustSort js = new JustSort(); // js는 effectively final

        Consumer<List<Integer>> c = e -> js.sort(e);
//        Consumer<List<Integer>> c = js::sort;

        c.accept(ls);
        System.out.println(ls);
        
//        js = new JustSort(); // 람다, 메소드 참조 작성 불가능
    }
}

 

2) forEach 메소드

Iterable 인터페이스의 default 메소드

public interface Iterable<T> {
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
}

forEach 메소드의 this는 default 메소드이기 때문에

결국 Iterable 인터페이스 하위 인터페이스, 클래스의 인스턴스 (아래 코드에서 List<String> ls)

Collection 인터페이스를 구현하는 클래스에서 사용이 가능하다.

public static void main(String[] args) {
    List<String> ls = Arrays.asList("Box", "Robot");
    ls.forEach(s -> System.out.println(s));
    ls.forEach(System.out::println);
}

 

forEach() 메소드는 Consumer 타입의 인자를 받아 accept() 메소드를 호출한다.

accept() 메소드가 받을 인자를 람다식으로 "s ->" 와 같이 작성하지만 메소드 참조로 표현하면

람다식의 인자를 Consumer의  void accept(T t) 메소드의 인자로 그대로 사용하는 형태가 된다.

 

 

3. 인스턴스 메소드 참조 2

1) 인스턴스 없이 인스턴스 메소드 참조

(b1, b2) -> b1.larger(b2) 처럼  두 개의 인자를 받아 b1의 메소드를 호출하면서 b2 를 인자로 넘기는 형태

(IBox 의 lager 와 같은 형태)를 다음과 같이 메소드 참조 형태로 표현할 수 있다.

 

ToIntBiFunction<IBox, IBox> bf = (b1, b2) -> b1.larger(b2);
ToIntBiFunction<IBox, IBox> bf = IBox::larger;

public interface ToIntBiFunction<T, U> {
    int applyAsInt(T t, U u);
}
class IBox {
    private int n; 

    public IBox(int i) { n = i; }

    public int larger(IBox b) {
        if(n > b.n)
            return n;
        else
            return b.n;
    }
}

class NoObjectMethodRef2 {
    public static void main(String[] args) {
        IBox ib1 = new IBox(5);
        IBox ib2 = new IBox(7);

//        ToIntBiFunction<IBox, IBox> bf = (b1, b2) -> b1.larger(b2);
        ToIntBiFunction<IBox, IBox> bf = IBox::larger;
        int bigNum = bf.applyAsInt(ib1, ib2);
        System.out.println(bigNum);}
}

 

 

4. 생성자 참조

1) 생성자 참조(default)

Greeting 타입을 리턴하는 default 생성자

Supplier<Greeting> greetingSupplier = Greeting::new;
System.out.println(greetingSupplier.get().hello("mandy"));

 

2) 생성자 참조(parameter)

String 타입을 인자로 받아 Greeting 타입을 리턴하는 생성자

Function<String, Greeting> greetingFunction = Greeting::new;
Greeting mandy = greetingFunction.apply("mandy");
System.out.println(mandy.getName());

 

5. static 메소드 참조

UnaryOperator<T> extends Function<T, T> : 입력값과 리턴값이 같은 Function인 경우 사용

Greeting 의 hi() String 타입을 인자로 받아 String 타입을 리턴하는 static 메소드

UnaryOperator<String> hi = Greeting::hi;
System.out.println(hi.apply("mandy"));

 

 

 

 

 

출처

https://cafe.naver.com/cstudyjava 윤성우의 열혈 java

728x90

'Java > Java 8' 카테고리의 다른 글

[java 8] 3-1. Stream (생성, 중간 연산, 최종 연산)  (0) 2021.12.29
[java 8] 4. Optional  (0) 2021.12.18
[java 8] 3. Stream  (0) 2021.12.17
[java 8] 2. 인터페이스의 변화  (0) 2021.12.02
[java 8] 1. 함수형 인터페이스와 람다  (0) 2021.11.08