Diferença entre findAny () e findFirst () em Java 8

91

Estou um pouco confuso entre Stream#findAny()e Stream#findFirst()da StreamAPI em Java 8.

O que entendi é que ambos retornarão o primeiro elemento correspondente do fluxo, por exemplo, quando usado em conjunto com o filtro?

Então, por que dois métodos para a mesma tarefa? Estou esquecendo de algo?

Mandeep Rajpal
fonte

Respostas:

94

O que entendi é que ambos retornarão o primeiro elemento correspondente do fluxo, por exemplo, quando usado em conjunto com o filtro?

Isso não é verdade. De acordo com o javadoc, Stream#findAny():

Retorna um que Optional<T>descreve algum elemento do fluxo, ou um vazio Optional<T>se o fluxo está vazio. O comportamento dessa operação é explicitamente não determinístico; é grátis selecionar qualquer elemento no stream. Isso é para permitir desempenho máximo em operações paralelas;

while Stream.findFirst()retornará um Optional<T>descrevendo estritamente o primeiro elemento do fluxo. A Streamclasse não tem um .findOne()método, então suponho que você quis dizer .findFirst().

Konstantin Yovkov
fonte
Ainda não entendi, então o que você está dizendo é que mesmo depois de filteraplicado um, findAnyconsegue retornar algum elemento, inclusive que não corresponda ao filtro aplicado?
Koray Tugay
@KorayTugay - Não, após o filtro, quaisquer elementos restantes estão presentes, findAnypode retornar qualquer elemento daquele em (mais ou menos) aleatório, particularmente em operações de fluxo paralelo
KrishPrabakar
46

Não, ambos não retornarão o primeiro elemento do Stream.

De Stream.findAny()(ênfase minha):

Retorna um que Optionaldescreve algum elemento do fluxo, ou um vazio Optionalse o fluxo está vazio.

Esta é uma operação de terminal de curto-circuito.

O comportamento dessa operação é explicitamente não determinístico; é grátis selecionar qualquer elemento no stream . Isso é para permitir o desempenho máximo em operações paralelas; o custo é que várias invocações na mesma fonte podem não retornar o mesmo resultado. (Se desejar um resultado estável, use em seu findFirst()lugar.)

Então, para simplificar, ele pode ou não escolher o primeiro elemento do Fluxo.

Com a implementação atual específica do Oracle, acredito que ela retornará o primeiro elemento em um pipeline não paralelo. No entanto, em um pipeline paralelo, nem sempre, executando por exemplo

System.out.println(IntStream.range(0, 100).parallel().findAny());

ele retornou OptionalInt[50]quando eu o executei. De qualquer forma, você não deve confiar nisso.

Tunaki
fonte
17

findFirst retorna os primeiros elementos do fluxo, mas findAny é livre para selecionar qualquer elemento no fluxo.

List<String> lst1 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
List<String> lst2 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");

Optional<String> findFirst = lst1.parallelStream().filter(s -> s.startsWith("D")).findFirst();
Optional<String> fidnAny = lst2.parallelStream().filter(s -> s.startsWith("J")).findAny();

System.out.println(findFirst.get()); //Always print David
System.out.println(fidnAny.get()); //Print Jack/Jill/Julia :behavior of this operation is explicitly nondeterministic
Amir
fonte
2

no modo paralelo, o findAnynão garante a ordem, mas findFirstsim.

Eu escrevi um trecho de código para mostrar a diferença, visite-o

Jiahut
fonte
1

No stream findFirst e findAny retornam o primeiro elemento e não executam o resto, mas no parallelStream, não é passível dizer a ordem e o parallelStream executa o resto da coleção.

Referência

Hora 1:25:00

emon
fonte
1

Direi apenas que cuidado com findFirst()E findAny()ao usar.

A partir de seu Javadoc ( aqui e aqui ), os dois métodos retornam um elemento arbitrário do fluxo - a menos que o fluxo tenha uma ordem de encontro , caso em que findFirst()retorna o primeiro elemento enquanto findAny()retornará qualquer elemento.

Suponha que temos o listISBN e o nome do LIVRO personalizados. Para um cenário, veja este exemplo:

public class Solution {
   private Integer ISBN;
   private String BookName;

public Solution(int i, String string) {
    ISBN =i;
    BookName = string;
}
//getters and setters
}

public static void main(String[] args) {
        List<Solution> Library = Arrays.asList(new Solution(12,"Java in Action"),new Solution(13,"Java 8"),new Solution(15,"Java 8 Features"),new Solution(16,"Java in Action"));
 System.out.println(Library.stream()
        .map(p->p.getBookName())
        .sorted(Comparator.reverseOrder())
        .findFirst());
    }

Produto :Optional[Java in Action]

Pode haver situações em que o nome do livro é o mesmo, mas os números ISBN são diferentes; nesse caso, a classificação e a localização do livro podem ser muito semelhantes findAny()e darão resultados errados. Pense em um cenário onde 5 livros são chamados de "Referência Java", mas têm números ISBN diferentes e o findFirst()livro por nome resultará no mesmo que findAny().

Pense em um cenário onde:

 ISBN    Name Of book
+-----+------------------+
| 100 | Java-8 in Action |
+-----+------------------+
| 101 | Java-8 in Action |
+-----+------------------+
| 102 | Java-8 in Action |
+-----+------------------+
| 103 | Java-8 in Action |
+-----+------------------+
| 104 | Java-8 in Action |
+-----+------------------+

aqui findFirst () e findAny () fornecerão o mesmo resultado, mesmo se classificados em BookByName.

Artigo detalhado:

Vishwa Ratna
fonte
-1

Quando Streamestá desordenado findFirst()e findAny()são iguais. Mas quando Streamfor encomendado, findAny()será melhor.

logbasex
fonte
Isso está incorreto. Nenhum desses métodos é "melhor", porque seus comportamentos e casos de uso são completamente diferentes. Além disso, o que você quer dizer com Streamser "ordenado"? É sempre ordenado (as operações são executadas na Streammesma ordem sempre que não está paralelizado), mas talvez não seja classificado pelo usuário.
Jezor,