首先它的特点是

Stream自己不会存储元素;

Stream不会改变源对象。相反,它们会返回一个持有结果的新Stream。

Stream操作是延迟执行的。这意味者它们会等到需要结果的时候才执行。

大概分为两种 一种是 stream() 另一种是 parallelStream()

parallelStream()和stream()的区别就是支持并行执行,提高程序运行效率,也就是多线程操作。但是如果使用不当可能会发生线程安全的问题。

对比发现parallelStream执行效率要比传统的for循环和stream要快的多,

那么什么时候要用stream或者parallelStream呢?可以从以下三点入手考虑

  1. 是否需要并行?  
  2. 任务之间是否是独立的?是否会引起任何竞态条件?  
  3. 结果是否取决于任务的调用顺序?

parallelStream可能会改变之前的顺序 Stream具有平行处理能力,处理的过程会分而治之,也就是将一个大任务切分成多个小任务,这表示每个任务都是一个操作 

parallelStream在中间处理时都是并行的(这里不展开说明并行的实现),所以parallelStream中间处理的结果都是乱序的,但是在使用了Collect收集器后,parallelStream被收集的结果默认都是按照集合的原序列进行排序的。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
numbers.parallelStream().forEachOrdered(System.out::println);   //这个只是输出而已
List<Integer> collect = testList.parallelStream()
.map(m -> {
if (Objects.isNull(m)) {
return null;
}
return m + 1;
})

.collect(Collectors.toList());// 后缀用了这个顺序就对了

使用parallelStream的一些注意点

(1)parallelStream并行流一定要使用线程安全的对象,比如有这样的一个场景 

List list = new ArrayList<>();        IntStream.rangeClosed(1, 10000).parallel().forEach(i -> list.add(i));

执行就立即报错了:

java stream 多个sum 速度 java stream 多线程_User

ArrayList本身就是一个线程不安全的容器,在多线程的操作下,扩容操作可能会导致产生数组越界的异常。

此时,要么使用线程安全的容器,比如Vector,要么使用collect完成串行收集。

List collect = IntStream.rangeClosed(1, 10000).parallel().boxed().collect(Collectors.toList());

(2)线程关联的ThreadLocal将会失效 

这一点从第二小节就可以看出,主线程参与到parallelStream中的任务处理的过程中。如果我们处理的任务方法中包含对ThreadLocal的处理,可能除主线程之外的所有线程都获取不到自己的线程局部变量,加之ForkJoinPool中的线程是反复使用的,线程关联的ThreadLocal会发生共用的情况。

所以我的建议是,parallelStream中就不要使用ThreadLocal了,要么在任务处理方法中,第一行先进行ThreadLocal.set(),之后再由ThreadLocal.get()获取到自己的线程局部变量。

非要用ThreadLocal的话,为了规避使用不当而带来内存泄漏的风险

(3)使用parallelStream也不一定会提升性能

在CPU资源紧张的时候,使用并行流可能会带来频繁的线程上下文切换,导致并行流执行的效率还没有串行执行的效率高。

如果要使用 还是需要有一定程度的理解 

一些运用的小例子

排序

新的排序  比之前的 没啥区别 还多创建一个对象 还是用之前的吧

List<User> list1 = list.stream().sorted((user1,user2)->{
return user1.getAge()-user2.getAge();
}).collect(Collectors.toList());之前的
Collections.sort(list2,(user1,user2)->{
return user1.getAge()-user2.getAge();
});//输出
list1.stream().forEach(System.out::println);
//筛选
List<User> list1 = list.stream().filter(user -> {return user.getAge()>30;}).collect(Collectors.toList());
// 先排序筛选年龄大于30的  
List<User> list1 = list.stream().sorted((user1,user2)->{
return user1.getAge()-user2.getAge();
}).filter(user -> {return user.getAge()>30;}).collect(Collectors.toList());
遍历  看起来有点像js的写法list2.forEach((user)->{
if(user.getAge()>60)
{
tempList.add(user);
System.out.println("test:"+user);
}
});//遍历 实际两种差不多  第二种更偏向于改原来的值 第一种就纯粹是一个便利操作了
 
//映射每个用户对应年龄加一
list.stream().map(user -> {user.setAge(user.getAge()+1);
return user;
});

计算数量 类型为long 

long num = list.stream().count();
Optional<User> max =list.stream().max((user1, user2)-> {  //通过max 取最大值
return user1.getAge()-user2.getAge();
}); 
User maxuser =list.stream().max((user1, user2)-> {// 通过max 取最大值  通过get 获得age最大的那个对象
return user1.getAge()-user2.getAge();
}).get(); 
 
//  过滤判断 
// 获得 属性集合
List<user> notNullList = orderDetailList.stream().filter(x -> !StringUtils.isEmpty(x.getCyitemno())).collect(Collectors.toList());
List<String> cyitemnolist = notNullList.stream().map(x -> x.getCyitemno()).collect(Collectors.toList())