В 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(Predicate)
метода. Но эта проблема все еще открыта, поэтому мы увидим это в ближайшее время в Java 12 (если вообще когда-либо).Ответы:
Predicate.not( … )
Java-11предлагает новый метод Predicate # not
Таким образом, вы можете отменить ссылку на метод:
источник
Я планирую статический импорт следующего, чтобы позволить использование ссылки на метод inline:
например
Обновление : начиная с Java-11, JDK также предлагает аналогичное встроенное решение .
источник
Существует способ составить ссылку на метод, противоположную текущей ссылке на метод. См. Ответ @ vlasec ниже, который показывает, как явным образом привести ссылку на метод к a,
Predicate
а затем преобразовать ее с помощьюnegate
функции. Это один из нескольких других не слишком хлопотных способов сделать это.Противоположность этому:
это:
или это:
Лично я предпочитаю более позднюю технику, потому что нахожу более понятным,
it -> !it.isEmpty()
чем длинное подробное явное приведение, а затем отрицание.Можно также сделать предикат и использовать его повторно:
Или, если есть коллекция или массив, просто используйте цикл for, который прост, имеет меньше накладных расходов, а * может быть ** быстрее:
* Если вы хотите знать, что быстрее, то используйте JMH http://openjdk.java.net/projects/code-tools/jmh и избегайте ручного кода тестов, если он не избегает всех оптимизаций JVM - см. Java 8: производительность потоков против коллекций
** Я получаю злость за предположение, что техника цикла for работает быстрее. Это исключает создание потока, исключает использование другого вызова метода (отрицательная функция для предиката) и устраняет временный список / счетчик аккумулятора. Итак, несколько вещей, которые сохраняются последней конструкцией, могут сделать ее быстрее.
Я думаю, что это проще и приятнее, хотя и не быстрее. Если работа требует молотка и гвоздя, не вводите бензопилу и клей! Я знаю, что некоторые из вас не согласны с этим.
список желаний: я хотел бы видеть, что
Stream
функции Java развиваются немного теперь, когда пользователи Java более знакомы с ними. Например, метод 'count' в Stream может принять a,Predicate
чтобы это можно было сделать прямо так:источник
Predicate.negate(String::isEmpty);
без громоздкого кастинга.Predicate
есть методыand
,or
иnegate
.Тем не менее,
String::isEmpty
не являетсяPredicate
, это простоString -> Boolean
лямбда и она все еще может стать что угодно, напримерFunction<String, Boolean>
. Вывод типа - это то, что должно произойти в первую очередь. Вfilter
метод выводит тип неявно . Но если вы отрицаете это, прежде чем передать его в качестве аргумента, это больше не происходит. Как упомянуто @axtavt, явный вывод можно использовать как уродливый способ:В других ответах рекомендуются другие способы, при этом статический
not
метод и лямбда, скорее всего, являются лучшими идеями. На этом заканчивается раздел tl; dr .Однако, если вы хотите получить более глубокое понимание вывода типа лямбда-выражений, я хотел бы объяснить его более подробно, используя примеры. Посмотрите на них и попытайтесь выяснить, что происходит:
Predicate
наObject
- глупо , но действуетPredicate
кFunction
, это больше не выводtest
который определяется его лямбдаInteger
не имеетisEmpty
методаString::isEmpty
статического метода сInteger
аргументомЯ надеюсь, что это поможет лучше понять, как работает вывод типа.
источник
Опираясь на ответы других и личный опыт:
источник
::
ссылку, как хотелось бы (String::isEmpty.negate()
), но если вы присваиваете переменную первым (или приводите кPredicate<String>
первому), это работает. Я думаю, что лямбда-ж /!
будет наиболее читаемой в большинстве случаев, но полезно знать, что можно, а что нельзя компилировать.Другой вариант заключается в использовании лямбда-приведения в однозначных контекстах в одном классе:
... а затем статический импорт служебного класса:
источник
Не должно
Predicate#negate
быть то, что вы ищете?источник
Predicate
первый.String::isEmpty()
чтобыPredicate<String>
раньше - это очень некрасиво.Predicate<String> p = (Predicate<String>) String::isEmpty;
иp.negate()
.s -> !s.isEmpty()
в этом случае!В этом случае вы можете использовать
org.apache.commons.lang3.StringUtils
и сделатьисточник
String::isEmpty
в качестве примера. Это все еще важная информация, если у вас есть этот вариант использования, но если он отвечает только на вариант использования String, то он не должен быть принят.Я написал полный служебный класс (вдохновленный предложением Аскара), который может взять лямбда-выражение Java 8 и превратить их (если применимо) в любой типизированный стандартный лямбда-код Java 8, определенный в пакете
java.util.function
. Вы можете, например, сделать:asPredicate(String::isEmpty).negate()
asBiPredicate(String::equals).negate()
Поскольку было бы много неоднозначностей, если бы все статические методы были бы названы просто
as()
, я решил вызвать метод «как», а затем возвращаемый тип. Это дает нам полный контроль над лямбда-интерпретацией. Ниже приведена первая часть (несколько большого) служебного класса, раскрывающая используемый шаблон.Взгляните на полный класс здесь (в гист).
источник
Вы можете использовать Предикаты из Коллекций Eclipse
Если вы не можете изменить строки из
List
:Если вам нужно только отрицание,
String.isEmpty()
вы также можете использоватьStringPredicates.notEmpty()
.Примечание: я участвую в коллекциях Eclipse.
источник
Вы можете сделать это так долго
emptyStrings = s.filter(s->!s.isEmpty()).count();
источник
Если вы используете Spring Boot (2.0.0+), вы можете использовать:
Который делает:
return (str != null && !str.isEmpty());
Таким образом, он будет иметь необходимый эффект отрицания для
isEmpty
источник