【java 笔记】Stream
参考于https://www.cnblogs.com/andywithu/p/7404101.html
作用
对大量数据进行集中操作的得到目标对象群
下面以一段代码为例做出解释
意为过滤掉年龄大于75的孩子
class Son{
private String name;
private Integer age;
public Son(String name,Integer age){
this.age=age;
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
public class hello {
static Random random;
static List<Son> sonList;
static
{
random=new Random();
sonList=new ArrayList<Son>(){
{
for (int i = 0; i < 100; i++) {
add(new Son("student" + i, random.nextInt(50) + 50));
}
}
};
}
public static void main(String[] args){
List<String> sons=sonList.stream()
.filter((x)->x.getAge()>75)
.sorted(Comparator.comparing(Son::getAge))
.map(Son::getName)
.collect(Collectors.toList());
System.out.println(sons);
}
}
通过大段stream操作输出目标流&集合&对象
目前看来作用比较简单,关键在于特性
引摘自博客的话,stream的特性主要在于三点
1.stream不存储数据
流操作是一次性的
2.stream不改变源数据
以上为例,流操作不会影响sonList
中的数据
3.stream的延迟执行特性
在流的聚合操作(即常规操作)之前可以改动添加数据
操作
代码借用https://www.cnblogs.com/andywithu/p/7404101.html
/**
* 通过数组创建流
*/
@Test
public void testArrayStream(){
//1.通过Arrays.stream
//1.1基本类型
int[] arr = new int[]{1,2,34,5};
IntStream intStream = Arrays.stream(arr);
//1.2引用类型
Student[] studentArr = new Student[]{new Student("s1",29),new Student("s2",27)};
Stream<Student> studentStream = Arrays.stream(studentArr);
//2.通过Stream.of
Stream<Integer> stream1 = Stream.of(1,2,34,5,65);
//注意生成的是int[]的流
Stream<int[]> stream2 = Stream.of(arr,arr);
stream2.forEach(System.out::println);
}
通过工具类Arrays的Stream方法将数组转化为流
/**
* 通过集合创建流
*/
@Test
public void testCollectionStream(){
List<String> strs = Arrays.asList("11212","dfd","2323","dfhgf");
//创建普通流
Stream<String> stream = strs.stream();
//创建并行流
Stream<String> stream1 = strs.parallelStream();
}
通过集合&表的自带的Stream方法将他们自身转化成流
@Test
public void testEmptyStream(){
//创建一个空的stream
Stream<Integer> stream = Stream.empty();
}
通过Stream自身类创造空流(意义暂不明)
@Test
public void testUnlimitStream(){
//创建无限流,通过limit提取指定大小
Stream.generate(()->"number"+new Random()
.nextInt())
.limit(100)
.forEach(System.out::println);
Stream.generate(()->new Student("name",10)).limit(20).forEach(System.out::println);
}
无限流(自动转换)
/**
* 产生规律的数据
*/
@Test
public void testUnlimitStream1(){
Stream.iterate(0,x->x+1).limit(10).forEach(System.out::println);
Stream.iterate(0,x->x).limit(10).forEach(System.out::println);
//Stream.iterate(0,x->x).limit(10).forEach(System.out::println);与如下代码意思是一样的
Stream.iterate(0, UnaryOperator.identity()).limit(10).forEach(System.out::println);
}
规律无限流(其中0为初始值)
public static void main(String[] args){
long son_count=sonList.stream()
.filter((x)->x.getAge()>75)
.sorted(Comparator.comparing(Son::getAge))
.distinct()
.count();
//System.out.println(son_count);
Optional<Integer> LOL=Stream.iterate(20,x->x+1)
.limit(1)
.reduce((x,y)->x-y);
System.out.println(LOL.get());
}
返回Optional
流类型
原始类型流
public static void main(String[] args){
Stream intStream=IntStream.of(4,5,6).boxed();
intStream.forEach(System.out::println);
}
public static void main(String[] args){
IntStream intStream=IntStream.of(4,5,6);
intStream.forEach(System.out::println);
}
输出均为
4
5
6
并行流
*parallel()*方法改变流从串行流变为并行流
public static void peek1(int x) {
System.out.println(Thread.currentThread().getName() + ":->peek1->" + x);
}
public static void peek2(int x) {
System.out.println(Thread.currentThread().getName() + ":->peek2->" + x);
}
public static void peek3(int x) {
System.out.println(Thread.currentThread().getName() + ":->final result->" + x);
}
public static void main(String[] args){
Stream<Integer> stream = Stream.iterate(1, x -> x + 1).limit(10);
stream.peek(hello::peek1).filter(x -> x > 5)
.peek(hello::peek2).filter(x -> x < 8)
.peek(hello::peek3)
.forEach(System.out::println);
}
输出为
main:->peek1->1
main:->peek1->2
main:->peek1->3
main:->peek1->4
main:->peek1->5
main:->peek1->6
main:->peek2->6
main:->final result->6
6
main:->peek1->7
main:->peek2->7
main:->final result->7
7
main:->peek1->8
main:->peek2->8
main:->peek1->9
main:->peek2->9
main:->peek1->10
main:->peek2->10
加入*parallel()*方法后
public static void main(String[] args){
Stream<Integer> stream = Stream.iterate(1, x -> x + 1).limit(10).parallel();
stream.peek(hello::peek1).filter(x -> x > 5)
.peek(hello::peek2).filter(x -> x < 8)
.peek(hello::peek3)
.forEach(System.out::println);
}
输出为
ForkJoinPool.commonPool-worker-3:->peek1->3
ForkJoinPool.commonPool-worker-1:->peek1->9
ForkJoinPool.commonPool-worker-1:->peek2->9
ForkJoinPool.commonPool-worker-1:->peek1->10
ForkJoinPool.commonPool-worker-1:->peek2->10
ForkJoinPool.commonPool-worker-4:->peek1->5
ForkJoinPool.commonPool-worker-2:->peek1->2
ForkJoinPool.commonPool-worker-5:->peek1->1
main:->peek1->7
main:->peek2->7
main:->final result->7
7
ForkJoinPool.commonPool-worker-1:->peek1->4
ForkJoinPool.commonPool-worker-6:->peek1->6
ForkJoinPool.commonPool-worker-3:->peek1->8
ForkJoinPool.commonPool-worker-6:->peek2->6
ForkJoinPool.commonPool-worker-3:->peek2->8
ForkJoinPool.commonPool-worker-6:->final result->6
6
可以看出加入*parallel()*方法明显数据处理以并行方式进行
以下文字摘自https://www.cnblogs.com/andywithu/p/7404101.html
我们将stream.filter(x -> x > 5).filter(x -> x < 8).forEach(System.out::println)的过程想象成上图的管道,我们在管道上加入的peek相当于一个阀门,透过这个阀门查看流经的数据,
1)当我们使用顺序流时,数据按照源数据的顺序依次通过管道,当一个数据被filter过滤,或者经过整个管道而输出后,第二个数据才会开始重复这一过程
2)当我们使用并行流时,系统除了主线程外启动了七个线程(我的电脑是4核八线程)来执行处理任务,因此执行是无序的,但同一个线程内处理的数据是按顺序进行的。
sorted()、distinct()等对并行流的影响
sorted()、distinct()是元素相关方法,和整体的数据是有关系的,map,filter等方法和已经通过的元素是不相关的,不需要知道流里面有哪些元素 ,并行执行和sorted会不会产生冲突呢?
结论:
1.并行流和排序是不冲突的
2.一个流是否是有序的,对于一些api可能会提高执行效率,对于另一些api可能会降低执行效率
3.如果想要输出的结果是有序的,对于并行的流需要使用forEachOrdered(forEach的输出效率更高)
在积累了一点知识后,我们下一章将从新开始学习设计思想Abstract-document