Встроенный предикат Java 8, который всегда возвращает истину?

130

У Google Guava есть предикат, который всегда возвращаетсяtrue . Есть ли в Java 8 что-то подобное Predicate? Я знаю, что могу использовать (foo)->{return true;}, но мне нужно что-то готовое, аналогичное Collections.emptySet().

Гаррет Уилсон
источник

Ответы:

162

В Java 8 нет встроенных предикатов всегда-истинно и всегда-ложно. Самый краткий способ их записи -

x -> true

и

x -> false

Сравните это с

Predicates.alwaysTrue() // Guava

и, наконец, к анонимному внутреннему классу:

new Predicate<Object>() {
    public boolean test(Object x) {
        return true;
    }
}

Вероятно, причина того, что Guava имеет эти встроенные предикаты, заключается в том, что существует огромное синтаксическое преимущество вызова статического метода над анонимным внутренним классом. В Java 8 лямбда-синтаксис настолько лаконичен, что запись вызова статического метода является синтаксическим недостатком .

Однако это просто синтаксическое сравнение. Вероятно, есть небольшое преимущество в пространстве, если бы существовал единственный глобальный предикат Always-true по сравнению с x -> trueэкземплярами, распределенными по нескольким классам, каждый из которых создал бы свой собственный экземпляр предиката. Это то, что вас беспокоит? Экономия не казалась убедительной, возможно, поэтому ее и не добавили. Но это может быть пересмотрено для будущего выпуска.

ОБНОВЛЕНИЕ 2015-04-24

Мы рассмотрели возможность добавления множества статических именованных функций, таких как Predicate.alwaysTrue, Runnable.noopи т. Д., И решили не добавлять больше в будущих версиях Java SE.

Конечно, есть некоторая ценность в том, что имеет имя по сравнению с записанной лямбдой, но это значение довольно мало. Мы ожидаем , что люди научатся читать и писать , x -> trueи () -> { }и что их использование будет идиоматическое. Даже ценность Function.identity()over x -> xсомнительна.

Повторное использование существующей функции вместо оценки записанного лямбда дает небольшое преимущество в производительности, но мы ожидаем, что использование этих функций будет настолько малым, что такое преимущество будет незначительным и, конечно, не стоит раздувания API.

Хольгер также упомянул в комментариях возможность оптимизации составных функций, таких как Predicate.orи такие. Это также рассматривалось ( JDK-8067971 ), но было сочтено несколько хрупким и подверженным ошибкам, а также происходящим достаточно редко, поэтому не стоило усилий для реализации.

См. Также этот раздел часто задаваемых вопросов о лямбде.

Стюарт Маркс
источник
14
Две проблемы: первая - краткость. Если (foo)->{return true;}это лучшее, что я могу сделать, я хочу лучшего. Но вы подняли x->true, что намного лучше и смягчает первую проблему. Вторая проблема связана с объявлением логики и статики. Если я использую x->true, все еще присутствует логика, которую я могу случайно испортить (например x->!true). Но Predicate.alwaysTrue()здесь нет места для логической ошибки, так как есть только один или два похожих метода. Плюс я получаю автозавершение кода IDE бесплатно. x->trueпочти нормально, но я все же написал Predicate.alwaysTrue()метод по причинам выше.
Гаррет Уилсон,
10
@GarretWilson Но с Predicate.alwaysTrue()тобой тоже можно облажаться, если ты случайно написал Predicate.alwaysFalse().
Дэвид Конрад
5
@DavidConrad, конечно. Всегда есть способы сделать ошибки, и на самом деле я постоянно придумываю новые. ;) Я не хочу начинать здесь споры из-за чего-то тривиального, но я просто хочу сказать, что моя точка зрения состоит в том, что со ссылкой на статический метод у меня есть ограниченный словарь только с двумя вариантами: alwaysTrue()и alwaysFalse(). Что касается реальной лямбды, у меня есть много вариантов; По сути, я каждый раз реконструирую формулу. По сути, alwaysTrue()это семантическая метка того, что я хочу делать; x->trueфактически делает это каждый раз заново. Не огромное, но заслуживающее внимания.
Гаррет Уилсон
25
Одно большое преимущество канонической Predicate.alwaysTrue()и Predicate.alwaysFalse()экземпляров в том, что они могут быть признаны комбинируя методы , как Predicate.or, Predicate.andи Predicate.negate(). Это позволило бы предварительно инициализировать Predicateпеременные с помощью alwaysTrue()предикатов и добавлять их путем объединения andбез дополнительных затрат. Поскольку лямбда-выражения не имеют гарантии идентичности объекта, это может не сработать x->true. Между прочим, если у меня есть класс Xс staticметодом y(){return true;}, использование X::yдаже короче, x->trueно не очень рекомендуется…
Хольгер
10
x -> trueНедостаток идиомы состоит в том, что мне приходится использовать переменную без использования. Это создает ненужную нагрузку на мозг, а также вызывает предупреждение в моей IDE. Я пробовал использовать _ -> true, но это синтаксическая ошибка. В Java определенно отсутствует ключевое слово (читай: клавиатурная буква) для «неиспользуемого параметра». Надеюсь, что что-то подобное появится в Java 9 (или, по крайней мере, в Java - что угодно, прежде чем я умру ^^)
kap
4

Без гуавы

Boolean.TRUE::booleanValue
boriselec
источник
3
Это интересно. Не уверен, что он полностью передает дух просьбы, но за творчество начисляются баллы!
Гаррет Уилсон
21
Но это не так Predicate, поскольку не требует аргументов.
Флоран Гийом
1
Это не предикат, это ссылка на метод, но она лаконична и не требует упоминания неиспользуемого параметра. +1 Кстати, поскольку он избегает использования Guava, у которого есть серьезная проблема модульности, он заслуживает моего одобрения;)
gouessej
16
Ссылка на ваш метод может быть назначена поставщику <Boolean>, но не Predicate <T>
Дэниел К.