JAVA8新特性

JDK8特点:

  • 速度更快
  • 代码更少(增加了新的语法 Lambda 表达式)
  • 强大的 Stream API
  • 便于并行
  • 最大化减少空指针异常 Optional

1. Lambda 表达式

1.1 背景

给定一个集合,需要对其进行相关操作,如下:

List<Employee> emps = Arrays.asList(
			new Employee(101, "张三", 18, 9999.99),//id name age salary
			new Employee(102, "李四", 59, 6666.66),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);

两个需求,如下:
1需求:获取公司中年龄小于 35 的员工信息
2需求:获取公司中工资大于 5000 的员工信息

1.2 传统方式

为每一个功能创造一个方法

	@Test
	public void test3(){
		List<Employee> list = filterEmployeeAge(emps);
		List<Employee> list2 = filterEmployeeSalary(emps);

		for (Employee employee : list) {
			System.out.println(employee);
		}
		System.out.println("***********************");
		for (Employee employee : list2) {
			System.out.println(employee);
		}
	}
	//需求:获取公司中年龄小于 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;
	}

上面方法存在大量重复代码,关键代码只有一行,而且灵活度不高,若再有一个需求过来,则需要改动原来代码地方

1.3 优化方式一: 策略模式

减少繁杂冗余的方法,只需要创建一个类按照接口实现方法功能即可
增加一个接口

public interface MyPredicate<T> {
	public boolean test(T t);//里面存放各个子类实现
}

实现类

public class FilterEmployeeForAge implements MyPredicate<Employee>{
	@Override
	public boolean test(Employee t) {
		return t.getAge() <= 35;//关键代码放此处
	}
}

调用类

	@Test
	public void test4(){
		//想用哪个就在这里添加实现类调用即可,不用大范围修改源文件代码
		List<Employee> list = filterEmployee(emps, new FilterEmployeeForAge());
		//List<Employee> list2 = filterEmployee(emps, new FilterEmployeeForSalary());
		for (Employee employee : list) {
			System.out.println(employee);
		}
	}
	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;
	}

1.4 优化方式二:匿名内部类

上面策略设计,有些不足的是,要实现一个功能,每次都要创建一个实现类来实现接口,然后进行调用,还是比较麻烦,于是用匿名内部类的话,就可以省去创建相关的实现类

@Test
	public void test5(){
		List<Employee> list = filterEmployee(emps, new MyPredicate<Employee>() {
			@Override
			public boolean test(Employee t) {
				return e.getAge() <= 35;
			}
		});
		
		for (Employee employee : list) {
			System.out.println(employee);
		}
	}

1.5 优化方式三:lambda

上面虽然用了匿名内部类,但是整个代码里就只有e.getAge() <= 35有用,其他都是多余的代码,代码冗余且影响阅读,不够简洁

List<Employee> list = filterEmployee(emps, (e) -> e.getAge() <= 35);
		list.forEach(System.out::println);
		
//虽然用了lambda,但是该写的方法还得写,实参传递过去的,是接口需要实现的逻辑而已,lambda必须要有接口载体才能用!!!
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;
}

1.6 优化方式四:stream

假若上面都没有相关实现类代码,就纯粹只有一个集合,那么我们就可以采用流的操作来操作集合或数组

public void test7(){
		emps.stream()
			.filter((e) -> e.getAge() <= 35)
			.forEach(System.out::println);
			}

1.7 lambda基础语法

Java8中引入了一个新的操作符 “->” 该操作符称为箭头操作符或 Lambda 操作符,箭头操作符将 Lambda 表达式拆分成两部分:

  • 左侧:Lambda 表达式的参数列表
  • 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
  • lambda就两条,一是要把表达式找一个接口类接受,二是通过接口类方法调用来触发方法体的使用
Runnable r1 = () -> System.out.println("Hello Lambda!");
  • 1.正如上面代码,r1之所有能接收右边()->这种形式,说明这个Runnable类里有一个正好符合右边格式的方法
  • 2.()->右边这种形式,实际上又可以看成隐式生成了一个内部类(虽然实际上没有产生class内部类文件),并实现了相关方法,然后把这个内部类的实例传递给左边的接口接收

1.7.1 语法格式一:无参数,无返回值

() -> System.out.println("Hello Lambda!");

在这里插入图片描述

	其实用Runnable能够接收,主要看这个类里的接口方法,若右边的符合,则可以直接用来接受
