Stream流
1、为什么需要 Stream?
首先:流就是从支持数据处理操作的源生成的元素序列
(1) 元素序列:和集合一样,流提供了一个接口,可以访问特定元素的一组有序值。因为集合时数据结构,所以它的主要目的是以特定的时间/空间复杂度储存和访问数据。但流的目的是表达计算。因此,集合讲的是数据,流讲的是计算。
(2)源:流会从源中获取要处理的流,有序集合生成流时会保持原来的顺序。
(3)数据处理操作:对数据进行处理,包括过滤,排序,遍历等。流操作还可以顺序执行和并行执行。
(4)流水线:很多流操作会返回处理后的流,这样我们就可以将多个操作链接起来。
(5)内部迭代:流的迭代是在背后进行的,跟迭代器显式迭代不太一样。
2、 流和集合的区别
(1)什么时候进行读取和计算:
集合是一个内存中的数据结构,包含数据结构中目前所有的值,我们要先把所有的数据加载到集合中以后才可以对集合进行操作。就像我们我们用DVD看电影,包含电影的所有东西。要看必须要有完整的电影。
流则是在概念上的固定的数据结构,其元素则是按需计算。例如我们在网上看电影,只需要加载目前进度的后面几分钟的电影就行。这样做有很大的好处,就是只有在我们需要的时候才会加载值。
(2)流只能遍历一次:
流和迭代器一样只能遍历一次,或者说只能消费一次。如果我们对一个流消费两次,那么代码会抛出java.lang.IllegalStateException:流已被操作或关闭。除非我们从数据源那再获取一个流。于此相反,我们可以对集合进行任意次的操作。
(3)内部迭代和外部迭代:
我们使用集合或者迭代器的时候,需要我们自己去声明如何进行迭代,例如使用for循环或者是hasNext显性的去获取每一个元素,然后再在方法体中说明如何操作这些元素。这个就是外部迭代。对于流来说,你只需要申明对流进行什么操作。流会自动在内部对元素进行迭代。这就是内部迭代。
3、流的操作
java.util.stream.Stream中的Stream接口定义了很多操作。它们可以分成两大类:中间操作和终端操作。
1,Collection体系的集合可以使用默认方法 stream()生成流
List<String> list = new ArrayList<>();
Stream<String> stringStream = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stringStream1 = set.stream();
2, Map集合间接生成流
Map<String,Integer> map = new HashMap<>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String,Integer>> stream=map.entrySet().stream();
3、数组可以通过吧Stream接口的静态方法 of(T…values)[可变参数]生成流
String[] strings ={"小华","小崔","小帅"};
Stream<String> strArrStream = Stream.of(strings);
Stream<String> stringStream2 = Stream.of("hello","word","java");
Stream<Integer> intArrStream = Stream.of(10,20,30);
4,数组工具类 Arrays.stream()
String[] strings1 ={"小","崔","帅"};
Stream<String> arraysStream = Arrays.stream(strings1);
System.out.println(arraysStream);
5 Stream流自己的静态方法 iterator() 和 generate()
Stream<Double> generate = Stream.generate(() -> (Math.random()));
Stream<Double> limit = generate.limit(10);
limit.forEach(s-> System.out.println(s));
中间操作
中间操作会返回一个新的流,例如从peopleList.stream()产生的流,在经过filter()以后,会产生一个新的流,给sorted()使用,在sorted()使用以后会产生一个流给map。这样不断的传递下去,就相当于工厂的流水线。还有很重要的一点,除非流水线触发一个终端操作,不然中间操作不会执行任何处理。因为中间操作能够合并起来,在终端操作时一次性全部处理。
List<String> nameList2 = peopleList.stream()
//过滤出年龄小于40的人
.filter(people1 ->{System.out.println("filter:"+people1.getAge());
return people1.getAge()<40;} )
//获取名称
.map(people -> {
System.out.println("map"+people.getName());
return people.getName();
})
//直取前三个
.limit(2)
//返回结果
.collect(Collectors.toList());
终端操作
终端操作会从流水线中生成结果。返回结果可以是List,Integer,甚至是void。
Stream<String> stringStream = Stream.of("a","m","c","u","e");
String reduceString = stringStream.reduce("120", (str1, str2) -> str1 + str2);
System.out.println(reduceString);//120amcue
Stream<Integer> integerStream = Stream.of(1,2,3,4,5,6);
Integer reduceInteger = integerStream.reduce(100,(v1,v2)->v1+v2);
System.out.println(reduceInteger);//121
System.out.println("=====");
Stream<String> stringStream5 = Stream.of("z","d","a","b","c");
//计算元素个数 stringStream5使用这一次之后就不能再使用了
Long collect = stringStream5.collect(Collectors.counting());
System.out.println(collect);//5
//拼接字符串 直接全部打印,不用循环遍历打印
Stream<String> stringStream6 = Stream.of("z","d","a","b","c");
String collect1 = stringStream6.collect(Collectors.joining());
System.out.println(collect1);//zdabc
//把流中的元素收集到lsit集合容器中
Stream<String> stringStream7 = Stream.of("z","d","a","b","c");
List<String> collect2 = stringStream7.collect(Collectors.toList());
System.out.println(collect2);//[z, d, a, b, c]
//把流中的元素收集到set集合容器中
Stream<String> stringStream8 = Stream.of("z","d","a","b","c");
Set<String> collect3 = stringStream8.collect(Collectors.toSet());
System.out.println(collect3);//[a, b, c, d, z]
Stream<String> stringStream9 = Stream.of("z","d","a","b","c");
ArrayList<String> collect5 = stringStream9.collect(Collectors.toCollection(() -> new ArrayList<String>()));
System.out.println(collect5);//[z, d, a, b, c]
System.out.println("+++++");
Stream<Integer> stringStream10 = Stream.of(1,5,3,2,6);
IntSummaryStatistics collect6 = stringStream10.collect(Collectors.summarizingInt(v -> v));
System.out.println(collect6.getMax());
System.out.println(collect6.getCount());
//6 5
/*分组*/
ArrayList<Student> arrayList = new ArrayList<>();
Student s1 = new Student("张三","男","#5",1);
Student s2 = new Student("李二","男","#5",1);
Student s3 = new Student("张五","女","#5",1);
Student s5 = new Student("张6","男","#5",1);
Student s6 = new Student("张9","女","#5",1);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s5);
arrayList.add(s6);
/*获取学生集合的Stream 流*/
Stream<Student> studentStream = arrayList.stream();
Map<String, List<Student>> collect4 = studentStream.collect(Collectors.groupingBy((stu) -> stu.getSex()));
collect4.forEach((k,v)-> System.out.println(k+"======"+v));
/*女======[Stream.Student@c4437c4, Stream.Student@433c675d]
男======[Stream.Student@3f91beef, Stream.Student@1a6c5a9e, Stream.Student@37bba400]