Java8新特性

Java8新特性

Lambda表达式

(o1,o2) -> Integer.compare(o1,o2);

格式:

-> :lambda操作符 或 箭头操作符

->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)

->右边:lambda体 (其实就是重写的抽象方法的方法体)

->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略

->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字

Lambda表达式的本质:作为函数式接口的实例
如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。

所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

内置的4大核心函数式接口

消费型接口 Consumer void accept(T t)
供给型接口 Supplier T get()
函数型接口 Function<T,R> R apply(T t)
断定型接口 Predicate boolean test(T t)

例子:

    public List<String> filterString(List<String> list, Predicate<String> pre){

        ArrayList<String> filterList = new ArrayList<>();

        for(String s : list){
            if(pre.test(s)){
                filterList.add(s);
            }
        }

        return filterList;

    }

List<String> filterStrs1 = filterString(list,s -> s.contains("京"));

方法引用

  1. 使用情境:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

  2. 方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。

  3. 使用格式: 类(或对象) :: 方法名

  4. 具体分为如下的三种情况:

    情况1 对象 :: 非静态方法

    情况2 类 :: 静态方法

    情况3 类 :: 非静态方法

  5. 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(针对于情况1和情况2)

		Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
		System.out.println(com1.compare(12,21));

		System.out.println("*******************");

		Comparator<Integer> com2 = Integer::compare;
		System.out.println(com2.compare(12,3));

//情况三
		Employee employee = new Employee(1001, "Jerry", 23, 6000);


		Function<Employee,String> func1 = e -> e.getName();
		System.out.println(func1.apply(employee));

		System.out.println("*******************");


		Function<Employee,String> func2 = Employee::getName;
		System.out.println(func2.apply(employee));

构造器引用

和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。抽象方法的返回值类型即为构造器所属的类的类型

数组引用写法与构造器引用一致。

    //Supplier中的T get()
    //Employee的空参构造器:Employee()
    @Test
    public void test1(){

        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println("*******************");

        Supplier<Employee>  sup1 = () -> new Employee();
        System.out.println(sup1.get());

        System.out.println("*******************");

        Supplier<Employee>  sup2 = Employee :: new;
        System.out.println(sup2.get());
    }

	//Function中的R apply(T t)
    @Test
    public void test2(){
        Function<Integer,Employee> func1 = id -> new Employee(id);
        Employee employee = func1.apply(1001);
        System.out.println(employee);

        System.out.println("*******************");

        Function<Integer,Employee> func2 = Employee :: new;
        Employee employee1 = func2.apply(1002);
        System.out.println(employee1);

    }

	//BiFunction中的R apply(T t,U u)
    @Test
    public void test3(){
        BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);
        System.out.println(func1.apply(1001,"Tom"));

        System.out.println("*******************");

        BiFunction<Integer,String,Employee> func2 = Employee :: new;
        System.out.println(func2.apply(1002,"Tom"));

    }

//数组引用
    //Function中的R apply(T t)
    @Test
    public void test4(){
        Function<Integer,String[]> func1 = length -> new String[length];
        String[] arr1 = func1.apply(5);
        System.out.println(Arrays.toString(arr1));

        System.out.println("*******************");

        Function<Integer,String[]> func2 = String[] :: new;
        String[] arr2 = func2.apply(10);
        System.out.println(Arrays.toString(arr2));

    }

Stream流

Stream关注的是对数据的运算,与CPU打交道,集合关注的是数据的存储,与内存打交道

Stream 自己不会存储元素。

Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行

Stream 执行流程:

​ ① Stream的实例化

​ ② 一系列的中间操作(过滤、映射、...)

​ ③ 终止操作

说明:

​ 一个中间操作链,对数据源的数据进行处理

​ 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

实例化

通过集合:

default Stream stream() : 返回一个顺序流

default Stream parallelStream() : 返回一个并行流

