回顾往期内容
![d223be3ee78059472d708e900bd361fd.png](https://i-blog.csdnimg.cn/blog_migrate/e46727644ac9a102bd8c68ec8bb5c8fc.png)
经过上一篇内容的讲解,相信小伙伴们应该或多或少对流基础操作有了那么一丢丢的感觉了吧!当然,streamApi的重要操作其实最主要还是在对流结果的处理上,也就是我们非常关心的终止操作,因为只有经过这一道工序我们才能最终把想要的结果进行进一步收集整理,得到我们最终想要的。所以。接下来呢,让我们进入最重要的一个环节,也就是流的最后一步操作,流的终止操作。
![d223be3ee78059472d708e900bd361fd.png](https://i-blog.csdnimg.cn/blog_migrate/e46727644ac9a102bd8c68ec8bb5c8fc.png)
引言
在正式进入前,问小伙伴们一个问题,咱们平常操作数据库,最常用的操作是什么?
相信大家都能答得上来,当然是查询啦。可以说,在增删改查中,查询占比可达到80%以上,这也是为什么数据库的索引会去采用B+树以牺牲增删改性能,来提升查询效率的原因了。既然查询这么重要,当然,stream中也不会缺席,最常用的查询,在Stream当中也都有。接下来,咱们来讲Stream当中关于匹配查找的内容。
![cf5c58b1e4dfd3c7c65a1b053346969d.png](https://i-blog.csdnimg.cn/blog_migrate/6b35c1c8f68f279881d46a1f25212dc5.png)
首先,我们先给员工类加上个状态
/**
* @author bihu
*/
public class Employee {
private String name;
private Integer age;
private Double salary;
private Status status;
public Employee(String name, Integer age, Double salary, Status status) {
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
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 Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
/**
* 添加Status内部类
*/
public enum Status{
//空闲
FREE,
//忙碌
BUSY,
//休假
VOCATION;
}
集合申明如下
private static List employees = Arrays.asList(new Employee("张无忌",22,9000.00, Employee.Status.FREE),new Employee("张三丰",88,10000.00, Employee.Status.FREE),new Employee("张翠山",36,8000.00, Employee.Status.VOCATION),new Employee("赵敏",22,7000.00, Employee.Status.FREE),new Employee("谢逊",22,7000.00, Employee.Status.BUSY),new Employee("白眉鹰王",22,7000.00, Employee.Status.BUSY)
);
1
Stream的查找、聚合、归约
01
Stream中的匹配查找(find )
![f867f266b5620fb0ed168eab48584b26.png](https://i-blog.csdnimg.cn/blog_migrate/656be35987fa3fa75c6db3c586d85dff.png)
![1dd76d706adf24d40a82832a19ef9714.png](https://i-blog.csdnimg.cn/blog_migrate/4067cad483bf27c6e3c333ca512e780f.png)
●allMatch(完全匹配)
检查集合中是否匹配所有元素。
/**
* 测试完全匹配
*/
@Testpublic void testAllMatch(){
boolean b = employees.stream().allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b);
}
输出结果:
●anyMatch(至少匹配一个)
检查集合中元素至少有一个匹配
/**
* 测试至少一个匹配
*/
@Testpublic void testAnyMatch(){
boolean b = employees.stream().anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b);
}
输出结果:
●noneMatch(是否没有匹配)
检查集合中是否没有匹配所有元素
/**
* 测试检查是否没有匹配的元素
*/
@Testpublic void testNoneMatch(){
boolean b = employees.stream().noneMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b);
}
输出结果:
●findFirst(返回第一个)
返回集合中的第一元素
/**
* 返回当前流中的第一个元素
* 比较工资最低的员工
*/
@Testpublic void testFindFirst(){
Optional b = employees.stream()
.sorted(Comparator.comparingDouble(Employee::getSalary))
.findFirst();
System.out.println(b.get());
}
输出结果:
●findAny(返回任意一个)
返回集合中任意一个元素,其中可分为单线程和多线程操作,单线程始终返回固定的元素,多线程则返回随机元素
单线程
/**
* 单线程
* 返回当前流中的任意元素
* 只要有一个是空闲的就从团队里调出来
*/
@Testpublic void testFindAny1(){
Optional b = employees.stream()
.filter((e) -> e.getStatus().equals(Employee.Status.FREE))
.findAny();
System.out.println(b.get());
}
输出结果:
多线程
/**
* 多线程
* 返回当前流中的任意元素
* 只要有一个是空闲的就从团队里调出来
*/
@Testpublic void testFindAny2(){
Optional b = employees.parallelStream()
.filter((e) -> e.getStatus().equals(Employee.Status.FREE))
.findAny();
System.out.println(b.get());
}
输出结果:
02
Stream中的简单聚合和归约
![f867f266b5620fb0ed168eab48584b26.png](https://i-blog.csdnimg.cn/blog_migrate/656be35987fa3fa75c6db3c586d85dff.png)
![b8e14f1bb768e363b06e32afbe77b45f.png](https://i-blog.csdnimg.cn/blog_migrate/23cb9066b1bad0a6cd6c0cefd6782769.png)
●count(统计集合元素个数)
对集合的元素进行统计,返回统计结果。
/**
* 返回当前流中元素的总个数
*/
@Testpublic void testCount(){
Long b = employees.stream()
.count();
System.out.println(b);
}
输出结果:
●max(集合中最大的元素)
统计集合中最大元素,可对员工工资进行比较,返回最大的那个员工对象
/**
* 返回当前流中元素的最大值
* 找出工资最高的那个人
*/
@Testpublic void testMax(){
Optional b = employees.stream()
.max(Comparator.comparingDouble(Employee::getSalary));
System.out.println(b.get());
}
输出结果:
●min(集合中最小的元素)
与查找最大值相反操作
/**
* 返回当前流中元素的最小值
* 找出工资最低的那个人
*/
@Testpublic void testMin(){
Optional min = employees.stream()
.map(Employee::getSalary)
.min(Double::compare);
System.out.println(min.get());
}
输出结果:
●reduce(归约)
最常用的组合reduce+map它可用于大规模数据集(大于1TB)的并行运算。
@Testpublic void testReduce1(){
List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0, (x, y) -> x + y);//其中0为起始值先赋值给x
System.out.println(sum);
}
输出结果:
/**
* 计算工资的总和是多少
*/
@Testpublic void testReduce2(){
Optional reduce = employees.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(reduce.get());
}
输出结果:
2
Stream的收集操作
![f867f266b5620fb0ed168eab48584b26.png](https://i-blog.csdnimg.cn/blog_migrate/656be35987fa3fa75c6db3c586d85dff.png)
![2f81380169a97746eb59a8abecfe9904.png](https://i-blog.csdnimg.cn/blog_migrate/b9509f1f3bc65f257b6d7c2d2f0ed2ec.png)
● collectToList(收集到List集合)
最常用的list方式收集
/**
* 收集到list
*/
@Test
public void testCollectList(){
List list = employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());list.forEach(System.out::println);
}
输出结果:
● collectToSet(收集到set集合)
可以通过此方式进行去重收集
/**
* 收集到set
*/
@Test
public void testCollectSet(){
Set list = employees.stream()
.map(Employee::getName)
.collect(Collectors.toSet());list.forEach(System.out::println);
}
添加一条重复数据
输出结果:
● collectToHashSet(到HashSet)
/**
* 收集到HashSet
*/
@Test
public void testCollectHashSet(){
HashSet list = employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));list.forEach(System.out::println);
}
输出结果:
● collectCount(收集count)
/**
* 收集count
*/
@Testpublic void testCollectCounting(){
Long count = employees.stream()
.collect(Collectors.counting());
System.out.println(count);
}
输出结果:
●collectAvgDouble(收集avg)
/**
* 收集avg
*/
@Testpublic void testCollectAvgDouble(){
Double avg = employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
}
输出结果:
● collectSumDouble(收集sum)
/**
* 收集sumDouble
*/
@Testpublic void testCollectSumDouble(){
Double sum = employees.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
}
输出结果:
● collectMax(收集max)
/**
* 收集max
*/
@Testpublic void testCollectMax(){
Optional max = employees.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
}
输出结果:
● collectMin(收集min)
/**
* 收集min
*/
@Testpublic void testCollectMin(){
Optional min = employees.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
}
输出结果:
● collectGroupby(收集分组)
根据员工的状态进行分组
/**
* 单条件分组
*/
@Test
public void testCollectGroupBy1(){
MapList> groupByCondition = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(groupByCondition);
}
输出结果:
{VOCATION=[Employee{name='张翠山', age=36, salary=8000.0}], FREE=[Employee{name='张无忌', age=22, salary=9000.0}, Employee{name='张三丰', age=88, salary=10000.0}, Employee{name='赵敏', age=22, salary=7000.0}], BUSY=[Employee{name='谢逊', age=22, salary=7000.0}, Employee{name='白眉鹰王', age=22, salary=7000.0}, Employee{name='白眉鹰王', age=22, salary=7000.0}]}
我们还可以通过多条件分组,先根据状态分组,然后再根据年龄<=35岁一组名为“青年”,年龄<=50的一组名为“中年”,剩下的归位“老年组”。
/**
* 多条件分组
*/
@Test
public void testCollectGroupBy2(){
MapString, List>> groupByMultiCondition = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e -> {if (e.getAge() <= 35) {return "青年";
} else if (e.getAge() <= 50) {return "中年";
} else {return "老年";
}
})));
System.out.println(groupByMultiCondition);
}
输出结果:
{FREE={青年=[Employee{name='张无忌', age=22, salary=9000.0}, Employee{name='赵敏', age=22, salary=7000.0}], 老年=[Employee{name='张三丰', age=88, salary=10000.0}]}, BUSY={青年=[Employee{name='谢逊', age=22, salary=7000.0}, Employee{name='白眉鹰王', age=22, salary=7000.0}, Employee{name='白眉鹰王', age=22, salary=7000.0}]}, VOCATION={中年=[Employee{name='张翠山', age=36, salary=8000.0}]}}
● collectPartition(分区收集)
/**
* 集合分区
*/
@Testpublic void testCollectPartition(){
Map> map = employees.stream()
.collect(Collectors.partitioningBy(e -> e.getSalary() > 8000));
System.out.println(map);
}
可以看到下面会把<=8000分为false一组,>8000分为true一组
输出结果:
{false=[Employee{name='张翠山', age=36, salary=8000.0}, Employee{name='赵敏', age=22, salary=7000.0}, Employee{name='谢逊', age=22, salary=7000.0}, Employee{name='白眉鹰王', age=22, salary=7000.0}, Employee{name='白眉鹰王', age=22, salary=7000.0}], true=[Employee{name='张无忌', age=22, salary=9000.0}, Employee{name='张三丰', age=88, salary=10000.0}]}
● SummaryStatics(汇总收集)
/**
* 汇总类
*/
@Test
public void testSummaryStatics(){
DoubleSummaryStatistics dss = employees.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getMax());
System.out.println(dss.getAverage());
System.out.println(dss.getCount());
System.out.println(dss.getMin());
System.out.println(dss.getSum());
}
可以一次性获取最大值、平均值、统计、最小值、最大值
输出结果:
● collectJoining(拼接收集)
/**
* 字符串拼接
*/
@Testpublic void testJoining(){
String str = employees.stream()
.map(Employee::getName)
.collect(Collectors.joining(","));
System.out.println(str);
}
输出结果:
![aa6cc3310a19e89ea64449752e4f8e4f.png](https://i-blog.csdnimg.cn/blog_migrate/a4ebabdfcaa14407ff301caacc4e1fee.png)
完结:
本节小结
关于Stream流到此咱们就已经讲完了,关于JDK1.8之所以越来越被企业认可,首先毋庸置疑是其稳定性,其次,用到1.8自然少不了Lambda表达式和Stream流以及1.8的时间类,关于Stream及Lambda我们只有不断的在业务中使用,才会慢慢的熟能生巧,才能不知不觉的体会其强大之处,希望小伙伴能够勤动手,多思考,突然有一天你会发先原来它是如此简单易用。好了,今天的内容就到这里啦!感谢你的收看。如果觉得对你还有用,就帮忙关注下我的公众号吧!你的支持和赞赏是我创作的不竭动力。
![3e3c22d913583160c5e2112ab4dda755.png](https://i-blog.csdnimg.cn/blog_migrate/546869247521e410c7ae905d81eb1e05.png)
![3835c1d2d4a4feb463a9c8110a20e6fa.gif](https://i-blog.csdnimg.cn/blog_migrate/bcef9f632175ad5381468023af86713f.gif)
点击关注了解更多精彩内容
扫 码
长按扫描
![cf8d923829d1569b66ca10cd0f11487a.png](https://i-blog.csdnimg.cn/blog_migrate/94d8cfb24418edf124d1cff10e3e0e9e.png)
关 注
关注我