其实,右边就是一个方法的实现体

    public void test(){
        int num = 0;//jdk 1.7 前,必须是 final
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World!" + num);
            }
        };
        r.run();

        System.out.println("-------------------------------");
		//():表示run()的参数列表
		//System.out.println("Hello Lambda!"):表示run()的方法实现
        Runnable r1 = () -> System.out.println("Hello Lambda!");
        r1.run();
    }

1.7.2 语法格式二:有一个参数,并且无返回值

1.7.3 语法格式三:若只有一个参数,小括号可以省略不写

(x) -> System.out.println(x)
在这里插入图片描述

public void test(){
		//x:表示accept中的参数t
        Consumer<String> con = (x) -> System.out.println(x);
        Consumer<String> con = x -> System.out.println(x);//小括号省略
        con.accept("你好,福欧罗!");
    }

1.7.4 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句

在这里插入图片描述

	public void test(){
		Comparator<Integer> com = (x, y) -> {
			System.out.println("函数式接口");
			return Integer.compare(x, y);
		};
	}

1.7.5 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写

	若不知道方法体是否该返回值,可以直接去接受者类里去找方法看一下
	public void test(){
		//Integer.compare(x, y):省略了上面的大括号和return
		Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
	}

1.7.6 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”

public void test(){
		Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
		//x,y类型可根据Comparator<Integer>中<>里的类型推断出来,即可省略x,y前面的类型
		Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
	}

举例:对一个数进行运算

1.定义一个函数式接口
@FunctionalInterface
public interface MyFun {
	//有类型Integer,则表示该方法需要返回值
    public Integer getValue(Integer value);
}
2.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);
    }

1.8 Lambda作用域

  • 1.lambda表达式中可以访问外部局部变量,但只有只读权限,一般能访问的局部变量其实都是final的
  • 2.实例变量和静态变量具有读写权限,这是因为在当前类中,方法可以修改类的实例变量和静态变量
public class Myclass {

    int a;
    static int m = 0;

    @Test
    public void test1() {

        int b = 2;

        Consumer c = (e) -> {
            a = 2;
            m = 5;
            System.out.println("e = " + e);
            //这里会报错,这是局部变量b应该是final,而b后面又被赋值
            System.out.println("b = " + b);
            System.out.println("a = " + a);
            System.out.println("m = " + m);
        };
        //赋值
        b = 3;

        c.accept("lll");

    }

}

2. 函数式接口

2.1 特点

Java中的lambda无法单独出现,它需要一个函数式接口来盛放,lambda表达式方法体其实就是函数接口的实现.

只包含一个抽象方法的接口,称为函数式接口

你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)

我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口

2.2 默认方法

public interface MyInterface {
    
    double calculate(int a);
    //默认方法
    default double sqrt(int a){
        return Math.sqrt(a);
    }
}

1.上面接口除了抽象方法外,还实现了一个默认方法sqrt,默认方法可以直接使用

2.3 内置的四大核心函数式接口

2.3.1 Consumer : 消费型接口

消费者,就是你给我参数,我把参数消费掉,而且还不返回
在这里插入图片描述

	@Test
	public void test(){
		happy(100, (m) -> System.out.println("上网消费:" + m + "元"));
	} 
	public void happy(double money, Consumer<Double> con){
		con.accept(money);
	}

andThen
谁在前面谁先执行

    @Test
    public void test2(){

        myPrint("aaa",(e) -> {
            System.out.println("c1 e = " + e);
        },(e) -> {
            System.out.println("c2 e = " + e);
        });

    }

    public void myPrint(String s, Consumer<String> c1,Consumer<String> c2){
    	//c2在前面,先执行c2,然后再执行c1
        c2.andThen(c1).accept(s);
    }

在这里插入图片描述

2.3.2 Supplier : 供给型接口

供给者,就是不接受任何参数,但是可以生产一个东西给你
在这里插入图片描述

	public void test(){
		//产生10个随机数
		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++) {
			//当执行sup.get()时,就执行上面Math.random() * 100)的代码实现
			Integer n = sup.get();
			list.add(n);
		}
		return list;
	}

2.3.3 Function<T, R> : 函数型接口

函数,就是你给一个参数给我,我给你变一个值给你
在这里插入图片描述

	public void test(){
		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);
	}

