二十、Java8新特性

引入

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

一、Lambda表达式

在这里插入图片描述

1.1 快速入门

// 案例引入
package com.gyh;

import java.util.Comparator;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class LambdaTest {
    public static void main(String[] args) {


        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("hsp");
            }
        };
        runnable.run();

        // Lambda表达式,与上面的功能一致
        Runnable runnable2 = () -> System.out.println("hsp");



        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        int compare = comparator.compare(1, 2);
        System.out.println(compare);

        // 有参的Lambda表达式
        Comparator<Integer> comparator2 = (o1, o2) -> Integer.compare(o1,o2);

        // 方法引用
        Comparator<Integer> comparator3 = Integer::compareTo;
    }
}

1.2 Lambda语法

在这里插入图片描述

在这里插入图片描述

package com.gyh;

import java.util.Comparator;
import java.util.function.Consumer;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class LambadaTest1 {
    /**
     * Lambda 表达式的使用
     * 1. 举例:(o1,o2) -> Integer.compare(o1,o2)
     * 2. 格式:
     *      -> : Lambda操作符 或 箭头操作符
     *      ->的左边:Lambda形参列表(其实就是接口中的抽象方法的形参列表)
     *      ->的右边:Lambda体(其实就是重写的抽象方法的方法体)
     * 3. Lambda表达式的使用(分为6中情况介绍)
     *      ->的左边:
     *          (1)lambda形参列表的参数类型可以省略;
     *          (2)如果Lambda形参列表只有一个参数,其一对()也可以省略
     *      ->的右边:
     *          (1)Lambda体应该使用一对{}包裹
     *          (2)如果Lambda体只有一条执行语句(可能是return语句),可以省略这一对{}和return
     *          
     *
     * 4. Lambda表达式的本质:作为函数式接口的实例
     */
    public static void main(String[] args) {

        // 语法格式一:无参,无返回值
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("hsp");
            }
        };
        // Lambda表达式替换
        Runnable runnable2 = () -> {
            System.out.println("hsp");
        };


        // 语法格式二:Lambda需要一个参数,但是没有返回值
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        // Lambda表达式替换
        Consumer<String> consumer2 = (String s) -> {
            System.out.println(s);
        };

        // 语法格式三:数据类型可以省略,因为可由编译器推断得出,称为 "类型推断"
        Consumer<String> consumer3 = (s) -> {
            System.out.println(s);
        };


        // 语法格式四:Lambda若只需要一个参数时,参数的小括号可以省略
        Consumer<String> consumer4 = s -> {
            System.out.println(s);
        };

        // 语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        // Lambda表达式替换
        Comparator<Integer> comparator1 = (x, y) -> {
            System.out.println("实现函数式接口方法!");
            return Integer.compare(x, y);
        };

        // 语法格式六:当 Lambda 体只有一条语句时,return与大括号若有,都可以省略
        Comparator<Integer> comparator2 = (x,y) -> Integer.compare(x, y);


    }

}

二、函数式(Functional)接口

2.1 函数式(Functional)接口介绍

在这里插入图片描述

在这里插入图片描述

2.2 Java内置函数式接口

在这里插入图片描述

在这里插入图片描述

package com.gyh;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class LambdaTest2 {
    /**
     * Java内置的4大核心函数式接口
     * 1. 消费型接口 Consumer<T> void accept(T t)
     * 2. 供给型接口 Supplier<T> T get()
     * 3. 函数型接口 Function<T,R> R apply(T t)
     * 4. 断定型接口 Predicate<T> boolean test(T t)
     *
     * @param args
     */
    public static void main(String[] args) {
        test();
    }

    public static void test() {
//        happyTime(100, m -> System.out.println(m));
        List<String> strings = Arrays.asList("北京", "东京", "西京", "南京", "天津");
        List<String> str = filterList(strings, s -> s.contains("京"));
        System.out.println(str);
    }

    public static void happyTime(double money, Consumer<Double> con) {
        con.accept(money);
    }

    private static List<String> filterList(List<String> str, Predicate<String> p) {
        ArrayList<String> newsStr = new ArrayList<>();
        for (String s : str) {
            if (p.test(s)) {
                newsStr.add(s);
            }
        }
        return newsStr;
    }
}

