十六章:Java8的其它新特性

目录

16.1:Lambda表达式

16.2:函数式(Function)接口

16.3:方法引用和构造器引用

16.4:强大的Stream API

                ①Stream实例化

                ②Stream的中间操作

                ③终止操作

16.5:Option类


16.1:Lambda表达式

package com.jiayifeng.java;

import org.junit.Test;

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

/**
 * author 爱编程的小贾
 * create 2023-10-19 12:29
 *
 * 一:Lambda表达式的使用
 *      1.举例:(o1,o2) -> Integer.compare(o1,o2);
 *      2.格式:
 *          "->":Lambda操作符或箭头操作符
 *          "->"左边:Lambda形参列表(也就是接口中的抽象方法的形参列表)
 *          "->"左边:Lambda体(也就是重写的抽象方法的方法体)
 *
 *      3.Lambda表达式的使用:(六种情况)
 *
 *      4.Lambda表达式的本质:作为函数式接口的实例
 *          如果一个接口中只声明了一个抽象方法,则此接口就称之为函数式接口。
 *          我们可以在一个接口上使用@FunctionalInterface注解,这样可以检验它
 *          是否是一个函数式接口
 *
 *
 *      5.总结
 *          "->"左边:Lambda形参列表的参数类型可以省略(类型推断);
 *              如果Lambda形参列表只有一个参数,其一对()也可以省略
 *          "->"右边:Lambda体应使用一对{}包裹;
 *              如果Lambda体只有一条执行语句(也可能是return语句),可以省略这一对{}和return关键字
 *
 */
public class Lambda {
    @Test
    public void test1(){
        Runnable r1 = new Runnable(){
            @Override
            public void run() {
                System.out.println("我爱北京天安门!");
            }
        };
        r1.run();
        System.out.println("************");

//        Lambda表达式的写法
        Runnable r2 = () -> System.out.println("我爱北京故宫!");
        r2.run();
        System.out.println("************");

//        方法引用
        Comparator com3 = Integer::compare;
        int compare = com3.compare(32, 21);
        System.out.println(compare);
    }

//  语法格式一:无参、无返回值
    @Test
    public void test2(){
        Runnable r1 = new Runnable(){
            @Override
            public void run() {
                System.out.println("我爱北京天安门!");
            }
        };
        r1.run();
        System.out.println("************");

//        Lambda表达式的写法
        Runnable r2 = () -> {
            System.out.println("我爱北京故宫!");
        };
        r2.run();
    }

//    语法格式二:Lambda需要一个参数,但是没有返回值
    @Test
    public void test3(){
        Consumer con = new Consumer() {

            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("谎言和誓言的区别是什么?");
        System.out.println("**************");

        Consumer con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("一个是听的人当真了,一个是说的人当真了");
    }

//    语法格式三:数据类型可以省略,因为可由编译推断得出,称为“类型推断”
    @Test
    public void test4(){
        Consumer con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("一个是听的人当真了,一个是说的人当真了");
        System.out.println("******************");

        Consumer con2 = (s) -> {
            System.out.println(s);
        };
        con1.accept("一个是听的人当真了,一个是说的人当真了!");
    }

//    语法格式四:Lambda若只需要一个参数时,参数的小括号可以省略
    @Test
    public void test5(){
        Consumer con1 = s -> {
            System.out.println(s);
        };
        con1.accept("一个是听的人当真了,一个是说的人当真了");
    }

//    语法格式五:Lambda需要两个或两个以上的参数,多条执行语句,并且可以有返回值
    @Test
    public void test6() {
        Comparator com1 = new Comparator() {

            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare(12,21));
        System.out.println("**************");

        Comparator com2 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(com2.compare(12,6));
    }

//    语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
    @Test
    public void test7(){
        Comparator com1 = (o1, o2) -> {
            return o1.compareTo(o2);
        };
        System.out.println(com1.compare(12,6));
        System.out.println("***********");

        Comparator com2 = (o1, o2) -> o1.compareTo(o2);
        System.out.println(com1.compare(12,9));
    }
}

16.2:函数式(Function)接口

Java内置四大核心函数式接口
函数式接口 参数类型 返回类型 用途
Consumer消费型接口 T void 对类型为T的对象应用操作,包含方法:void accept(T t)
Supplier供给型接口 T 返回类型为T的对象,包含方法:T get()
Function函数型接口 T R 对类型为T的对象应用操作,并返回结果,结果是R类型的对象。包含方法:R apply(T t)
Predicate断定型接口 T boolean 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:boolean test(T t)
package com.jiayifeng.java;

import org.junit.Test;

import java.util.function.Consumer;

/**
 * author 爱编程的小贾
 * create 2023-10-19 16:51
 *
 * 一:Java内置的四大核心函数式接口
 */
public class LambdaTest1 {
    @Test
    public void test1(){
        happyTime(500, new Consumer() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("学习太累了,去超市买瓶水,价格为:" + aDouble);
            }
        });
        System.out.println("**************");

