2016-10-10 1 views
4

최근에 저는 새로운 java8 기능에 대해 더 잘 이해하고 있습니다. : object -> targetRef.equals(object); : 나를 의심이 줄이었다 만든 무엇Predicate.isEqual이 구현 된 이유는 무엇입니까?

/** 
* Returns a predicate that tests if two arguments are equal according 
* to {@link Objects#equals(Object, Object)}. 
* 
* @param <T> the type of arguments to the predicate 
* @param targetRef the object reference with which to compare for equality, 
*    which may be {@code null} 
* @return a predicate that tests if two arguments are equal according 
* to {@link Objects#equals(Object, Object)} 
*/ 
static <T> Predicate<T> isEqual(Object targetRef) { 
    return (null == targetRef) 
      ? Objects::isNull 
      : object -> targetRef.equals(object); 
} 

: Stream.filter에 몇 가지 물건을하려고 할 때

나는 내가 isEqual 방법의 다음과 같은 구현을 발견하는 Predicate.java의 소스를 가로 질러왔다.

은 어쩌면 내가 다량이 지나친하고 있지만, 그 선이 같은 : targetRef::equals;되지 않은 이유를 나는 즉시 생각을 떨칠 수 없었다 :

static <T> Predicate<T> isEqual(Object targetRef) { 
    return (null == targetRef) 
      ? Objects::isNull 
      : targetRef::equals; 
} 

그렇지 않으면 나에게 람다의 불필요한 생성을 보인다.

내가 뭔가를 놓치지 않는다면 나에게도 마찬가지입니다. (그들은 똑같은가?) 현재 구현이 선택된 이유가 있습니까? 아니면이게 그냥 믿을 수 없을만큼 작아서 그냥 간과했거나 아무도 정말로 신경 쓰지 않았습니다.

사실상 보너스 질문이 발생합니다. 다른 편도를 사용하는 데 어떤 이점이 있습니까? 어떤 종류의 (아마도 아주 작은) 성과 보너스와 마찬가지로?

+2

방법 참조는 명시 적 람다와 동일한 연삭 기계에서 끝납니다. 두 가지 모두에 대해 동일한 구현 기술이 필요합니다. –

+0

@MarkoTopolnik 예, 메소드 참조를 전달하는 대신 lamba (메소드를 호출하는 것만으로)를 작성하여 불필요한 메소드 호출 (람다)을 체인에 추가하지 않습니까? (아마 스트림에 많은 아이템이 포함되어 있다면 많이 불려질 것입니다.) –

+3

아무에게도 대답 할 수 없을 것입니다 ... 코드를 작성한 사람을 기대하십시오. 확신. – Tunaki

답변

7

왜 이렇게 했습니까?

순수한 추측이지만 개발자가 작성했을 때 개발자는 그 당시에는 더 이상 안락 할 수있었습니다. 라이브러리는 컴파일러에서 버그를 수정하는 동안 작성되었습니다.

알 수있는 방법이 없으며 작성자가 기억하지 못할 수도 있습니다. 가 : 당신이 실제로 보너스 질문 결과

추측 (이 예에서와 같이) 메소드 참조 또는 폐쇄 구문, 객체의 같은 수의 대부분의 경우는 만들어 사용 여부


다른 편도를 사용하는 데 어떤 이점이 있습니까? 어떤 종류의 (아마도 아주 작은) 성과 보너스와 마찬가지로?

메소드 참조를 사용하면 메소드 호출이 적습니다. 레벨 수는 기본적으로 9로 제한되므로 인라이닝에 간접적 인 영향을 미칠 수 있습니다. 예를 들어

import java.util.function.Consumer; 

public class Main { 
    public static void main(String[] args) { 
     Consumer<String> lambda = s-> printStackTrace(s); 
     lambda.accept("Defined as a lambda"); 

     Consumer<String> methodRef = Main::printStackTrace; 
     methodRef.accept("Defined as a method reference"); 
    } 


    static void printStackTrace(String description) { 
     new Throwable(description).printStackTrace(); 
    } 
} 

인쇄

제 경우
java.lang.Throwable: Defined as a lambda 
    at Main.printStackTrace(Main.java:15) 
    at Main.lambda$main$0(Main.java:6) 
    at Main.main(Main.java:7) 

java.lang.Throwable: Defined as a method reference 
    at Main.printStackTrace(Main.java:15) 
    at Main.main(Main.java:10) 

컴파일러를 사용하거나 다른 상세하게 여기서 실제로 printStackTrace

를 호출하는 코드를 포함 Main.lambda$main$0라는 방법을 생성했다 차이점은 캡처 (값 저장) 또는 비 캡처 람다를 가질 수있는 경우입니다. 비 캡처 람다는 한 번만 생성됩니다.

당신이 System.setOut를 호출하는 경우 그것이 쓸 수있는의 PrintStream의 자신의 사본의이 같은 첫 번째 경우에

Consumer<String> print1 = System.out::println; // creates an object each time 
Consumer<String> print2 = s->System.out.println(s); // creates an object once. 

는,이 변화를 무시합니다.

+0

와우, 당신은 방금 그 모범을 보았습니다! 절대로 그렇게 생각하지 않았습니다. –

+1

왜 이런 방식으로 수행되었는지에 대한 초기 질문에 대해서는 "우리는 결코 알지 못할 것이며 아마 중요하지 않을 것"이라고 대답 할 것이라고 생각하십니까? –

+1

@OlleKelderman은 이제 lambda 세트를 상상해 봅니다.이 경우 두 번 추가하면 두 번째 세트에, 두 번째 경우에는 세트 1이됩니다. 하나를 제거하려고 시도하면 크기가 2가 될 수 있습니다. 0이다. –

관련 문제