三、方法引用与构造器引用

3.1 方法引用

在这里插入图片描述

package com.gyh;

import java.util.Comparator;
import java.util.function.Consumer;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class LambdaTest3 {
    /**
     * 方法引用的使用
     * 1. 使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
     * <p>
     * 2. 方法引用,本质上就是 Lambda 表达式,而Lambda表达式作为函数式接口的实例。所以
     * 方法引用,也是函数式接口的实例。
     * <p>
     * 3. 使用格式: 类(对象):: 方法名
     * <p>
     * 4. 具体分为如下的三种情况:
     * 对象::非静态方法
     * 类::静态方法
     * 类::非静态方法
     *
     * 5. 方法引用使用的要求:要求接口中的抽象方法的参数列表和返回值类型与方法引用的方法的
     *    形参列表和返回值类型相同! (针对于 情况1 和 情况2)
     * @param args
     */
    public static void main(String[] args) {

    }

    /**
     * 情况一:  对象::实例方法
     * Consumer 中的void accept(T t)
     * PrintStream中的void println(T t)
     */
    public static void test1() {

        Consumer<String> con1 = str -> System.out.println(str);
        con1.accept("北京");
        // 方法引用
        Consumer<String> con2 = System.out::println;
    }

    /**
     * 情况二:  类::静态方法
     * Comparator 中的int compare(T t1,T t2)
     * Integer中的int compare(T t1,T t2)
     */
    public static void test2() {
        Comparator<Integer> com1 = (i1,i2) -> Integer.compare(i1,i2);
        Comparator<Integer> com2 = Integer::compareTo;
    }

    /**
     * 情况三:  类::实例方法
     * Comparator 中的int compare(T t1,T t2)
     * String 中的 int t1.compareTo(t2)
     */
    public static void test3() {
        Comparator<String> com1 = (i1,i2) -> i1.compareTo(i2);
        Comparator<String> com2 = String::compareTo;
    }
}

3.2 构造器引用

package com.gyh;

import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class LambdaTest4 {
    /**
     * 一、构造器引用
     * 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致
     * 抽象方法的返回值类型即为构造器所属的类的类型
     * <p>
     *
     * 二、数组引用
     * 大家可以把数组看做是一个特殊的类,则写法与构造器引用一致
     */
    // 空参构造器的引用
    public void test1() {
        Supplier<String> stringSupplier1 = new Supplier<String>() {
            @Override
            public String get() {
                return new String();
            }
        };
        // Lambda表达式
        Supplier<String> stringSupplier2 = () -> new String();
        // 构造器引用
        Supplier<String> stringSupplier3 = String::new;
    }

    // 有参构造器的引用(利用参数列表寻找对应的构造器)
    public void test2() {
        // lambda表达式
        Function<String, String> f1 = (name) -> new String(name);

        // 构造器引用
        Function<String, String> f2 = String::new;
    }

    // 数组引用
    // Function 中的 R apply(T t)
    public void test3() {
        // lambda表达式
        Function<Integer, String[]> f1 = (length) -> new String[length];

        // 构造器引用
        Function<Integer, String[]> f2 = String[]::new;
    }
}