        happyTime(400,money -> System.out.println("学习太累了,去超市喝了瓶水,价格为:" + money));
    }

    public void happyTime(double money, Consumer con){
        con.accept(money);
    }
}

16.3:方法引用和构造器引用

package com.jiayifeng.java;

import org.junit.Test;

import java.io.PrintStream;
import java.util.function.Consumer;

/**
 * author 爱编程的小贾
 * create 2023-10-19 17:10
 *
 * 一:方法引用和构造器引用
 *      1.使用情景:当要传递给Lambda体的操作已经有实现的方法了,可以使用方法引用
 *      2.方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。
 *      所以方法引用,也是函数式接口的实例
 *      3.使用格式:类(或对象) :: 方法名
 *      4.具体分为如下的三种情况:
 *          对象 :: 非静态方法
 *          类 :: 静态方法
 *          类 :: 非静态方法
 *      5.方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与
 *        方法引用的方法的形参列表和返回值类型相同(针对于前两种情况)
 */
public class MethodRefTest {
    @Test
    public void test1(){
//        情况一:对象 :: 实例方法
//        Consumer中的void accept(T t)
//        PrintStream中的void Println(T t)
        Consumer con1 = str -> System.out.println(str);
        con1.accept("北京");
        System.out.println("**********");

        PrintStream ps = System.out;
        Consumer con2 = ps :: println;
        con2.accept("beijing");
    }
}

构造器引用:

        和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致

数组引用:

        可以将数组看做是一个特殊的类,写法与构造器引用一致

16.4:强大的Stream API

        使用Stream API对数据集合进行操作,就类似于使用SQL执行的数据库查询

        简言之:Stream API提供了一种高效且易于使用的处理数据的方式

        定义:Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列

                “集合讲的是数据,Stream讲的是计算”

        注意:

                ①Stream自己不会存储数据

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

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

        执行流程:

                ①Stream实例化
package com.jiayifeng.java;

/**
 * author 爱编程的小贾
 * create 2023-10-19 19:34
 */
public class Employee {

    private int id;
    private String name;
    private int age;
    private double salary;


    public Employee(int id) {
        this.id = id;
    }


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

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Employee)) return false;

        Employee employee = (Employee) o;

        if (getId() != employee.getId()) return false;
        if (getAge() != employee.getAge()) return false;
        if (Double.compare(employee.getSalary(), getSalary()) != 0) return false;
        return getName() != null ? getName().equals(employee.getName()) : employee.getName() == null;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = getId();
        result = 31 * result + (getName() != null ? getName().hashCode() : 0);
        result = 31 * result + getAge();
        temp = Double.doubleToLongBits(getSalary());
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

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

    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 Employee() {
    }

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

import java.util.ArrayList;
import java.util.List;

/**
 * author 爱编程的小贾
 * create 2023-10-19 19:35
 */
public class EmployeeData {
    public static List getEmp() {

        List list = new ArrayList<>();
        list.add(new Employee(1001, "马化腾", 34, 6000.38));
        list.add(new Employee(1002, "马云", 12, 9876.12));
        list.add(new Employee(1003, "刘强东", 33, 3000.82));
        list.add(new Employee(1004, "雷军", 26, 7657.37));
        list.add(new Employee(1005, "李彦宏", 65, 5555.21));
        list.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
        list.add(new Employee(1006, "任正非", 26, 4333.32));
        list.add(new Employee(1006, "扎克伯格", 35, 2500.32));
        return list;
    }
}
package com.jiayifeng.java;

import org.junit.Test;

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

/**
 * author 爱编程的小贾
 * create 2023-10-19 19:26
 *
 * 一:Stream API
 *      1.Stream关注的是对数据的运算,与CPU打交道
 *        集合关注的是数据的存储,与内存打交道
 *
 *      2.Stream执行流程
 *          ①Stream实例化
 *          ②一系列的中间操作(过滤、映射等)
 *          ③终止操作
 *
 *      3.说明
 *          ①一个中间操作链,对数据源的数据进行处理
 *          ②一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被调用
 *
 */
public class StreamAPI {
    /**
     * 创建Stream方式1:通过集合List
     */
    @Test
    public void test1() {

        List emp = EmployeeData.getEmp();
        //通过集合来创建
        //顺序流
        Stream stream = emp.stream();
        //并行流
        Stream employeeStream = emp.parallelStream();
    }

