JDK1.8新特性
1、Lambda 表达式
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码 像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使 Java的语言表达能力得到了提升。
- 从匿名类到 Lambda 的转换
//匿名内部类
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello World!" );
}
};
//Lambda表达式
Runnable r1 = () -> System.out.println("Hello Lambda!");//原来使用匿名内部类作为参数传递
TreeSet<String> ts2 = new TreeSet<>(new Comparator<String>(){
@Override
public int compare(String o1, String o2) {
return Integer.compare(o1.length(), o2.length());
}
});
//Lambda作为参数传递
TreeSet<String> ts2 = new TreeSet<>((o1,o2)->Integer.compare(o1.length(), o2.length()));1.1、Lambda表达式的演变过程
这里以员工的比较为例进行说明
Employee实体类
//这里省略了set,get以及构造方法
public class Employee {
private int id;
private String name;
private int age;
private double salary;
}Test类
public class Test{
List<Employee> emps = Arrays.asList(
new Employee(101, "张三", 18, 9999.99),
new Employee(102, "李四", 59, 6666.66),
new Employee(103, "王五", 28, 3333.33),
new Employee(104, "赵六", 8, 7777.77),
new Employee(105, "田七", 38, 5555.55)
);
//需求:获取公司中年龄小于 35 的员工信息
public List<Employee> filterEmployeeAge(List<Employee> emps){
List<Employee> list = new ArrayList<>();
for (Employee emp : emps) {
if(emp.getAge() <= 35){
list.add(emp);
}
}
return list;
}
//需求:获取公司中工资大于 5000 的员工信息
public List<Employee> filterEmployeeSalary(List<Employee> emps){
List<Employee> list = new ArrayList<>();
for (Employee emp : emps) {
if(emp.getSalary() >= 5000){
list.add(emp);
}
}
return list;
}
//这里是最常见的过滤方法,弊端:不同的过滤条件需要定义不同的函数才可以实现
@Test
public void demo(){
List<Employee> list = filterEmployeeAge(emps);
for (Employee employee : list) {
System.out.println(employee);
}
}
//优化方式一:设计模式中的策略设计模式(MyPredicate<Employee> mp 就是我们所定义的策略)
public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp){
List<Employee> list = new ArrayList<>();
for (Employee employee : emps) {
if(mp.test(employee)){
list.add(employee);
}
}
return list;
}
@Test
public void test4(){
List<Employee> list = filterEmployee(emps, new FilterEmployeeForAge());
for (Employee employee : list) {
System.out.println(employee);
}
System.out.println("------------------------------------------");
List<Employee> list2 = filterEmployee(emps, new FilterEmployeeForSalary());
for (Employee employee : list2) {
System.out.println(employee);
}
}
//优化方式二:匿名内部类
@Test
public void test5(){
List<Employee> list = filterEmployee(emps, new MyPredicate<Employee>() {
@Override
public boolean test(Employee t) {
return t.getId() <= 103;
}
});
for (Employee employee : list) {
System.out.println(employee);
}
}
//优化方式三:Lambda 表达式
@Test
public void test6(){
List<Employee> list = filterEmployee(emps, (e) -> e.getAge() <= 35);
list.forEach(System.out::println);
System.out.println("------------------------------------------");
List<Employee> list2 = filterEmployee(emps, (e) -> e.getSalary() >= 5000);
list2.forEach(System.out::println);
}
//优化方式四:Stream API
@Test
public void test7(){
emps.stream()
.filter((e) -> e.getAge() <= 35)
.forEach(System.out::println);
System.out.println("----------------------------------------------");
emps.stream()
.map(Employee::getName)
.limit(3)
.sorted()
.forEach(System.out::println);
}
}MyPredicate策略接口
@FunctionalInterface
public interface MyPredicate<T> {
public boolean test(T t);
}FilterEmployeeForAge实现类
public class FilterEmployeeForAge implements MyPredicate<Employee>{
@Override
public boolean test(Employee t) {
return t.getAge() <= 35;
}
}FilterEmployeeForSalary实现类
public class FilterEmployeeForSalary implements MyPredicate<Employee> {
@Override
public boolean test(Employee t) {
return t.getSalary() >= 5000;
}
}2、函数式接口
2.1、什么是函数式接口
⚫ 只包含一个抽象方法的接口,称为函数式接口。
⚫ 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方 法上进行声明)。
⚫ 我们可以在任意函数式接口上使用 @FunctionalInterface 注解, 这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包 含一条声明,说明这个接口是一个函数式接口。
2.2、自定义函数式接口
@FunctionalInterface
public interface MyFun {
public Integer getValue(Integer num);
}函数接口中使用泛型
@FunctionalInterface
public interface MyFunc<T> {
public T getValue(T t);
}作为参数传递Lambda 表达式
public String toUpperString(MyFunc<String> mf,String str){
return mf.getValue(str);
}
//调用
String newStr=toUpperString(
(str)->str.toUpperCase(),
"abcdef"
)
System.out.printLn(newStr);
注意:作为参数传递 Lambda 表达式:为了将 Lambda 表达式作为参数传递,接
收Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口
的类型。示例:需求:对一个数进行运算
@Test
public void test6(){
Integer num = operation(100, (x) -> x * x);
System.out.println(num);
System.out.println(operation(200, (y) -> y + 200));
}
public Integer operation(Integer num, MyFun mf){
return mf.getValue(num);
}MyFun
@FunctionalInterface
public interface MyFun {
public Integer getValue(Integer num);
}
2.3、Java 内置四大核心函数式接口
Consumer<T> : 消费型接口
void accept(T t);
Supplier<T> : 供给型接口
T get();
Function<T, R> : 函数型接口
R apply(T t);
Predicate<T> : 断言型接口
boolean test(T t);Consumer
: 消费型接口 void accept(T t);
//Consumer<T> 消费型接口 :
@Test
public void test1(){
happy(10000, (m) -> System.out.println("他喜欢大宝剑,每次消费:" + m + "元"));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}Supplier
: 供给型接口 T get();
//Supplier<T> 供给型接口 :
@Test
public void test2(){
List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
for (Integer num : numList) {
System.out.println(num);
}
}
//需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}Function<T, R> : 函数型接口 R apply(T t);
//Function<T, R> 函数型接口:
@Test
public void test3(){
String newStr = strHandler("\t\t\t 威武 ", (str) -> str.trim());
System.out.println(newStr);
String subStr = strHandler("我威武", (str) -> str.substring(2, 5));
System.out.println(subStr);
}
//需求:用于处理字符串
public String strHandler(String str, Function<String, String> fun){
return fun.apply(str);
}Predicate
: 断言型接口 boolean test(T t);
//Predicate<T> 断言型接口:
@Test
public void test4(){
List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
List<String> strList = filterStr(list, (s) -> s.length() > 3);
for (String str : strList) {
System.out.println(str);
}
}
//需求:将满足条件的字符串,放入集合中
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String str : list) {
if(pre.test(str)){
strList.add(str);
}
}
return strList;
}3、 方法引用与构造器引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用! (实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!) 方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。 如下三种主要使用情况:
⚫ 对象::实例方法 ⚫ 类::静态方法 ⚫ 类::实例方法
* 一、方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用
* (可以将方法引用理解为 Lambda 表达式的另外一种表现形式)
*
* 1. 对象的引用 :: 实例方法名
*
* 2. 类名 :: 静态方法名
*
* 3. 类名 :: 实例方法名
*
* 注意:
* ①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
* ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
*
* 二、构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致!
* 1. 类名 :: new
*
* 三、数组引用
* 类型[] :: new;
*/3.1、方法引用
@Test
public void test1(){
PrintStream ps = System.out;
Consumer<String> con = (str) -> ps.println(str);
con.accept("Hello World!");
System.out.println("--------------------------------");
Consumer<String> con2 = ps::println;
con2.accept("Hello Java8!");
Consumer<String> con3 = System.out::println;
}3.2、对象的引用 :: 实例方法名
//对象的引用 :: 实例方法名
@Test
public void test2(){
Employee emp = new Employee(101, "张三", 18, 9999.99);
Supplier<String> sup = () -> emp.getName();
System.out.println(sup.get());
System.out.println("----------------------------------");
Supplier<String> sup2 = emp::getName;
System.out.println(sup2.get());
}
3.3、类名 :: 静态方法名
//类名 :: 静态方法名
@Test
public void test4(){
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
System.out.println("-------------------------------------");
Comparator<Integer> com2 = Integer::compare;
}
@Test
public void test3(){
BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
System.out.println(fun.apply(1.5, 22.2));
System.out.println("--------------------------------------------------");
BiFunction<Double, Double, Double> fun2 = Math::max;
System.out.println(fun2.apply(1.2, 1.5));
}3.4、类名 :: 实例方法名
@Test
public void test5(){
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
System.out.println(bp.test("abcde", "abcde"));
System.out.println("-----------------------------------------");
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp2.test("abc", "abc"));
System.out.println("-----------------------------------------");
Function<Employee, String> fun = (e) -> e.show();
System.out.println(fun.apply(new Employee()));
System.out.println("-----------------------------------------");
Function<Employee, String> fun2 = Employee::show;
System.out.println(fun2.apply(new Employee()));
}3.5、构造器引用
@Test
public void test7(){
Function<String, Employee> fun = Employee::new;
BiFunction<String, Integer, Employee> fun2 = Employee::new;
}
@Test
public void test6(){
Supplier<Employee> sup = () -> new Employee();
System.out.println(sup.get());
System.out.println("------------------------------------");
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
}3.6、数组引用
@Test
public void test8(){
Function<Integer, String[]> fun = (args) -> new String[args];
String[] strs = fun.apply(10);
System.out.println(strs.length);
System.out.println("--------------------------");
Function<Integer, Employee[]> fun2 = Employee[] :: new;
Employee[] emps = fun2.apply(20);
System.out.println(emps.length);
}4、 Stream API
4.1、什么是Stream
流(Stream) 到底是什么呢?
流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 “集合讲的是数据,流讲的是计算!”
注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream流的一些特点:
- 不是数据结构,不会保存数据
- 不会修改原来的数据源,它会将操作后的数据保存到另一个对象中
- 惰性求值,流在进行中间操作的过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算
4.2、Stream 的操作三个步骤
⚫ 创建 Stream 一个数据源(如:集合、数组),获取一个流
⚫ 中间操作 一个中间操作链,对数据源的数据进行处理
⚫ 终止操作(终端操作) 一个终止操作,执行中间操作链,并产生结果

