终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void
查找与匹配
allMatch(Predicate p):检查是否匹配所有元素
anyMatch(Predicate p):检查是否至少匹配一个元素
noneMatch(Predicate p):检查是否没有匹配所有元素
findFirst():返回第一个元素
findAny():返回当前流中的任意元素
count():返回流中元素的总数
max(Comparator c):返回流中的最大值
min(Comparator c):返回流中的最小值
forEach(Consumer c):内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代,相反,Stream API使用内部迭代--他帮你把迭代做了。)
具体Demo
package com.chentongwei.java8.day01;
public class Employee {
private Integer id;
private String name;
private int age;
private double salary;
public Employee(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Employee(Integer id) {
super();
this.id = id;
}
public Employee(String name, int age, double salary) {
super();
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee() {
super();
}
public Employee(Integer id, String name, int age, double salary) {
super();
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(salary);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (age != other.age)
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
return false;
return true;
}
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
}
package com.chentongwei.java8.day05;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.Test;
import com.chentongwei.java8.day05.Employee.Status;
/**
* Stream流的终止操作
* @author TongWei.Chen
* @date 2017年4月2日14:34:13
*/
public class TestStreamaAPI4 {
List emps = Arrays.asList(
new Employee(102, "李四", 59, 6666.66, Status.BUSY),
new Employee(101, "张三", 18, 9999.99, Status.FREE),
new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
new Employee(104, "赵六", 8, 7777.77, Status.FREE),
new Employee(104, "赵六", 8, 7777.77, Status.FREE),
new Employee(105, "田七", 38, 5555.55, Status.BUSY)
);
//终止操作
/*
allMatch——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配的元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
count——返回流中元素的总个数
max——返回流中最大值
min——返回流中最小值
*/
@Test
public void test1(){
boolean bl = emps.stream()
.allMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl);
boolean bl1 = emps.stream()
.anyMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl1);
boolean bl2 = emps.stream()
.noneMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl2);
}
@Test
public void test2(){
//optional:防止空指针,java8出的,会自动判断创建的流是否有可能为null,若有可能则返回optional
//若为null,则optional会负责产生一个临时对象,防止出现空指针。
Optional op = emps.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());
System.out.println("--------------------------------");
Optional op2 = emps.parallelStream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.findAny();
System.out.println(op2.get());
}
@Test
public void test3(){
long count = emps.stream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.count();
System.out.println(count);
Optional op = emps.stream()
.map(Employee::getSalary)
.max(Double::compare);
System.out.println(op.get());
Optional op2 = emps.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op2.get());
}
//注意:流进行了终止操作后,不能再次使用
@Test
public void test4(){
Stream stream = emps.stream()
.filter((e) -> e.getStatus().equals(Status.FREE));
@SuppressWarnings("unused")
long count = stream.count();
stream.map(Employee::getSalary)
.max(Double::compare);
}
}
归约
reduce(T iden, BinaryOperator b):可以将流中元素反腐结合起来,得到一个值。返回T
reduce(BinaryOperator b):可以将流中元素反复结合起来,得到一个值,返回Optional
备注:map和reduce的连接通常称为map-reduce模式。
package com.chentongwei.java8.day05;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.junit.Test;
import com.chentongwei.java8.day05.Employee.Status;
/**
* Stream流的终止操作
* @author TongWei.Chen
* @date 2017年4月2日14:34:13
*/
public class TestStreamaAPI5 {
List emps = Arrays.asList(
new Employee(102, "李四", 79, 6666.66, Status.BUSY),
new Employee(101, "张三", 18, 9999.99, Status.FREE),
new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
new Employee(104, "赵六", 8, 7777.77, Status.FREE),
new Employee(104, "赵六", 8, 7777.77, Status.FREE),
new Employee(105, "田七", 38, 5555.55, Status.BUSY)
);
//3. 终止操作
/*
归约
reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。
*/
@Test
public void test1() {
List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0, (x ,y) -> x + y);
System.out.println(sum);
System.out.println("----------------------------------------");
//统计所有员工的工资总和
Optional op = emps.stream().map(Employee :: getSalary).reduce(Double :: sum);
System.out.println(op.get());
}
}
结果为
55
----------------------------------------
48888.84000000001
分析:
为什么是55?
Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0, (x ,y) -> x + y);
这句话会首先把0当做x,把1(数组下标为0的)当做y进行相加
0+1=1
然后会把0+1的结果作为x,2(数组下标为1的)作为y进行相加
0+1+2=3
然后会把0+1+2的值作为x,3(数组下标为2的)作为y进行相加
....
最后结果55
收集
collect(Collector c):将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map等)。但是Collectors实用类提供了很多静态方法,可以方便的创建常见收集器实例,具体如下表:
Demo
package com.chentongwei.java8.day05;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Test;
import com.chentongwei.java8.day05.Employee.Status;
/**
* Stream流的终止操作
* @author TongWei.Chen
* @date 2017年4月2日14:34:13
*/
public class TestStreamaAPI6 {
List emps = Arrays.asList(
new Employee(102, "李四", 79, 6666.66, Status.BUSY),
new Employee(101, "张三", 18, 9999.99, Status.FREE),
new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
new Employee(104, "赵六", 8, 7777.77, Status.FREE),
new Employee(104, "赵六", 8, 7777.77, Status.FREE),
new Employee(105, "田七", 38, 5555.55, Status.BUSY)
);
//collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
@Test
public void test1() {
//把name放到list中
List list = emps.stream().map(Employee :: getName).collect(Collectors.toList());
//[李四, 张三, 王五, 赵六, 赵六, 赵六, 田七]
System.out.println(list);
//把name放到set中
Set set = emps.stream().map(Employee :: getName).collect(Collectors.toSet());
//[李四, 张三, 王五, 赵六, 田七],Set不可重复
System.out.println(set);
//把name放到自定义类中,比如HashSet,而并非是Set接口
HashSet hashset = emps.stream().map(Employee :: getName).collect(Collectors.toCollection(HashSet :: new));
//[李四, 张三, 王五, 赵六, 田七]
System.out.println(hashset);
}
@Test
public void test2() {
//找到员工工资最多的那个人
Optional max = emps.stream()
.map(Employee :: getSalary)
.collect(Collectors.maxBy(Double :: compare));
//9999.99
System.out.println(max.get());
//找到员工工资最少的
Optional min = emps.stream()
.map(Employee :: getSalary)
.collect(Collectors.minBy(Double :: compare));
//3333.33
System.out.println(min.get());
//员工工资总和
double sum = emps.stream()
.collect(Collectors.summingDouble(Employee :: getSalary));
//48888.840000000004
System.out.println(sum);
//员工工资平均值
double avg = emps.stream()
.collect(Collectors.averagingDouble(Employee :: getSalary));
//6984.120000000001
System.out.println(avg);
//员工总数
Long count = emps.stream().collect(Collectors.counting());
//7
System.out.println(count);
//另外一种实现方式
DoubleSummaryStatistics dss = emps.stream()
.collect(Collectors.summarizingDouble(Employee :: getSalary));
System.out.println(dss.getMax());
System.out.println(dss.getMin());
System.out.println(dss.getAverage());
System.out.println(dss.getCount());
System.out.println(dss.getSum());
}
//分组
@Test
public void test3() {
Map> map = emps.stream()
.collect(Collectors.groupingBy(
Employee :: getStatus));
//{FREE=[Employee [id=101, name=张三, age=18, salary=9999.99, status=FREE], Employee [id=104, name=赵六, age=8, salary=7777.77, status=FREE], Employee [id=104, name=赵六, age=8, salary=7777.77, status=FREE]], BUSY=[Employee [id=102, name=李四, age=79, salary=6666.66, status=BUSY], Employee [id=104, name=赵六, age=8, salary=7777.77, status=BUSY], Employee [id=105, name=田七, age=38, salary=5555.55, status=BUSY]], VOCATION=[Employee [id=103, name=王五, age=28, salary=3333.33, status=VOCATION]]}
System.out.println(map);
}
//多级分组(先按照status,在按照自定义的规则分)
@Test
public void test4() {
Map>> map =
emps.stream()
.collect(
Collectors.groupingBy(
Employee :: getStatus,
Collectors.groupingBy((e) -> {
if(e.getAge() >= 60) {
return "old";
} else if(e.getAge() >= 35) {
return "中年";
} else
return "成年";
})));
//{FREE={成年=[Employee [id=101, name=张三, age=18, salary=9999.99, status=FREE], Employee [id=104, name=赵六, age=8, salary=7777.77, status=FREE], Employee [id=104, name=赵六, age=8, salary=7777.77, status=FREE]]}, BUSY={old=[Employee [id=102, name=李四, age=79, salary=6666.66, status=BUSY]], 成年=[Employee [id=104, name=赵六, age=8, salary=7777.77, status=BUSY]], 中年=[Employee [id=105, name=田七, age=38, salary=5555.55, status=BUSY]]}, VOCATION={成年=[Employee [id=103, name=王五, age=28, salary=3333.33, status=VOCATION]]}}
System.out.println(map);
}
//分区
@Test
public void test5() {
Map> map =
emps.stream().collect(Collectors.partitioningBy(e -> e.getSalary() >= 5000));
//{false=[Employee [id=103, name=王五, age=28, salary=3333.33, status=VOCATION]], true=[Employee [id=102, name=李四, age=79, salary=6666.66, status=BUSY], Employee [id=101, name=张三, age=18, salary=9999.99, status=FREE], Employee [id=104, name=赵六, age=8, salary=7777.77, status=BUSY], Employee [id=104, name=赵六, age=8, salary=7777.77, status=FREE], Employee [id=104, name=赵六, age=8, salary=7777.77, status=FREE], Employee [id=105, name=田七, age=38, salary=5555.55, status=BUSY]]}
//分成了 true和false两个区。每个区中的数据是根据e.getSalary() >= 5000来分配的
System.out.println(map);
}
//字符串拼接
@Test
public void test6() {
String str = emps.stream().map(Employee :: getName).collect(Collectors.joining());
//李四张三王五赵六赵六赵六田七
System.out.println(str);
String str1 = emps.stream().map(Employee :: getName).collect(Collectors.joining(","));
//李四,张三,王五,赵六,赵六,赵六,田七
System.out.println(str1);
}
//求和,求最大,求最小等等另一种实现方式
@Test
public void test7(){
Optional sum = emps.stream()
.map(Employee::getSalary)
.collect(Collectors.reducing(Double::sum));
//48888.84000000001
System.out.println(sum.get());
Optional max = emps.stream()
.map(Employee::getSalary)
.collect(Collectors.reducing(Double::max));
//9999.99
System.out.println(max.get());
}
}
若有兴趣,欢迎来加入群,【Java初学者学习交流群】:458430385,此群有Java开发人员、UI设计人员和前端工程师。有问必答,共同探讨学习,一起进步!
欢迎关注我的微信公众号【Java码农社区】,会定时推送各种干货: