我对java 8中Stream#findAny()
API的Stream#findFirst()
和Stream
感到困惑。
我的理解是两者都会从流中返回第一个匹配的元素,例如,当与过滤器一起使用时?
那么,为什么两种方法可以完成相同的任务呢?我错过了什么吗?
答案 0 :(得分:65)
我的理解是两者都将返回第一个匹配的元素 例如,当与过滤器一起使用时,来自流?
那不是真的。根据javadoc,Stream#findAny()
:
返回描述流的某些元素的
Optional<T>
,或者为空 如果流为空,则Optional<T>
。 此操作的行为明确是不确定的; 可以自由选择流中的任何元素。这是为了在并行操作中实现最大性能;
而Stream.findFirst()
将返回Optional<T>
,描述严格流的第一个元素。 Stream
课程没有.findOne()
方法,因此我认为您的意思是.findFirst()
。
答案 1 :(得分:34)
不,两者都不会返回Stream的第一个元素。
来自Stream.findAny()
(强调我的):
返回描述流的某个元素的
Optional
,如果流为空则返回空Optional
。这是一种短路终端操作。
此操作的行为明确是不确定的; 可以自由选择流中的任何元素。这是为了在并行操作中实现最大性能;成本是同一源上的多次调用可能不会返回相同的结果。 (如果需要稳定的结果,请改用
findFirst()
。)
所以更简单地说,它可能会也可能不会选择Stream的第一个元素。
使用当前的Oracle特定实现,我相信它将返回非并行管道中的第一个元素。但是,在并行管道中,它不会总是(例如System.out.println(IntStream.range(0, 100).parallel().findAny());
执行,当我运行它时返回OptionalInt[50]
)。无论如何,你必须不依赖它。
答案 2 :(得分:4)
findFirst返回流的第一个元素,但是findAny可以自由选择流中的任何元素。
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
答案 3 :(得分:1)
在并行模式下,findAny
不能保证顺序,但是findFirst
可以保证顺序。
我写了一些代码片段来显示差异,visit it
答案 4 :(得分:1)
我只是说,在使用时要当心class UserMiddleware(object):
def process_request(self, request):
if not request.get_full_path().endswith('/settings/force/') \
and request.user and not request.user.is_anonymous() \
and request.institute.force_student_data and not request.user.is_data_collected(request.institute):
return redirect(reverse('settings:force_update'))
return None
和findFirst()
。
从Javadoc(here和here)开始,这两种方法都从流中返回任意元素-除非流具有遇到顺序,在这种情况下,{ {1}}返回第一个元素,而findAny()
将返回任何元素。
假设我们具有由ISBN和BOOK名称组成的自定义findFirst()
。
对于这种情况,请看以下示例:
findAny()
list
输出:public class Solution {
private Integer ISBN;
private String BookName;
public Solution(int i, String string) {
ISBN =i;
BookName = string;
}
//getters and setters
}
在某些情况下,书名相同但ISBN号不同,在这种情况下,对书的分类和查找可能与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());
}
非常相似,并且会给出错误的结果。考虑这样一种情况,其中有5本书被命名为“ Java参考”,但是具有不同的ISBN号,按名称命名的Optional[Java in Action]
本书将与findAny()
相同。
考虑以下情况:
findFirst()
在这里,即使按 BookByName排序,findFirst()和findAny()也会给出相同的结果。
答案 5 :(得分:1)
[1]我开发了一个小代码来测试流的 findAny 和 findFirst。我已经创建了 1000 万个虚拟数据并过滤了这些数据,并通过在两者上使用并行流和顺序流来应用 findAny 和 findFirst。
从小实验中,我发现 findAny 和 findFirst 给出了相同的结果,并且它提供了顺序流中的第一个结果。但我发现 findAny 不能保证每次在 parallelStream 中产生相同的结果,而 findFirst 保证它总是产生相同的结果,无论流是并行的还是顺序的。
public class TestFilter {
static class Employee {
String name;
double salary;
long id;
public Employee(String name, long id, double salary) {
this.name = name;
this.id = id;
this.salary = salary;
}
String genNextName() {
return "Emp-" + (this.id + 1);
}
double genNextSalary() {
return new Random().nextDouble() * 1000000;
}
long genNextId() {
return this.id + 1;
}
@Override
public String toString() {
return this.id + " " + this.name + " " + this.salary + "\n";
}
}
public static void main(String[] args) {
List<Employee> employees = createDummyEmployee(10000000l);
List<Employee> emps = null;
long time = 0;
for (int i = 0; i < 50; i++) {
Optional<Employee> e1 = employees.stream()
.filter(e -> e.name.endsWith("999"))
.filter(e -> e.salary > 10000)
.filter(e -> e.id % 2 == 1)
.findAny();
Optional<Employee> e2 = employees.stream()
.filter(e -> e.name.endsWith("999"))
.filter(e -> e.salary > 10000)
.filter(e -> e.id % 2 == 1)
.findFirst();
Optional<Employee> pe1 = employees.parallelStream()
.filter(e -> e.name.endsWith("999"))
.filter(e -> e.salary > 10000).filter(e -> e.id % 2 == 1)
.findAny();
Optional<Employee> pe2 = employees.parallelStream()
.filter(e -> e.name.endsWith("999"))
.filter(e -> e.salary > 10000)
.filter(e -> e.id % 2 == 1)
.findFirst();
System.out.print("FindAny without parallel : " + (e1.isPresent() ? e1.get().id +"": "null"));
System.out.print(" | FindFirst without parallel : " + (e2.isPresent() ? e2.get().id +"": "null"));
System.out.print(" | FindAny by Parallel : " + (pe1.isPresent() ? pe1.get().id +"": "null"));
System.out.print(" | FindFirst by Parallel : " + (pe2.isPresent() ? pe2.get().id +"": "null"));
System.out.println();
}
}
public static List<Employee> createDummyEmployee(long n) {
Employee e1 = new Employee("Emp-1", 1l, 1.0);
return Stream.iterate(e1, (Employee e) -> new Employee(e.genNextName(), e.genNextId(), e.genNextSalary()))
.limit(n).collect(Collectors.toList());
}
}
【实验结果】 [1]:https://i.stack.imgur.com/HOZjA.png
答案 6 :(得分:0)
在流findFirst和findAny中返回第一个元素,不执行其余元素,但是在parallelStream中,说顺序是不可行的,而parallelStream执行集合的其余部分。
时间1:25:00
答案 7 :(得分:-1)
当Stream
无序时,findFirst()
和findAny()
相同。但是订购Stream
时,findAny()
会更好。