4.2.1、创建Stream
1、创建Stream流方式一: 通过集合
//创建一个集合
List<Employee> list = EmployeeData.getEmployees();
//得到一个顺序流
Stream<Employee> stream = list.stream();
//得到一个并行了流
Stream<Employee> stream2 = list.parallelStream();2、创建Stream流方式二:通过数组
//先创建一个数组
int[] arr = new int[]{1, 2, 3, 4, 5, 6};
//使用数组Arrays工具类获取Stream流
IntStream stream = Arrays.stream(arr);3、创建Stream流方式三:通过Stream流的of()方法
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);4、创建Stream流方式四:创建无线流
//无限流之迭代方式
//创建了10个元素从0到18
Stream<Integer> s = Stream.iterate(0, t -> t + 2).limit(10);
//无限流之生成方式
//创建了10个随机数
Stream<Double> s2 = Stream.generate(Math::random).limit(10);@Test
public void test1(){
//1. Collection 提供了两个方法 stream() 与 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
//2. 通过 Arrays 中的 stream() 获取一个数组流
Integer[] nums = new Integer[10];
Stream<Integer> stream1 = Arrays.stream(nums);
//3. 通过 Stream 类中静态方法 of()
Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
//4. 创建无限流
//迭代
Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
stream3.forEach(System.out::println);
//生成
Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
stream4.forEach(System.out::println);
}4.2.1.1、迭代
- 1、需求:随机创建int类型的数组,计算各数组中各个元素的总和
- 2、思路:两种方式:外部迭代和内部迭代
- 外部迭代:通过for循环迭代数组
- 内部迭代:先将数组转化成流->再通过流的相关操作来实现
- 外部迭代是串行的,如果要实现并行需要自己编写代码实现;内部迭代实现并行操作只需要调用一个parallel()操作即可
- 3、代码实现
package com.ly.business;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream;
public class Case01 {
private int [] nums;
private int count = 4;
private Random random;
@Before
public void init() {
random = new Random();
nums = new int[count];
for (int i = 0; i < nums.length; i++) { // 随机产生数组元素
nums[i] = random.nextInt(30);
}
}
/**
* 外部迭代:自己利用for训话实现
*/
@Test
public void test01() {
int sum = 0;
for (int i : nums) {
sum += i;
}
System.out.println(Arrays.toString(nums) + " 各个元素的累加和为:" + sum);
}
/**
* 内部迭代:利用流的相关方法实现
*/
@Test
public void test02() {
int sum = 0;
sum = IntStream.of(nums).parallel().sum();
System.out.println(Arrays.toString(nums) + " 各个元素的累加和为:" + sum);
}
}4.2.2、中间操作
多个中间操作可以连接起来形成一个流水线,除非流水 线上触发终止操作,否则中间操作不会执行任何的处理! 而在终止操作时一次性全部处理,称为“惰性求值” 。
- 当数据源中的数据上了流水线后,这个过程对数据进行的所有操作都称为“中间操作”;
- 中间操作仍然会返回一个流对象,因此多个中间操作可以串连起来形成一个流水线;
- stream 提供了多种类型的中间操作,如 filter、distinct、map、sorted 等等;
1、筛选与切片
| 方法 | 描述 |
|---|---|
| filter(Predicate p) | 接收 Lambda , 从流中排除某些元素。 |
| distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素 |
| limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
| skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个,则返回一个空流。与 limit(n) 互补 |
2、映射
| 方法 | 描述 |
|---|---|
| map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。 |
| mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream。 |
| mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream。 |
| mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream。 |
| flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流 |
3、排序
| 方法 | 描述 |
|---|---|
| sorted() | 产生一个新流,其中按自然顺序排序 |
| sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
Employee实体类
package com.ly.business;
public class Employee {
private int id;
private String name;
private int age;
private double salary;
private Status status;
public Employee() {
}
public Employee(String name) {
this.name = name;
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee(int id, String name, int age, double salary, Status status) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public int getId() {
return id;
}
public void setId(int 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;
}
public String show() {
return "测试方法引用!";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + id;
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 != 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 [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status
+ "]";
}
public enum Status {
FREE, BUSY, VOCATION;
}
}
test1
//2. 中间操作
List<Employee> emps = Arrays.asList(
new Employee(102, "李四", 59, 6666.66),
new Employee(101, "张三", 18, 9999.99),
new Employee(103, "王五", 28, 3333.33),
new Employee(104, "赵六", 8, 7777.77),
new Employee(104, "赵六", 8, 7777.77),
new Employee(104, "赵六", 8, 7777.77),
new Employee(105, "田七", 38, 5555.55)
);
/*
筛选与切片
filter——接收 Lambda , 从流中排除某些元素。
limit——截断流,使其元素不超过给定数量。
skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
*/
//内部迭代:迭代操作 Stream API 内部完成
@Test
public void test2(){
//所有的中间操作不会做任何的处理
Stream<Employee> stream = emps.stream()
.filter((e) -> {
System.out.println("测试中间操作");
return e.getAge() <= 35;
});
//只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
stream.forEach(System.out::println);
}
//外部迭代
@Test
public void test3(){
Iterator<Employee> it = emps.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
@Test
public void test4(){
emps.stream()
.filter((e) -> {
System.out.println("短路!"); // && ||
return e.getSalary() >= 5000;
}).limit(3)
.forEach(System.out::println);
}
@Test
public void test5(){
emps.parallelStream()
.filter((e) -> e.getSalary() >= 5000)
.skip(2)
.forEach(System.out::println);
}
@Test
public void test6(){
emps.stream()
.distinct()
.forEach(System.out::println);
}
test2:
package com.ly.business;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
* 一、 Stream 的操作步骤
*
* 1. 创建 Stream
*
* 2. 中间操作
*
* 3. 终止操作
*/
public class TestStreamAPI1 {
List<Employee> emps = Arrays.asList(
new Employee(102, "李四", 59, 6666.66),
new Employee(101, "张三", 18, 9999.99),
new Employee(103, "王五", 28, 3333.33),
new Employee(104, "赵六", 8, 7777.77),
new Employee(104, "赵六", 8, 7777.77),
new Employee(104, "赵六", 8, 7777.77),
new Employee(105, "田七", 38, 5555.55)
);
//2. 中间操作
/*
映射
map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
可以类比集合中的add和addAll的区别
*/
@Test
public void test1(){
Stream<String> str = emps.stream()
.map((e) -> e.getName());
str.forEach(System.out::println);
System.out.println("-------------------------------------------");
List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
Stream<String> stream = strList.stream()
.map(String::toUpperCase);
stream.forEach(System.out::println);
Stream<Stream<Character>> stream2 = strList.stream()
.map(TestStreamAPI1::filterCharacter);
stream2.forEach((sm) -> {
sm.forEach(System.out::println);
});
System.out.println("---------------------------------------------");
Stream<Character> stream3 = strList.stream()
.flatMap(TestStreamAPI1::filterCharacter);
stream3.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
/*
sorted()——自然排序
sorted(Comparator com)——定制排序
*/
@Test
public void test2(){
emps.stream()
.map(Employee::getName)
.sorted()
.forEach(System.out::println);
System.out.println("------------------------------------");
emps.stream()
.sorted((x, y) -> {
if(x.getAge() == y.getAge()){
return x.getName().compareTo(y.getName());
}else{
return Integer.compare(x.getAge(), y.getAge());
}
}).forEach(System.out::println);
}
}
test3:
package com.ly.business;
import com.ly.business.Employee.Status;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
/*
* 一、 Stream 的操作步骤
*
* 1. 创建 Stream
*
* 2. 中间操作
*
* 3. 终止操作
*/
public class TestStreamAPI2 {
List<Employee> 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)
);
//3. 终止操作
/*
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<Employee> op = emps.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());
System.out.println("--------------------------------");
Optional<Employee> 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<Double> op = emps.stream()
.map(Employee::getSalary)
.max(Double::compare);
System.out.println(op.get());
Optional<Employee> op2 = emps.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op2.get());
}
}
//注意:流进行了终止操作后,不能再次使用
@Test
public void test4(){
Stream<Employee> stream = emps.stream()
.filter((e) -> e.getStatus().equals(Status.FREE));
long count = stream.count();
System.out.println(count);
stream.map(Employee::getSalary)
.max(Double::compare);
}
4.3.3、终止操作
- 当所有的中间操作完成后,若要将数据从流水线上拿下来,则需要执行终端操作;
- stream 对于终端操作,可以直接提供一个中间操作的结果,或者将结果转换为特定的 collection、array、String 等;
test1
package com.ly.business;
import com.ly.business.Employee.Status;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
public class TestStreamAPI3 {
List<Employee> 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<Integer> 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<Double> op = emps.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
}
//需求:搜索名字中 “六” 出现的次数
@Test
public void test2(){
Optional<Integer> sum = emps.stream()
.map(Employee::getName)
.flatMap(TestStreamAPI1::filterCharacter)
.map((ch) -> {
if(ch.equals("六")){ return 1;
}
else
return 0;
}).reduce(Integer::sum);
System.out.println(sum.get());
}
//collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
@Test
public void test3(){
List<String> list = emps.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("----------------------------------");
Set<String> set = emps.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("----------------------------------");
HashSet<String> hs = emps.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));
hs.forEach(System.out::println);
}
@Test
public void test4(){
Optional<Double> max = emps.stream()
.map(Employee::getSalary)
.collect(Collectors.maxBy(Double::compare));
System.out.println(max.get());
Optional<Employee> op = emps.stream()
.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(op.get());
Double sum = emps.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
Double avg = emps.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
Long count = emps.stream()
.collect(Collectors.counting());
System.out.println(count);
System.out.println("--------------------------------------------");
DoubleSummaryStatistics dss = emps.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getMax());
}
//分组
@Test
public void test5(){
Map<Status, List<Employee>> map = emps.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
}
//多级分组
@Test
public void test6(){
Map<Status, Map<String, List<Employee>>> map = emps.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if(e.getAge() >= 60)
return "老年";
else if(e.getAge() >= 35)
return "中年";
else
return "成年";
})));
System.out.println(map);
}
//分区
@Test
public void test7(){
Map<Boolean, List<Employee>> map = emps.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));
System.out.println(map);
}
//
@Test
public void test8(){
String str = emps.stream()
.map(Employee::getName)
.collect(Collectors.joining("," , "----", "----"));
System.out.println(str);
}
@Test
public void test9(){
Optional<Double> sum = emps.stream()
.map(Employee::getSalary)
.collect(Collectors.reducing(Double::sum));
System.out.println(sum.get());
}
}
依次执行结果如下:
test1:
test2:

test3:

test4:

test5:

test6:

test7:

test8:

test9:

5、 接口中的默认方法与静态方法
6、 新时间日期API
7、 其他新特性