四、强大的Stream API

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.1 创建 Stream 的4种方式

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.gyh;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class StreamAPITest {
    public static void main(String[] args) {
        /**
         * 1. stream关注的是对数据的运算,与CPU打交道
         *      集合关注的是数据的存储,与内存打交道
         * 2.
         * (1) Stream 自己不会存储元素
         * (2) Stream 不会改变源对象。相反,它们会返回一个持有结果的新Stream
         * (3) Stream 操作是延迟执行的。这意味着它们会等到需要结果的时候才执行
         *
         * 3. Stream 执行流程
         * (1) Stream实例化
         * (2) 一系列的中间操作
         * (3) 终止操作
         *
         * 4. 说明
         * 4.1 一个中间操作链,对数据源的数据进行处理
         * 4.2 一旦执行终止操作,就执行中间操作链,并产生结果,之后不会再被执行
         */

        // 创建 Stream 方式一:通过集合
        List<Employee> employees = EmployeeData.getEmployees();

        // default Stream<E> stream():返回一个顺序流
        Stream<Employee> stream = employees.stream();

        // default Stream<E> parallelStream():返回一个并行流
        Stream<Employee> employeeStream = employees.parallelStream();


        // 创建 Stream 方式二:通过数组
        int[] arr = {1, 2, 3, 4, 5, 6};
        IntStream stream1 = Arrays.stream(arr);

        Employee[] objects = (Employee[]) employees.toArray();
        Stream<Employee> stream2 = Arrays.stream(objects);


        // 创建 Stream 方式三:通过Stream的of()
        Stream<Employee> objects1 = Stream.of(objects);


        // 创建 Stream 方式四:创建无限流
        // 迭代  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);
    }
}

class EmployeeData {
    public static List<Employee> getEmployees() {
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(new Employee("马化腾", 34, 1001, 6000.38));
        employees.add(new Employee("马云", 12, 1002, 9876.12));
        employees.add(new Employee("刘强东", 33, 1003, 3000.82));
        employees.add(new Employee("雷军", 26, 1004, 7657.37));
        employees.add(new Employee("李彦宏", 65, 1005, 5555.32));
        employees.add(new Employee("比尔盖茨", 42, 1006, 9500.43));
        employees.add(new Employee("任正非", 26, 1007, 4333.32));
        employees.add(new Employee("扎克伯格", 35, 1008, 2500.32));

        return employees;
    }

}

class Employee {
    private String name;
    private int age;
    private int id;
    private double salary;

    public Employee(String name, int age, int id, double salary) {
        this.name = name;
        this.age = age;
        this.id = id;
        this.salary = salary;
    }

    @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 &&
                id == employee.id &&
                Double.compare(employee.salary, salary) == 0 &&
                Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, id, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                ", salary=" + salary +
                '}';
    }

    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 int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

4.2 Stream 的中间操作

4.2.1 筛选与切片

在这里插入图片描述

package com.gyh;

import java.util.List;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class StreamAPITest1 {
    public static void main(String[] args) {
        // filter(Predicate p) --- 接收 Lambda,从六中排除某些元素
        List<Employee> employees = EmployeeData.getEmployees();
        employees.stream()
                .filter(e -> e.getSalary() > 7000)
                .forEach(System.out::println);

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


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


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

    }
}

4.2.2 映射

在这里插入图片描述

package com.gyh;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class StreamAPITest2 {
    public static void main(String[] args) {
        // map(Function f) --- 接收一个函数作为参数,将元素转换成其他形式或提取信息,
        // 该函数会被应用到每个元素上,并将其映射成一个新的元素
        List<String> strings = Arrays.asList("aa", "bb", "cc", "dd");
        strings.stream()
                .map(String::toUpperCase)
                .forEach(System.out::println);


        // flatMap(Function f) --- 接收一个函数作为参数,将流中的每一个值都换成另一个流
        // 然后把所有流连接成一个流
        strings.stream()
                .map(StreamAPITest2::fromStringToStream)
                .forEach(s -> {
                    s.forEach(System.out::println);
                });

        strings.stream()
                .flatMap(StreamAPITest2::fromStringToStream)
                .forEach(System.out::println);


    }

    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> characters = new ArrayList<>();
        for (Character s : str.toCharArray()) {
            characters.add(s);
        }
        return characters.stream();
    }
}

4.2.3 排序

