No Java 8, você pode usar uma referência de método para filtrar um fluxo, por exemplo:
Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();
Existe uma maneira de criar uma referência de método que é a negação de uma existente, ou seja, algo como:
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
Eu poderia criar o not
método como abaixo, mas queria saber se o JDK oferecia algo semelhante.
static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
Predicate.not(Predicate)
método estático . Mas como esse problema ainda está aberto, veremos isso o mais cedo possível no Java 12 (se houver).Respostas:
Predicate.not( … )
java-11oferece um novo método Predicado # não
Portanto, você pode negar a referência do método:
fonte
Estou planejando importar estática o seguinte para permitir que a referência do método seja usada em linha:
por exemplo
Atualização : A partir do Java-11, o JDK também oferece uma solução semelhante .
fonte
Existe uma maneira de compor uma referência de método que é o oposto de uma referência de método atual. Veja a resposta da @ vlasec abaixo, que mostra como
Predicate
converter explicitamente a referência de método para a e depois convertê-la usando anegate
função Essa é uma maneira dentre algumas outras maneiras não muito problemáticas de fazê-lo.O oposto disso:
é isto:
ou isto:
Pessoalmente, prefiro a técnica posterior porque acho mais claro ler do
it -> !it.isEmpty()
que um elenco explícito longo e explícito e depois nego.Também se poderia fazer um predicado e reutilizá-lo:
Ou, se tiver uma coleção ou matriz, use um loop for que seja simples, tenha menos sobrecarga e * possa ser ** mais rápido:
* Se você quiser saber o que é mais rápido, use JMH http://openjdk.java.net/projects/code-tools/jmh e evite o código de referência manual, a menos que evite todas as otimizações da JVM - consulte Java 8: desempenho do Streams vs Colecções
** Estou recebendo críticas por sugerir que a técnica de loop for é mais rápida. Elimina a criação de um fluxo, elimina o uso de outra chamada de método (função negativa para predicado) e elimina uma lista / contador de acumuladores temporários. Portanto, algumas coisas que são salvas pela última construção que podem torná-la mais rápida.
Eu acho que é mais simples e agradável, mesmo que não seja mais rápido. Se o trabalho exigir um martelo e um prego, não traga uma serra elétrica e cola! Eu sei que alguns de vocês têm problemas com isso.
lista de desejos: Gostaria de ver as
Stream
funções Java evoluírem um pouco agora que os usuários Java estão mais familiarizados com elas. Por exemplo, o método 'count' no Stream pode aceitar umPredicate
para que isso possa ser feito diretamente assim:fonte
Predicate.negate(String::isEmpty);
sem o elenco pesado.Predicate
tem métodosand
,or
enegate
.No entanto,
String::isEmpty
não é umPredicate
, é apenas umString -> Boolean
lambda e ainda pode se tornar qualquer coisa, por exemploFunction<String, Boolean>
. Inferência de tipo é o que precisa acontecer primeiro. Ofilter
método deduz o tipo implicitamente . Mas se você negar antes de passar como argumento, isso não acontece mais. Como o @axtavt mencionou, a inferência explícita pode ser usada como uma maneira feia:Existem outras maneiras recomendadas em outras respostas, com
not
método estático e lambda provavelmente as melhores idéias. Isso conclui a seção tl; dr .No entanto, se você quiser uma compreensão mais profunda da inferência do tipo lambda, gostaria de explicar um pouco mais a fundo, usando exemplos. Olhe para eles e tente descobrir o que acontece:
Predicate
paraObject
- bobagem, mas válidaPredicate
paraFunction
, ele não é mais sobre inferênciatest
definido por sua lambdaInteger
não possuiisEmpty
métodoString::isEmpty
método estático comInteger
argumentoEspero que isso ajude a obter mais informações sobre como funciona a inferência de tipo.
fonte
Com base nas respostas de outros e na experiência pessoal:
fonte
::
referência funcional como se poderia desejar (String::isEmpty.negate()
), mas se você atribuir a uma variável primeiro (ou converter aPredicate<String>
primeira), isso funcionará. Acho que o lambda!
será mais legível na maioria dos casos, mas é útil saber o que pode e o que não pode ser compilado.Outra opção é utilizar a conversão lambda em contextos não ambíguos em uma classe:
... e, em seguida, estática, importe a classe do utilitário:
fonte
Não deve
Predicate#negate
ser o que você está procurando?fonte
Predicate
primeiro.String::isEmpty()
paraPredicate<String>
antes - é muito feio.Predicate<String> p = (Predicate<String>) String::isEmpty;
ep.negate()
.s -> !s.isEmpty()
nesse caso!Nesse caso, você poderia usar o
org.apache.commons.lang3.StringUtils
efonte
String::isEmpty
como exemplo. Ainda são informações relevantes se você tiver esse caso de uso, mas se ele responder apenas ao caso de uso String, ele não deverá ser aceito.Eu escrevi uma classe de utilitário completa (inspirada na proposta de Askar) que pode pegar a expressão lambda do Java 8 e transformá-la (se aplicável) em qualquer lambda padrão do Java 8 definido no pacote
java.util.function
. Você pode, por exemplo, fazer:asPredicate(String::isEmpty).negate()
asBiPredicate(String::equals).negate()
Como haveria inúmeras ambiguidades se todos os métodos estáticos fossem nomeados apenas
as()
, optei por chamar o método "como" seguido pelo tipo retornado. Isso nos dá controle total da interpretação lambda. Abaixo está a primeira parte da classe de utilidade (um tanto grande) que revela o padrão usado.Dê uma olhada na turma completa aqui (no gist).
fonte
Você pode usar Predicados das Coleções Eclipse
Se você não pode alterar as strings de
List
:Se você só precisa de uma negação,
String.isEmpty()
você também pode usarStringPredicates.notEmpty()
.Nota: Sou colaborador do Eclipse Collections.
fonte
Você pode fazer isso contanto
emptyStrings = s.filter(s->!s.isEmpty()).count();
fonte
Se você estiver usando o Spring Boot (2.0.0+), poderá usar:
O que faz:
return (str != null && !str.isEmpty());
Portanto, terá o efeito de negação necessário para
isEmpty
fonte