    /**
     * 创建Stream方式2:通过数组
     */
    @Test
    public void test2() {
        int arr[] = new int[]{1, 2, 3, 4, 5, 6};
        //调用Arrays.stream返回数组
        IntStream stream = Arrays.stream(arr);

        Employee e1 = new Employee(1, "1", 1, 1);
        Employee e2 = new Employee(2, "1", 1, 1);

        Employee employees[] = new Employee[]{e1, e2};
        Stream stream1 = Arrays.stream(employees);
    }


    /**
     * 创建Stream方式3: 通过Stream的of()来创建
     */
    @Test
    public void test3() {
        Stream integerStream = Stream.of(1, 2, 3, 4, 5, 6);
        Stream stream = Stream.of(1.0, 2, 3, 4, 5, 6);
    }

    /**
     * 创建Stream方式4:创建无限流
     */
    @Test
    public void test4() {
        //迭代
        //遍历前10个偶数
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
        //生成
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }
}
                ②Stream的中间操作
package com.jiayifeng.java;

import org.junit.Test;

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

/**
 * author 爱编程的小贾
 * create 2023-10-19 19:46
 *
 * 一:测试Stream的中间操作
 */
public class StreamAPITest1 {
//    1.筛选与切片
    @Test
    public void test1(){
        List list = EmployeeData.getEmp();
//        filter(Predicate p):接收Lambda,从流中欧排除某些元素
        Stream 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个,则返回一个空流
        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,"刘强东",40,8000));
        list.add(new Employee(1010,"刘强东",40,8000));
        list.add(new Employee(1010,"刘强东",40,8000));
        list.add(new Employee(1010,"刘强东",40,8000));
//        System.out.println(list);

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

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

//        flatMap(Function f):接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有
//        流连接成一个流
        ArrayList list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);

        ArrayList list2 = new ArrayList();
        list2.add(4);
        list2.add(5);
        list2.add(6);

        list1.addAll(list2);
        System.out.println(list1);
    }

//    3.排序
    @Test
    public void test3(){
//       sort():自然排序
        List list = Arrays.asList(12, 45, 24, 46, 67, 98);
        list.stream().sorted().forEach(System.out :: println);

//        抛异常,原因:Employee没有实现Comparable接口
//        List emp = EmployeeData.getEmp();
//        emp.stream().sorted().forEach(System.out :: println);

//       sorted(Compatater com):定制排序
        List emp = EmployeeData.getEmp();
        emp.stream().sorted((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge()))
            .forEach(System.out :: println);

    }
}
                ③终止操作
package com.jiayifeng.java1;

/**
 * author 爱编程的小贾
 * create 2023-10-21 11:49
 */

public class Student {
    private int id;//id
    private String name;//姓名
    private int age;//年龄
    private Score score;//成绩(优秀、良好、及格)

    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 Score getScore() {
        return score;
    }

    public void setScore(Score score) {
        this.score = score;
    }

    public enum Score{
        EXCELLENT,
        GOOD,
        PASS
    }

    public Student(int id, String name, int age, Score score) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
    }
}
package com.jiayifeng.java1;

/**
 * author 爱编程的小贾
 * create 2023-10-21 11:50
 */
import com.jiayifeng.java.Employee;
import com.jiayifeng.java.EmployeeData;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @description: 终止操作
 *                  allMatch——检查是否匹配所有元素
 *                  anyMatch——检查是否至少匹配一个元素
 * 		            noneMatch——检查是否没有匹配的元素
 * 		            findFirst——返回第一个元素
 * 		            findAny——返回当前流中的任意元素
 * 		            count——返回流中元素的总个数
 * 		            max——返回流中最大值
 * 		            min——返回流中最小值
 * @author: xz
 */