通过数组:

        int[] arr = new int[]{1,2,3,4,5,6};
        //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
        IntStream stream = Arrays.stream(arr);

        Employee e1 = new Employee(1001,"Tom");
        Employee e2 = new Employee(1002,"Jerry");
        Employee[] arr1 = new Employee[]{e1,e2};
        Stream<Employee> stream1 = Arrays.stream(arr1);

通过Stream的of():

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);

创建无限流:

//      迭代
//      public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        //遍历前10个偶数
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);


//      生成
//      public static<T> Stream<T> generate(Supplier<T> s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);

中间操作

筛选与切片:

        List<Employee> list = EmployeeData.getEmployees();
//        filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
        Stream<Employee> stream = list.stream();
        //练习:查询员工表中薪资大于7000的员工信息
        stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);

        System.out.println();
//        limit(n)——截断流,使其元素不超过给定数量。
        list.stream().limit(3).forEach(System.out::println);
        System.out.println();

//        skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
        list.stream().skip(3).forEach(System.out::println);

        System.out.println();
//        distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

        list.add(new Employee(1010,"刘强东",40,8000));
        list.add(new Employee(1010,"刘强东",41,8000));
        list.add(new Employee(1010,"刘强东",40,8000));
        list.add(new Employee(1010,"刘强东",40,8000));
        list.add(new Employee(1010,"刘强东",40,8000));

        list.stream().distinct().forEach(System.out::println);

映射:

//        map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);

//        flatMap(Function f)——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out::println);

排序:

//        sorted()——自然排序        List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);        list.stream().sorted().forEach(System.out::println);//        sorted(Comparator com)——定制排序        List<Employee> employees = EmployeeData.getEmployees();        employees.stream().sorted( (e1,e2) -> {           int ageValue = Integer.compare(e1.getAge(),e2.getAge());           if(ageValue != 0){               return ageValue;           }else{               return -Double.compare(e1.getSalary(),e2.getSalary());           }        }).forEach(System.out::println);

终止操作

匹配与查找:

//        allMatch(Predicate p)——检查是否匹配所有元素。//          练习:是否所有的员工的年龄都大于18        boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);        System.out.println(allMatch);//        anyMatch(Predicate p)——检查是否至少匹配一个元素。//         练习:是否存在员工的工资大于 10000        boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000);        System.out.println(anyMatch);//        noneMatch(Predicate p)——检查是否没有匹配的元素。//          练习:是否存在员工姓“雷”        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));        System.out.println(noneMatch);//        findFirst——返回第一个元素        Optional<Employee> employee = employees.stream().findFirst();        System.out.println(employee);//        findAny——返回当前流中的任意元素        Optional<Employee> employee1 = employees.parallelStream().findAny();        System.out.println(employee1);        // count——返回流中元素的总个数        long count = employees.stream().filter(e -> e.getSalary() > 5000).count();        System.out.println(count);//        max(Comparator c)——返回流中最大值//        练习:返回最高的工资:        Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());        Optional<Double> maxSalary = salaryStream.max(Double::compare);        System.out.println(maxSalary);//        min(Comparator c)——返回流中最小值//        练习:返回最低工资的员工        Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));        System.out.println(employee);        System.out.println();//        forEach(Consumer c)——内部迭代        employees.stream().forEach(System.out::println);

归约:

//        reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
//        练习1:计算1-10的自然数的和
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);


//        reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
//        练习2:计算公司所有员工工资的总和
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
//        Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
        Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
        System.out.println(sumMoney.get());

收集:

//        collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
//        练习1:查找工资大于6000的员工,结果返回为一个List或Set

        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());

        employeeList.forEach(System.out::println);
        System.out.println();
        Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());

        employeeSet.forEach(System.out::println);

Optional类

为了在程序中避免出现空指针异常

Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):t可以为null

orElse(T t1):如果当前的Optional内部封装的t是非空的,则返回内部的t.如果内部的t是空的,则返回orElse()方法中的参数t1.

posted @ 2021-10-11 23:36  hugeBlair  阅读(40)  评论(0)    收藏  举报