2.3.4 Predicate : 断言型接口

断言,就是你给我一个参数,我判断了真假后返回一个结果给你
在这里插入图片描述

	public void test(){
		List<String> list = Arrays.asList("Hello", "Demaxiya", "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;
	}

2.3.5 其他函数式接口

BiFunction<T, U, R>R apply(T t, U u)
UnaryOperator< T>T apply(T t)
BinaryOperator< T>T apply(T t1, T t2)
BiConsumer<T, U>void accept(T t, U u)
ToIntFunction< T>
IntFunction< R>

3. 方法引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
其实就是lambda复用其他函数功能,形式为 调用者::调用者的方法,即用::替换.

class MySort{
    static int myComparator(Integer a,Integer b){
        return a.compareTo(b);
    }
}

当要排序的时候,正好有一个个类MySort里面实现了一个比较方法,而Arrays排序里第二个参数正好需要一个比较方法,那么我们就可以直接用现成类已实现的方法来调用,如下:

    public void test2(){
        int[] scores = new int[] { 78, 45, 85, 97, 87 };
        //调用现成方法
        Arrays.sort(scores,MySort::myComparator);
    }

3.1 对象的引用 :: 实例方法名

在这里插入图片描述
在这里插入图片描述

	public void test(){
		//1.Consumer的lambda形式
		PrintStream ps = System.out;
		Consumer<String> con = (str) -> ps.println(str);
		con.accept("Hello World!");
		
		System.out.println("--------------------------------");
		//2.Consumer的对象的引用 :: 实例方法名,替换lambda方式
		//注意:只有Consumer中的方法accept和ps中的方法println
		//在方法参数类型和返回值都一样时才能这样用
		Consumer<String> con2 = ps::println;
		con2.accept("Hello Java8!");//accept直接引用println的实现
		//3.实例:实例方法名
		Consumer<String> con3 = System.out::println;
	}

3.2 类名 :: 静态方法名

	public void test(){
		Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
		
		System.out.println("-------------------------------------");
		//Comparator和Interger里的方法(x,y)
		Comparator<Integer> com2 = Integer::compare;
	}

3.3 类名 :: 实例方法名

在这里插入图片描述

	public void test(){
		BiPredicate<String, String> bp = (x, y) -> x.equals(y);
		System.out.println(bp.test("abcde", "abcde"));
		System.out.println("-----------------------------------------");
		//若x是方法(如:equals)调用者,y是方法的形成,则可用类::实例方法形式
		BiPredicate<String, String> bp2 = String::equals;
		System.out.println(bp2.test("abc", "abc"));
	}

注意:

  • ①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
  • ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName

3.4 构造器引(类名 :: new)

	public void test(){
		//1.lambda形式
		Supplier<Employee> sup = () -> new Employee();
		System.out.println(sup.get());		
		System.out.println("------------------------------------");
		//2.构造器引用
		//因为Supplier接口里的方法是无参的,所以new调用的是无参构造器
		Supplier<Employee> sup2 = Employee::new;
		System.out.println(sup2.get());
		System.out.println("------------------------------------");
		//3.构造器引用
		//因为Function里有一个参数,所以new调用有一个参数的构造器
		Function<String, Employee> fun = Employee::new;
		//BigFunction同理
		BiFunction<String, Integer, Employee> fun2 = Employee::new;

	}

注意:
构造器的参数列表,需要与函数式接口中参数列表保持一致

3.5 数组引用(类型[] :: new)

	public void test(){
		//创建数组长度为10
		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

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)。
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

流(Stream)
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算! ”

注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

三个步骤

  • 创建 Stream
    一个数据源(如: 集合、数组), 获取一个流
  • 中间操作
    一个中间操作链,对数据源的数据进行处理
  • 终止操作(终端操作)
    一个终止操作,执行中间操作链,并产生结果
    在这里插入图片描述
    集合或数组里的元素,一般都是stream里面的方法实现体的参数,比如toUpperCase
    需要接受字符串,变成大写,就是这样List strList = Arrays.asList(“aaa”, “bbb”, “ccc”, “ddd”, “eee”);
    map说白了,就是根据fuction执行后把原来元素变成fuction执行后的元素,供后续操作用

JAVA8 Stream接口流式方法 map操作 filter操作以及flatMap操作
总结:其实filter是过滤元素,返回的还是这个元素,而map是可以过滤后返回lambda表达式给出的另外数据类型

        List<String> collect3 = emps.stream().map(Employee::getName).collect(Collectors.toList());
        collect3.forEach(System.out::println);

Java8新特性Stream之list转map及问题解决
tomap基本上都是用在tream()后的collect里的,我看其他用法基本上都是这样

        Map<Integer, String> collect4 = emps.stream().collect(Collectors.toMap(Employee::getId, Employee::getName));
        Set<Map.Entry<Integer, String>> entries = collect4.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            System.out.println(entry.getKey()+"*"+entry.getValue());
        }