public class StreamTest {
    public static void main(String[] args) {
        List studentsList = Arrays.asList(
                new Student(1, "李四", 20,Student.Score.EXCELLENT),
                new Student(2, "张三", 19,Student.Score.GOOD ),
                new Student(3, "王五", 24,Student.Score.PASS),
                new Student(4, "赵六", 23, Student.Score.GOOD),
                new Student(5, "xz", 21, Student.Score.PASS )
        );

        //检查学生的成绩是都是良好
        boolean b = studentsList.stream()
                .allMatch(s -> s.getScore().equals(Student.Score.GOOD));
        System.out.println("allMatch——"+b);

        //检查学生的成绩至少有一个是良好
        boolean b1 = studentsList.stream()
                .anyMatch(s -> s.getScore().equals(Student.Score.GOOD));
        System.out.println("anyMatch——"+b1);

        //检查学生的成绩是否没有匹配到良好
        boolean b2 = studentsList.stream()
                .noneMatch(s -> s.getScore().equals(Student.Score.GOOD));
        System.out.println("noneMatch——"+b2);

        //按年龄排序且返回第一个元素
        Optional op1 = studentsList.stream()
                .sorted((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge()))
                .findFirst();
        System.out.println("findFirst(按年龄排序且返回第一个元素)——"+op1.get());

        //查找学生成绩为及格且返回的任意元素
        Optional op2 = studentsList.parallelStream()
                .filter(s -> s.getScore().equals(Student.Score.PASS))
                .findAny();
        System.out.println("findAny(查找学生成绩为及格且返回的任意元素)——"+op2.get());

        ///查找学生的总人数
        long count = studentsList.stream()
                .count();
        System.out.println("count——"+count);

        //查找年龄最大的学生信息
        Optional op3 = studentsList.stream()
                .max((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge()));
        System.out.println("max——"+op3.get());

        //查找学生所有的年龄范围,并获取最小的年龄
        Optional op4 = studentsList.stream()
                .map(Student::getAge)
                .min(Integer::compare);
        System.out.println("min——"+op4.get());
    }
    /*
        allMatch——false
        anyMatch——true
        noneMatch——false
        findFirst(按年龄排序且返回第一个元素)——com.jiayifeng.java1.Student@5f184fc6
        findAny(查找学生成绩为及格且返回的任意元素)——com.jiayifeng.java1.Student@34a245ab
        count——5
        max——com.jiayifeng.java1.Student@34a245ab
        min——19
     */

//    规约
    @Test
    public void Test1(){
//        练习一:计算1-10的自然数之和
        List 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);//55

//        练习二:计算公司所有员工工资的总和
        List employees = EmployeeData.getEmp();
        Stream salaryStream = employees.stream().map(Employee::getSalary);
        Optional sumMoney = salaryStream.reduce((d1, d2) -> (d1 + d2));
        System.out.println(sumMoney);
    }

//    收集
    @Test
    public void test2(){
        List emp = EmployeeData.getEmp();
        List employeeList = emp.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
        employeeList.forEach(System.out::println);
    }
}

Stream的详细介绍参考:http://t.csdnimg.cn/bAycz

16.5:Optional类

        为了解决空指针异常而引入Optional类

        Optional类的javadoc描述如下:这是一个可以为null的容器对象。如果值存在,则isPresent()方法会返回true,调用get()方法会返回该对象

        

package com.jiayifeng.java2;

/**
 * author 爱编程的小贾
 * create 2023-10-21 12:25
 */
public class Girl {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Girl() {
    }

    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                '}';
    }

    public Girl(String name) {
        this.name = name;
    }
}
package com.jiayifeng.java2;

/**
 * author 爱编程的小贾
 * create 2023-10-21 12:25
 */
public class Boy {
    private Girl girl;

    public Boy(Girl girl) {
        this.girl = girl;
    }

    public Boy() {
    }

    @Override
    public String toString() {
        return "Boy{" +
                "girl=" + girl +
                '}';
    }

    public Girl getGirl() {
        return girl;
    }

    public void setGirl(Girl girl) {
        this.girl = girl;
    }
}
package com.jiayifeng.java2;

import org.junit.Test;

import java.util.Optional;

/**
 * author 爱编程的小贾
 * create 2023-10-21 12:27
 *
 * 一:Optional类:为了在程序中避免出现空指针异常而创建的
 */
public class OptionalTest {
    @Test
    public void test1(){
//        1.Optional.of(T t):创建一个Optional实例,t必须为空
        Girl girl = new Girl();
        Optional girl1 = Optional.of(girl);

//        2.Optional.empty():创建一个空的Optional实例

//        3.Optional.ofNullable(T t):t可以为空
        Girl girl2 = new Girl();
        girl2 = null;
        Optional optionalGirlgirl1 = Optional.ofNullable(girl2);
        System.out.println(optionalGirlgirl1);
    }

    public String getGirlName(Boy boy){
        Optional boyOptional = Optional.ofNullable(boy);
//        此时的boy1一定非空
        Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));

        Girl girl1 = boy1.getGirl();

        Optional girlOptional = Optional.ofNullable(girl1);
//        girl2一定非空
        Girl girl2 = girlOptional.orElse(new Girl("古力娜扎"));

        return girl2.getName();
    }

    @Test
    public void test2(){
        Boy boy = null;
        boy = new Boy();
        boy = new Boy(new Girl("贾老师"));
        String girlName = getGirlName(boy);
        System.out.println(girlName);
    }
}

你可能感兴趣的:(Java语言,java,intellij-idea)