W Javie 8 możesz użyć odwołania do metody do filtrowania strumienia, na przykład:
Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();
Czy istnieje sposób na utworzenie odwołania do metody, które jest negacją istniejącego, tj. Coś takiego:
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
Mogłem stworzyć not
metodę jak poniżej, ale zastanawiałem się, czy JDK oferuje coś podobnego.
static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
Predicate.not(Predicate)
metody statycznej . Ale ten problem jest nadal otwarty, więc zobaczymy to najwcześniej w Javie 12 (jeśli w ogóle).Odpowiedzi:
Predicate.not( … )
java-11oferuje nową metodę Predicate # not
Możesz więc zanegować odwołanie do metody:
źródło
Planuję zaimportować statycznie następujące elementy, aby umożliwić użycie odwołania do metody w wierszu:
na przykład
Aktualizacja : Począwszy od Java-11, JDK oferuje równieżwbudowane podobne rozwiązanie .
źródło
Istnieje sposób na skomponowanie odwołania do metody, które jest przeciwieństwem bieżącego odwołania do metody. Zobacz odpowiedź @ vlasec poniżej, która pokazuje, jak jawnie rzutować odwołanie do metody na a,
Predicate
a następnie przekonwertować ją za pomocąnegate
funkcji. To jeden ze sposobów na kilka innych niezbyt kłopotliwych sposobów.Przeciwieństwo tego:
czy to jest:
albo to:
Osobiście wolę późniejszą technikę, ponieważ uważam, że czytanie
it -> !it.isEmpty()
jest łatwiejsze niż długa pełna wypowiedź, a następnie negacja.Można również zrobić predykat i użyć go ponownie:
Lub, jeśli masz kolekcję lub tablicę, po prostu użyj pętli for, która jest prosta, ma mniejszy narzut i * może być ** szybsza:
* Jeśli chcesz wiedzieć, co jest szybsze, użyj JMH http://openjdk.java.net/projects/code-tools/jmh i unikaj ręcznego kodu testowego, chyba że unika się wszystkich optymalizacji JVM - patrz Java 8: wydajność strumieni vs Kolekcje
** Dostaję błąd, sugerując, że technika for-loop jest szybsza. Eliminuje tworzenie strumienia, eliminuje użycie innego wywołania metody (funkcja ujemna dla predykatu) i eliminuje tymczasową listę / licznik akumulatorów. Kilka rzeczy, które są zapisywane przez ostatni konstrukt, które mogą go przyspieszyć.
Myślę, że jest to jednak prostsze i przyjemniejsze, nawet jeśli nie szybsze. Jeśli praca wymaga młota i gwoździa, nie przynoś piły łańcuchowej i kleju! Wiem, że niektórzy z was mają z tym problem.
lista życzeń: Chciałbym, aby
Stream
funkcje Java ewoluowały nieco teraz, gdy użytkownicy Java są z nimi bardziej zaznajomieni. Na przykład metoda „count” w Streamie może zaakceptować a,Predicate
dzięki czemu można to zrobić bezpośrednio w następujący sposób:źródło
Predicate.negate(String::isEmpty);
bez uciążliwego rzucania.Predicate
posiada metodyand
,or
inegate
.Jednak
String::isEmpty
nie jestPredicate
, to po prostuString -> Boolean
lambda i wciąż może stać się czymkolwiek, npFunction<String, Boolean>
. Wnioskowanie typu jest tym, co musi się zdarzyć najpierw. Wfilter
wyprowadza metoda wpisać niejawnie . Ale jeśli zaprzeczysz temu, zanim przekażesz go jako argument, to już się nie stanie. Jak wspomniano @axtavt, jawnego wnioskowania można użyć jako brzydkiego sposobu:Istnieją inne sposoby wskazane w innych odpowiedziach, przy czym
not
metoda statyczna i lambda są prawdopodobnie najlepszymi pomysłami. To kończy sekcję tl; dr .Jeśli jednak chcesz głębiej zrozumieć wnioskowanie o typie lambda, chciałbym wyjaśnić to bardziej szczegółowo, używając przykładów. Spójrz na nie i spróbuj dowiedzieć się, co się stanie:
Predicate
naObject
głupie, ale poprawnePredicate
sięFunction
, to już nie chodzi o wnioskowanietest
zdefiniowaną przez jej lambdaInteger
nie maisEmpty
metodyString::isEmpty
metody statycznej zInteger
argumentemMam nadzieję, że pomoże to uzyskać lepszy wgląd w działanie wnioskowania typu.
źródło
Opierając się na odpowiedziach innych i osobistym doświadczeniu:
źródło
::
odwołania, jakString::isEmpty.negate()
byś chciał ( ), ale jeśli najpierw przypiszesz zmienną (lub przerzucisz naPredicate<String>
pierwszą), to zadziała. Myślę, że lambda w /!
będzie najbardziej czytelna w większości przypadków, ale warto wiedzieć, co można, a czego nie można skompilować.Inną opcją jest wykorzystanie rzutowania lambda w niejednoznacznych kontekstach do jednej klasy:
... a następnie zaimportuj statycznie klasę narzędzia:
źródło
Czy nie powinno
Predicate#negate
być to, czego szukasz?źródło
Predicate
pierwszy.String::isEmpty()
doPredicate<String>
wcześniej - to jest bardzo brzydka.Predicate<String> p = (Predicate<String>) String::isEmpty;
ip.negate()
.s -> !s.isEmpty()
w takim przypadku!W takim przypadku
org.apache.commons.lang3.StringUtils
możesz użyć i zrobićźródło
String::isEmpty
stanowi przykład. Jest to nadal ważna informacja, jeśli masz ten przypadek użycia, ale jeśli odpowiada on tylko na przypadek użycia Ciąg, to nie powinien zostać zaakceptowany.Napisałem kompletną klasę narzędziową (zainspirowaną propozycją Askara), która może pobrać wyrażenie lambda Java 8 i zamienić je (jeśli dotyczy) w dowolny typowy standardowy lambda Java 8 zdefiniowany w pakiecie
java.util.function
. Możesz na przykład:asPredicate(String::isEmpty).negate()
asBiPredicate(String::equals).negate()
Ponieważ byłoby wiele dwuznaczności, gdyby wszystkie statyczne metody zostały nazwane tylko
as()
, zdecydowałem się wywołać metodę „as”, a następnie zwracany typ. To daje nam pełną kontrolę nad interpretacją lambda. Poniżej znajduje się pierwsza część (nieco dużej) klasy użyteczności ujawniająca zastosowany wzorzec.Spójrz na całą klasę tutaj (w skrócie).
źródło
Możesz użyć predykatów z kolekcji Eclipse
Jeśli nie możesz zmienić ciągów z
List
:Jeśli potrzebujesz tylko negacji
String.isEmpty()
, możesz również użyćStringPredicates.notEmpty()
.Uwaga: Jestem współtwórcą kolekcji Eclipse.
źródło
Możesz to zrobić tak długo
emptyStrings = s.filter(s->!s.isEmpty()).count();
źródło
Jeśli używasz Spring Boot (2.0.0+), możesz użyć:
Co robi:
return (str != null && !str.isEmpty());
Będzie to miało wymagany efekt negacji
isEmpty
źródło