在这里插入图片描述

package com.gyh;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class StreamAPITest3 {
    public static void main(String[] args) {
//        sorted() --- 自然排序
        List<Integer> integers = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
        integers.stream().sorted().forEach(System.out::println);
        EmployeeData.getEmployees()
                .stream()
                .sorted(Comparator.comparingDouble(Employee::getSalary))
                .forEach(System.out::println);

//        sorted(Comparator com) --- 定制排序
    }
}

4.3 Stream 的终止操作

4.3.1 匹配与查找

在这里插入图片描述

在这里插入图片描述

package com.gyh;

import java.util.List;
import java.util.Optional;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class StreamAPITest4 {
    public static void main(String[] args) {
        // allMatch(Predicate p) --- 查找是否匹配所有元素
        List<Employee> employees = EmployeeData.getEmployees();

        // 是否所有的员工的年龄都大于18
        boolean b = employees.stream()
                .allMatch(e -> e.getAge() > 18);

        // anyMatch(Predicate p) --- 检测是否至少匹配一个元素
        // 是否有员工的工资大于一万
        boolean b1 = employees.stream()
                .anyMatch(e -> e.getSalary() > 10000);


        // noneMatch(Predicate p) --- 检测是否没有匹配所有元素
        boolean b2 = employees.stream()
                .noneMatch(e -> e.getName().contains("雷"));


        // findFirst() --- 返回第一个元素
        Optional<Employee> first = employees.stream()
                .findFirst();

        // findAny() --- 返回当前流中的任意元素
        Optional<Employee> any = employees.stream()
                .findAny();


        // count --- 返回流中的元素的总个数
        long count = employees.stream().filter(e -> e.getAge() > 12).count();

        // max(Comparator c) --- 返回流中的最大值
        // 返回最高的工资
        Optional<Employee> max = employees.stream()
                .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));

        // min(Comparator c) --- 返回流中的最小值
        // 返回最低工资的员工
        Optional<Employee> min = employees.stream()
                .min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));

        // forEach(Consumer c) --- 内部迭代
        employees.stream().forEach(System.out::println);
        // 使用集合的遍历操作
        employees.forEach(System.out::println);

    }
}

4.3.2 归约

在这里插入图片描述

package com.gyh;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class StringAPITest5 {
    public static void main(String[] args) {
        // identity作为初始值
        // reduce(T identity,BinaryOperator) --- 可以将流中元素反复结合起来,得到一个值。返回 T
        // 计算1-10的自然数的和
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer reduce = list.stream().reduce(0, Integer::sum);


        // reduce(BinaryOperator b) --- 可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
        // 计算公司所有员工工资的总和
        List<Employee> employees = EmployeeData.getEmployees();
        Optional<Double> reduce1 = employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);


    }
}

4.3.3 收集

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.gyh;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class StreamAPITest6 {
    public static void main(String[] args) {
        // collect(Collector c) --- 将流转换为其他形式。接收一个 Collector 接口的实现
        // 练习1:查找工资大于6000的员工,结果返回一个List或Set
        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> collect = employees.stream()
                .filter(e -> e.getSalary() > 6000)
                .collect(Collectors.toList());

        collect.forEach(System.out::println);
    }


}

五、Optional类

在这里插入图片描述

在这里插入图片描述

package com.gyh;

import java.util.Optional;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class StreamAPITest7 {
    public static void main(String[] args) {
        Employee employee = new Employee("aa", 12, 1001, 9000);
        // Optional.of(T t):创建一个Optional 实例,t必须非空
        // of(T t):保证 t 是非空的
        Optional<Employee> employee1 = Optional.of(employee);


        // Optional.empty(): 创建一个空的 Optional 实例
        Optional<Object> empty = Optional.empty();
        // Optional.ofNullable(T t): t可以为null
        Optional<Employee> employee2 = Optional.ofNullable(employee);
    }
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ModelBulider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值