什么是Stream流式计算
大数据:存储 + 计算
集合、MySQL 本质就是存储东西的;
计算都应该交给流来操作!
Stream是对集合功能的增强,它提供了各种非常便利、高效的聚合操作,可以大批量数据操作,同时再结合Lambda表达式,就可以极大的提高编程效率。
Stream的API提供了串行和并行两种模式进行操作数据。
Stream操作分为中间操作或者最终操作两种:
- 中间操作,返回Stream本身,这样就可以将多个操作依次串起来例如,
map、flatMap、filter、distinct、sorted、peek、limit、skip、parallel、sequential、unordered
- 最终操作,返回一特定类型的计算结果例如,
forEach、forEachOrdered、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator
public class User {
private Integer id;
private String name;
private Integer age;
// get、set
// 有参、无参构造方法
// tostring
}
package com.kuang.stream;
import java.util.Arrays; import java.util.List;
/**
* 题目要求:一分钟内完成此题,只能用一行代码实现! * 现在有5个用户!筛选:
* 1、ID 必须是偶数
* 2、年龄必须大于23岁
* 3、用户名转为大写字母
* 4、用户名字母倒着排序
* 5、只输出一个用户!
*/
public class Test {
public static void main(String[] args) {
User u1 = new User(1,"a",21);
User u2 = new User(2,"b",22);
User u3 = new User(3,"c",23);
User u4 = new User(4,"d",24);
User u5 = new User(6,"e",25);
// 集合就是存储
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
// 计算交给Stream流
// lambda表达式、链式编程、函数式接口、Stream流式计算
list.stream()
.filter(u->{return u.getId()%2==0;})
.filter(u->{return u.getAge()>23;})
.map(u->{return u.getName().toUpperCase();})
// 这个只是字符串比较 如果是对象比较需要另一种方式
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
.limit(1)
.forEach(System.out::println);
}
}
Stream的操作,看起来很像生产车间的流水线作业:
常用方法:
iterator
:返回迭代器对象-
forEach
:将调Stream中的每个元素,交给一个Consumer函数处理public class Test { public static void main(String[] args{ Stream<String> stream = Stream.of("hello","world","briup"); stream.forEach(System.out::println); } }
-
count
:统计流中的元素数,并返回结果public class Test { public static void main(String[] args{ Stream<String> stream = Stream.of("hello","world","briup"); System.out.println(stream.count()); } }
-
max
:返回流中基于comparator所指定的比较规则,比较出的最大值
toArray
:使用调用流中的元素,生成数组返回-
filter
:过滤public static void filter(){ // 通过流将字符串转换成Stream格式的集合 Stream<String> java = Stream.of("Java", "Python", "PHP"); // 将包含字符串P的字符串筛选出来,并打印结果 java.filter(str -> str.contains("P")).forEach(str -> System.out.println(str)); }
-
distinct
:去重System.out.println("所有user的年龄集合"); List<Integer> userAgeList = list.stream().map(User::getAge).distinct().collect(Collectors.toList()); System.out.println("userAgeList = " + userAgeList);
所有user的年龄集合 userAgeList = [``10``, ``12``, ``15``, ``25``, ``16``, ``14``, ``17``]
Collectors.toList()
:返回一个 Collector ,它将输入元素 List到一个新的 List-
limit
:limit返回包含前n个元素的流,当集合大小小于n时,则返回实际长度public static void filter(){ // 通过流将字符串转换成Stream格式的集合 Stream<String> java = Stream.of("Java", "Python", "PHP"); // 将包含字符串P的字符串筛选出来,只输出一个 java.filter(str -> str.contains("P")).limit(1).forEach(str -> System.out.println(str)); }
-
sorted
:sorted要求待比较的元素必须实现comparator
接口-
Comparator接口里面有一个compare方法,方法有两个参数T o1和T o2,是泛型的表示方式,分别表示待比较的两个对象
- o1大于o2,如果返回正整数,表示参数o1大于o2
- o1等于o2,返回0
- o1小于o2,如果返回负整数,表示参数o1小于o2
import java.util.Comparator; public class StudentComparator implements Comparator<StudentBean>{ public int compare(StudentBean o1, StudentBean o2) { // 返回负数 说明比较器认为传进来得参数o1比o2小,所以o1在o2前面 // 实际上从我们角度o1比o2大 // 但是比较器只看返回得结果去判断o1是否大于o2从而进行升序降序 if(o1.getScore() > o2.getScore()){ return -1; }else if(o1.getScore() < o2.getScore()){ return 1; } return 0; } }
-
-
map
:映射假设我们希望筛选出所有专业为计算机科学的学生姓名,那么我们可以在filter筛选的基础之上,通过map将学生实体映射成为学生姓名字符串
List<String> names = students.stream() .filter(student -> "计算机科学".equals(student.getMajor())) .map(Student::getName).collect(Collectors.toList());
除了上面这类基础的map,java8还提供了
mapToDouble(ToDoubleFunction mapper)
,mapToInt(ToIntFunction mapper)
,mapToLong(ToLongFunction mapper)
,这些映射分别返回对应类型的流,java8为这些流设定了一些特殊的操作,比如我们希望计算所有专业为计算机科学学生的年龄之和,那么我们可以实现如下:int totalAge = students.stream() .filter(student -> "计算机科学".equals(student.getMajor())) .mapToInt(Student::getAge).sum();
调用串行Stream的
parallel()
方法,可以将其转换并行Stream-
flatMap
:flatMap与map的区别在于 flatMap是将一个流中的每个值都转成一个个流,然后再将这些流扁平化成为一个流 。举例说明,假设我们有一个字符串数组
String[] strs = {"java8", "is", "easy", "to", "use"};
,我们希望输出构成这一数组的所有非重复字符,那么我们可能首先会想到如下实现:
List<String[]> distinctStrs = Arrays.stream(strs) // 映射成为Stream<String[]> .map(str -> str.split("")) .distinct() .collect(Collectors.toList());
在执行map操作以后,我们得到是一个包含多个字符串(构成一个字符串的字符数组)的流,此时执行
distinct操作是基于在这些字符串数组之间的对比,所以达不到我们希望的目的,此时的输出为:
[j, a, v, a, 8] [i, s] [e, a, s, y] [t, o] [u, s, e]
-
方法 说明 filter 元素过滤,对Stream对象按照指定的Predicate进行过滤,返回的Strema对象中仅包含满足条件的元素 map [mapToInt] [mapToLong] [mapToDouble] 元素一对一转换,使用传入的Function对象对Stream中所有元素进行映射处理,返回的Stream对象中的元素为原元素处理后的结果 flatMap (flatMapToInt) (flatMapToLong) (flatMapToDouble) 元素一对多转换,对Stream对象中的所有元素进行操作,每个元素会有一个或多个结果,然后将所有的元素组合成一个统一的Stream并返回 distinct 元素去重,返回去重后的Stream对象 sorted [sorted(Comparator<? super T> comparator)] 元素排序,返回排序后的Stream对象 limit 元素截取,返回有限个元素组成新的Stream对象 skip 元素跳过,抛弃前指定个元素后,使用剩下的元素组成新的Stream对象返回 peek 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数即引用的方法,当Stream每个元素被消费的时候都会先执行新Stream给定的方法 distinct只有对于一个包含多个字符的流进行操作才能达到我们的目的,即对
Stream<String>
进行操作。此时flatMap就可以达到我们的目的:
List<String> distinctStrs = Arrays.stream(strs) // 映射成为Stream<String[]> .map(str -> str.split("")) // 扁平化为Stream<String> .flatMap(Arrays::stream) .distinct() .collect(Collectors.toList());
flatMap将由map映射得到的
Stream<String[]>
,转换成由各个字符串数组映射成的流Stream<String>
,再将这些小的流扁平化成为一个由所有字符串构成的大流Steam<String>
,从而能够达到我们的目的。