4.1 创建流方式

.Java8 中的 Collection 接口被扩展,提供了
两个获取流的方法:
	default Stream<E> stream() : 返回一个顺序流
	default Stream<E> parallelStream() : 返回一个并行流

二.由数组创建流
Java8 中的 Arrays 的静态方法 stream() 可
以获取数组流:
 	 static <T> Stream<T> stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:
	 public static IntStream stream(int[] array)
 	 public static LongStream stream(long[] array)
	 public static DoubleStream stream(double[] array).由值创建流
可以使用静态方法 Stream.of(), 通过显示值
创建一个流。它可以接收任意数量的参数。
	public static<T> Stream<T> of(T... values) : 返回一个流

四.由函数创建流:创建无限流
可以使用静态方法 Stream.iterate() 和
Stream.generate(), 创建无限流
迭代
	public static<T> Stream<T> iterate(final T seed, final
UnaryOperator<T> f)
生成
	public static<T> Stream<T> generate(Supplier<T> s) :


	public void test(){
		//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 中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”

4.2.1 筛选与切片

filter(Predicate p) 接收 Lambda , 从流中排除某些元素。
distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去
除重复元素
limit(long maxSize) 截断流,使其元素不超过给定数量。
skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素
不足 n 个,则返回一个空流。与 limit(n) 互补

	public void test(){
		Stream<Employee> empstream = emps.stream()
				.filter((e) -> e.getAge() > 35);
		//empstream.forEach(System.out::println);这里不能用System.out.println
		empstream.forEach(System.out::println);

	}

4.2.2 映射

map(Function f)
接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
mapToDouble(ToDoubleFunction f)
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
mapToInt(ToIntFunction f)
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
mapToLong(ToLongFunction f)
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
flatMap(Function f)
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

	public void test(){
		Stream<String> str = emps.stream()
			.map((e) -> e.getName());
		
		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);
	}

4.2.3 排序

sorted() 产生一个新流,其中按自然顺序排序
sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序

	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);
	}

4.3 终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的
值,例如: List、 Integer,甚至是 void

4.3.1 查找与匹配

allMatch(Predicate p) 检查是否匹配所有元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
count() 返回流中元素总数
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭
代,称为外部迭代。相反, Stream API 使用内部
迭代——它帮你把迭代做了)

public class Employee {

	private int id;
	private String name;
	private int age;
	private double salary;
	private Status status;
	
	public enum Status {
		FREE, BUSY, VOCATION;
	}
}


	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)
	);
	@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();
		
		stream.map(Employee::getSalary)
			.max(Double::compare);//会报错
	}

4.3.2 规约

reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。
返回 T
归约
reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。
返回 Optional
备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它
来进行网络搜索而出名。

	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());
	}

4.3.3 收集

collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的
实现,用于给Stream中元素做汇总的方法
Collector 接口中方法的实现决定了如何对流执行收集操作(如收
集到 List、 Set、 Map)。但是 Collectors 实用类提供了很多静态
方法,可以方便地创建常见收集器实例
在这里插入图片描述
在这里插入图片描述

	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);
	}

5. Optional

在这里插入图片描述

    @Test
    public void test3(){

        Optional<Person> person = Optional.of(new Person());
        System.out.println("person = " + person.get());
		//若为空,则返回另外一个值
        Optional<Object> o = Optional.ofNullable(null);
        System.out.println("o = " + o.orElse(new Person()));

    }

在这里插入图片描述

6. 新时间日期 API

在这里插入图片描述

在这里插入图片描述

7. 参考

参考
探索Java8:(二)Function接口的使用
参考
Java8新特性学习-函数式编程(Stream/Function/Optional/Consumer)
Java8函数式编程-包教包会系列(十)

Github1
Github2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值