Java 8에서 메소드 참조를 사용하여 스트림을 필터링 할 수 있습니다. 예를 들면 다음과 같습니다.
Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();
기존 참조의 부정 인 메소드 참조를 작성하는 방법이 있습니까?
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
not
아래와 같은 방법을 만들 수는 있지만 JDK가 비슷한 것을 제공하는지 궁금합니다.
static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
답변
Predicate.not( … )
따라서 메소드 참조를 부정 할 수 있습니다.
Stream<String> s = ...;
long nonEmptyStrings = s.filter(Predicate.not(String::isEmpty)).count();
답변
메소드 참조를 인라인으로 사용할 수 있도록 다음을 정적 가져 오기로 계획하고 있습니다.
public static <T> Predicate<T> not(Predicate<T> t) {
return t.negate();
}
예 :
Stream<String> s = ...;
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
업데이트 : Java-11부터 JDK는 유사한 솔루션을 기본제공합니다.
답변
현재 메소드 참조와 반대 인 메소드 참조를 작성하는 방법이 있습니다. 아래의 @vlasec의 답변을 참조하여 메소드 참조를 a로 명시 적으로 캐스팅 Predicate
한 다음 negate
함수를 사용하여 변환 하는 방법을 보여줍니다 . 그렇게하는 몇 가지 다른 방법 중 하나입니다.
이것의 반대 :
Stream<String> s = ...;
int emptyStrings = s.filter(String::isEmpty).count();
이것입니다 :
Stream<String> s = ...;
int notEmptyStrings = s.filter(((Predicate<String>) String::isEmpty).negate()).count()
아니면 이거:
Stream<String> s = ...;
int notEmptyStrings = s.filter( it -> !it.isEmpty() ).count();
개인적으로, 나는 it -> !it.isEmpty()
장황한 명시 적 캐스트보다 읽는 것이 더 명확하고 부정 하기 때문에 나중의 기술을 선호합니다 .
술어를 만들어 재사용 할 수도 있습니다.
Predicate<String> notEmpty = (String it) -> !it.isEmpty();
Stream<String> s = ...;
int notEmptyStrings = s.filter(notEmpty).count();
또는 컬렉션이나 배열이있는 경우 간단하고 오버 헤드가 적고 * 더 빠를 수있는 for 루프를 사용하십시오.
int notEmpty = 0;
for(String s : list) if(!s.isEmpty()) notEmpty++;
* 빠른 것이 무엇인지 알고 싶다면 JMH http://openjdk.java.net/projects/code-tools/jmh 를 사용 하고 모든 JVM 최적화를 피하지 않는 한 핸드 벤치 마크 코드를 피하십시오 ( Java 8 : Streams의 성능 참조) . vs 컬렉션
** for-loop 기술이 더 빠르다는 제안에 착각했습니다. 스트림 작성을 제거하고 다른 메소드 호출 (조건 자에 대해 음수 함수)을 사용하지 않고 임시 누적 기 목록 / 카운터를 제거합니다. 따라서 마지막 구성으로 저장되는 몇 가지 사항은 더 빠를 수 있습니다.
그래도 더 빠르지는 않더라도 더 간단하고 훌륭하다고 생각합니다. 직업이 망치와 못을 요구하는 경우 전기 톱과 접착제를 가져 오지 마십시오! 나는 당신 중 일부가 그 문제를 안다는 것을 알고 있습니다.
희망 목록 : Stream
Java 사용자가 익숙해지면서 Java 기능이 조금 발전하고 싶습니다 . 예를 들어 Stream의 ‘count’메서드는 Predicate
다음과 같이 직접 수행 할 수 있도록 허용 할 수 있습니다.
Stream<String> s = ...;
int notEmptyStrings = s.count(it -> !it.isEmpty());
or
List<String> list = ...;
int notEmptyStrings = lists.count(it -> !it.isEmpty());
답변
Predicate
방법을 가지고 and
, or
그리고 negate
.
그러나 String::isEmpty
는 아닙니다. Predicate
단지 String -> Boolean
람다이며 여전히 예를 들어 무엇이든 될 수 있습니다 Function<String, Boolean>
. 형식 유추 가 먼저 발생해야합니다. 이 filter
메소드는 타입을 암시 적으로 유추합니다 . 그러나 인수로 전달하기 전에 부정하면 더 이상 발생하지 않습니다. @axtavt가 언급했듯이 명시 적 추론은 추악한 방법으로 사용될 수 있습니다.
s.filter(((Predicate<String>) String::isEmpty).negate()).count()
다른 답변에는 다른 방법이 있습니다. 정적 not
방법과 람다는 가장 좋은 아이디어 일 것입니다. 이것으로 tl; dr 섹션을 마 칩니다 .
그러나 람다 형식 유추에 대해 더 깊이 이해하고 싶다면 예제를 사용하여 조금 더 깊이 설명하고 싶습니다. 이것들을보고 무슨 일이 일어나는지 알아 내십시오.
Object obj1 = String::isEmpty;
Predicate<String> p1 = s -> s.isEmpty();
Function<String, Boolean> f1 = String::isEmpty;
Object obj2 = p1;
Function<String, Boolean> f2 = (Function<String, Boolean>) obj2;
Function<String, Boolean> f3 = p1::test;
Predicate<Integer> p2 = s -> s.isEmpty();
Predicate<Integer> p3 = String::isEmpty;
- obj1이 컴파일되지 않습니다-람다는 기능적 인터페이스를 유추해야합니다 (= 하나의 추상 메소드 사용)
- p1과 f1은 각각 다른 유형을 유추하여 잘 작동합니다.
- obj2보다 A는 캐스트
Predicate
에Object
바보 만 유효 – - F2는 런타임에 실패하지 않습니다 – 당신이 캐스팅 할 수
Predicate
로Function
,이 추론에 대해 더 이상이다 - f3 작동-
test
람다로 정의 된 술어의 메소드 를 호출 - p2는 컴파일되지 않습니다- 메소드
Integer
가 없습니다isEmpty
- p3도 컴파일되지 않습니다- 인수가있는
String::isEmpty
정적 메소드 가 없습니다Integer
이것이 유형 유추 작동 방식에 대한 통찰력을 얻는 데 도움이되기를 바랍니다.
답변
다른 사람의 답변과 개인적인 경험을 바탕으로 :
Predicate<String> blank = String::isEmpty;
content.stream()
.filter(blank.negate())
답변
또 다른 옵션은 모호하지 않은 컨텍스트에서 람다 캐스팅을 한 클래스로 활용하는 것입니다.
public static class Lambdas {
public static <T> Predicate<T> as(Predicate<T> predicate){
return predicate;
}
public static <T> Consumer<T> as(Consumer<T> consumer){
return consumer;
}
public static <T> Supplier<T> as(Supplier<T> supplier){
return supplier;
}
public static <T, R> Function<T, R> as(Function<T, R> function){
return function;
}
}
… 그리고 유틸리티 클래스를 정적으로 가져옵니다 :
stream.filter(as(String::isEmpty).negate())