YAZONG 我的开源

JDK新特性8-17

  , ,
0 评论0 浏览

#此次特性更新到java17,具体原因看”LTS”部分。

#这里暂时只提供基本语法规则和API的使用部分内容。

下载

https://www.oracle.com/cn/java/technologies/downloads/”

发布

image.png

从java9这个版本开始,java的计划发布周期是6个月。Oracle快速迭代,小步快跑,互联网精神,功能更新快又好。

这意味着java的更新从传统的以特性驱动的发布周期,转变为时间驱动的发布模式。

针对企业客户要求,Oracle将以三年为周期发布长期支持版本(long term support)。

oracle的官方观点认为:与java7->java8->java9相比,

Java9->java10->java11的升级和8->8u20->8u40更相似。

新模式下的java版本发布都会包含许多变更,包括语言变更和JVM变更,这两者都会对IDE、字节码库和框架产生重大影响。此外,不仅会新增其他API,还会有API被删除(java9之前不会删除API,但之后,发布频率高,会发生API被删除的情况,这是比较显著的一个变化)。

目前看这种发布策略是非常成功的,解开了JAVA/JVM演进的许多枷锁,至关重要的是,OpenJDK的权利中心,正在转移到开发社区和开发者手中。

在新的模式中,既可以利用LTS满足企业长期可靠支持的需求,也可以满足各种开发者对于新特性迭代的诉求。

OracleJDK和OpenJDK

image.png

基本上oracle JDK和open JDK中的各种特性一样。

Open JDK基于开源,但是事实发现功能没啥区别。但在垃圾回收器层面,open JDK中有,oracle JDK中没有。

JEP

JEP(JDK Enhancement Proposals):jdk改进提案,每当需要有新的设想的时候,JEP可以提出非正式的规范(specification),被正式认可的JEP正式写进JDK的发展路线图并分配版本号。

LTS

LTS(long-term Support)长期支持。

image.png

Spring框架已支持JDK17。DUBBO3.2在202304也已支持,其他开源框架也在跟进。

那么根据已有市场开源环境,JDK版本的支持市场以及大特性的发布,那么在这相近时间段内选用JDK17是比较合理的选择。

发现从java11开始的LTS版本,都是8年一个生命周期。

新特性数量变化

image.png

如何学习新特性

一定要站在一定高度去看!升级JDK看重的还是底层的变化!

学习新特性的角度:

角度一(新的语法规则-多关注:

自动装箱拆箱、注解、枚举、lambda表达式、方法引用、switch表达式、try-catch变化、record、sealed等)。

角度二(增加、过时、删除API:

String、StringBuilder、StringBuffer、ArrayList、新的日期时间、Optional等)。

角度三(底层的优化、JVM参数的调整、GC的变化、内存结构(永久代->元空间))。

====案例开始JDK8部分

入门

package com.feature.jdk8.start.demo;

/**
 * @Author: yalong
 * @Description: 自定义函数式接口
 * @Date: Created in 2023/5/1 19:31
 * @Modified:
 */
@FunctionalInterface
public interface MyFunctionalInterface {
    void method();
}



package com.feature.jdk8.start.demo;

/**
 * @Author: yalong
 * @Description: 自定义函数式接口
 * @Date: Created in 2023/5/1 19:32
 * @Modified:
 */

public class MyFunctionalInterfaceTest {

    public static void main(String[] args) {
        MyFunctionalInterface myFunctionalInterface = () -> System.out.println("hello world");
        myFunctionalInterface.method();
    }

}

Lambda表达式1

package com.feature.jdk8.start;

import java.util.Comparator;

/**
 * @Author: yalong
 * @Description: lambda入门
 *
 * 举例:
 * (o1,o2) -> Integer.compare(o1,o2);
 *
 * 格式:
 * lambda形参列表 ->(lambda箭头操作符) lambda体
 * ->左边:lambda形参列表,对应着要重写的接口中的抽象方法的形参列表。
 * ->右边:lambda体,对应着接口的实现类要重写的方法的方法体。
 *
 * 本质:
 * 一方面,lambda表达式作为接口的实现类的对象。 -->万事万物皆对象。
 * 另一方面,lambda表达式是一个匿名函数。
 *
 * 函数式接口:接口中只声明一个抽象方法(@FunctionalInterface)。
 * 只有给函数式接口提供实现类的对象时,才可以使用lambda表达式。
 *
 * @Date: Created in 2023/5/1 8:37
 * @Modified:
 */

public class LambdaTest01 {

    public static void main(String[] args) {

        //-----------------案例:Runnable-----------------

        //方式一:匿名内部类
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello world 1~~!");
            }
        };
        r1.run();

        //方式二:lambda表达式
        Runnable r2 = () -> System.out.println("Hello world 2~~!");
        r2.run();


        //-----------------案例:Comparator-----------------

        /**
         * 方式一:匿名内部类
         */
        Comparator<Integer> com1 = new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                return Integer.compare(o1,o2);
            }
        };
        int compare11 = com1.compare(1,2);
        //A<B输出-1
        System.out.println("compare11:" + compare11);
        //A=B输出0
        int compare12 = com1.compare(1,1);
        System.out.println("compare12:" + compare12);
        //A>B输出1
        int compare13 = com1.compare(2,1);
        System.out.println("compare13:" + compare13);

        /**
         * 方式二:lambda表达式
         * 格式:
         * lambda形参列表 ->(lambda箭头操作符) lambda体
         * ->左边:lambda形参列表,对应着要重写的接口中的抽象方法的形参列表。
         * ->右边:lambda体,对应着接口的实现类要重写的方法的方法体。
         */

        //方式二:lambda方式1
        Comparator<Integer> com2 = (Integer o1,Integer o2) -> {return Integer.compare(o1,o2);};
        int compare2 = com2.compare(1,2);
        System.out.println("compare2:" + compare2);

        //方式二:lambda方式2
        Comparator<Integer> com3 = (o1,o2) -> {return Integer.compare(o1,o2);};
        int compare3 = Integer.compare(1,2);
        System.out.println("compare3:" + compare3);

        //方式二:lambda方式3-方法引用
        Comparator<Integer> com4 = Integer::compare;
        int compare4 = Integer.compare(1,2);
        System.out.println("compare4:" + compare4);


    }

}

Lambda表达式2

package com.feature.jdk8.start;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

/**
 * @Author: yalong
 * @Description: lambda语法:无参数、单个参数、多参数、有无返回值、类型推断
 *
 * 举例:
 * (o1,o2) -> Integer.compare(o1,o2);
 *
 * 格式:
 * lambda形参列表 ->(lambda箭头操作符) lambda体
 * ->左边:lambda形参列表,对应着要重写的接口中的抽象方法的形参列表。
 * ->右边:lambda体,对应着接口的实现类要重写的方法的方法体。
 *
 * 本质:
 * 一方面,lambda表达式作为接口的实现类的对象。 -->万事万物皆对象。
 * 另一方面,lambda表达式是一个匿名函数。
 *
 * 函数式接口:接口中只声明一个抽象方法(@FunctionalInterface)。
 * 只有给函数式接口提供实现类的对象时,才可以使用lambda表达式。
 *
 * @Date: Created in 2023/5/1 9:23
 * @Modified:
 */

public class LambdaTest02 {

    public static void main(String[] args) {

        //-----------------lambda语法1:无参数、无返回值
        Runnable r1 = new Runnable(){
            @Override
            public void run(){
                System.out.println("Hello world~~1");
            }
        };
        r1.run();

        Runnable r2 = () ->{
            System.out.println("Hello world~~2");
        };
        r2.run();


        //-----------------lambda语法2:单个参数、无返回值
        Consumer<String> consumer1 = new Consumer<String>(){
            @Override
            public void accept(String str){
                System.out.println(str);
            }
        };
        consumer1.accept("Hello world~~3");


        //-----------------lambda语法3:"类型推断"-数据类型可以省略、因为可由编译器推断得出。
        Consumer<String> consumer2 = (String str) -> System.out.println(str);
        consumer2.accept("Hello world~~4");

        Consumer<String> consumer3 = (str) -> System.out.println(str);
        consumer3.accept("Hello world~~5");

        //案例:数组中的类型推断
        int[] arr1 = new int[]{1,2,3};
        int[] arr2 = {1,2,3};
        //案例:泛型中的类型推断,最后省略了数据类型。
        HashMap<String,Integer> map = new HashMap<>();
        //案例:JDK10之后的entrySet
        Set<Map.Entry<String,Integer>> entrySet1 = map.entrySet();
        var entrySet2 = map.entrySet();


        //-----------------lambda语法4:lambda若只需要一个参数时,参数的小括号可以省略。
        Consumer<String> consumer4 = str -> System.out.println(str);
        consumer4.accept("Hello world~~6");

        //-----------------lambda语法5:lambda需要两个或以上的参数,多条执行语句,可以有返回值。
        Comparator<Integer> comparator1 = new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                System.out.println("Hello world~~7 : " + o1);
                System.out.println("Hello world~~7 : " + o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println("Hello world~~7 : " + comparator1.compare(1,2));

        Comparator<Integer> comparator2 = (o1,o2) -> {
            System.out.println("Hello world~~8 : " + o1);
            System.out.println("Hello world~~8 : " + o2);
            return o1.compareTo(o2);
        };
        System.out.println("Hello world~~8 : " + comparator2.compare(1,1));

        //-----------------lambda语法6:当lambda体只有一条语句时,return与大括号都有,那么都可以省略。

        Comparator<Integer> comparator3 = (o1,o2) -> o1.compareTo(o2);
        System.out.println("Hello world~~9 : " + comparator3.compare(1,1));

        Comparator<Integer> comparator4 = Integer::compareTo;
        System.out.println("Hello world~~10 : " + comparator4.compare(2,1));


    }

}

四大核心函数接口

image.png

公共类

package com.feature.jdk8.common;

/**
 * @Author: yalong
 * @Description:
 * @Date: Created in 2023/5/2 9:38
 * @Modified:
 */

public class Employee {

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

    public Employee() {
    }

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

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

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


    @Override
    public int hashCode() {

        int result;
        long temp;
        result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        temp = Double.doubleToLongBits(salary);
        result = 31 * result + (int)(temp ^ (temp >>> 32));

        return result;

    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(obj == null || getClass() != obj.getClass()){
            return false;
        }
        Employee employee = (Employee) obj;

        if(this.getId() != employee.getId()){
            return false;
        }
        if(this.getAge() != employee.getAge()){
            return false;
        }
        if(Double.compare(employee.getSalary(),this.getSalary()) != 0){
            return false;
        }

        return this.getName() != null ? this.getName().equals(employee.getName()) : employee.getName() == null;

    }


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

package com.feature.jdk8.common;

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

/**
 * @Author: yalong
 * @Description:
 * @Date: Created in 2023/5/3 8:57
 * @Modified:
 */

public class EmployeeData {

    public static List<Employee> getEmployee(){

        List<Employee> list = new ArrayList<>();

        list.add(new Employee(1001,"name1001",11,1111));
        list.add(new Employee(1002,"name1002",22,2222));
        list.add(new Employee(1003,"name1003",33,3333));
        list.add(new Employee(1004,"name1004",44,4444));
        list.add(new Employee(1005,"name1005",55,5555));
        list.add(new Employee(1006,"name1006",66,6666));
        list.add(new Employee(1007,"name1007",77,7777));
        list.add(new Employee(1008,"name1008",88,8888));
        list.add(new Employee(1008,"name1008",88,8888));
        list.add(new Employee(1009,"name1009",99,9999));
        list.add(new Employee(1009,"name1009",99,9999));
        list.add(new Employee(1009,"name1009",99,9999));

        return list;
    }


}
package com.feature.jdk8.common;

/**
 * @Author: yalong
 * @Description:
 * @Date: Created in 2023/5/2 9:38
 * @Modified:
 */

public class Employee2 implements Comparable<Employee2>{

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

    @Override
    public int compareTo(Employee2 o) {
        return 0;
    }

    public Employee2() {
    }

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

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

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


    @Override
    public int hashCode() {

        int result;
        long temp;
        result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        temp = Double.doubleToLongBits(salary);
        result = 31 * result + (int)(temp ^ (temp >>> 32));

        return result;

    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(obj == null || getClass() != obj.getClass()){
            return false;
        }
        Employee2 employee = (Employee2) obj;

        if(this.getId() != employee.getId()){
            return false;
        }
        if(this.getAge() != employee.getAge()){
            return false;
        }
        if(Double.compare(employee.getSalary(),this.getSalary()) != 0){
            return false;
        }

        return this.getName() != null ? this.getName().equals(employee.getName()) : employee.getName() == null;

    }


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


package com.feature.jdk8.common;

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

/**
 * @Author: yalong
 * @Description:
 * @Date: Created in 2023/5/3 8:57
 * @Modified:
 */

public class EmployeeData2 {

    public static List<Employee2> getEmployee(){

        List<Employee2> list = new ArrayList<>();

        list.add(new Employee2(1001,"name1001",11,1111));
        list.add(new Employee2(1002,"name1002",22,2222));
        list.add(new Employee2(1003,"name1003",33,3333));
        list.add(new Employee2(1004,"name1004",44,4444));
        list.add(new Employee2(1005,"name1005",55,5555));
        list.add(new Employee2(1006,"name1006",66,6666));
        list.add(new Employee2(1007,"name1007",77,7777));
        list.add(new Employee2(1008,"name1008",88,8888));
        list.add(new Employee2(1008,"name1008",88,8888));
        list.add(new Employee2(1009,"name1009",99,9999));
        list.add(new Employee2(1009,"name1009",99,9999));
        list.add(new Employee2(1009,"name1009",99,9999));

        return list;

    }

}

方法引用

对象::实例方法

package com.feature.jdk8.methodreference;

import com.feature.jdk8.common.Employee;

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

/**
 * @Author: yalong
 * @Description: 方法引用
 * 举例:
 * Integer :: compare
 * 格式:
 * 类(或对象) :: 方法名
 * 理解:
 * 方法引用,可以看做是基于lambda表达式的进一步刻画。
 * 当需要提供一个函数式接口的实例时,那么可以使用lambda表达式提供此实例。
 * 当满足一定的条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。
 * 本质:
 * 方法引用作为了函数式接口的实例。 --> "万事万物皆对象"
 *
 * 情况1: 对象 :: 实例方法
 * 要求: 函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的形参列表和返回值类型都相同/一致(多态场景:装箱拆箱、父类)。
 * 此时,可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。
 * 注意:此方法b是非静态方法,需要对象调用。
 *
 * @Date: Created in 2023/5/1 19:57
 * @Modified:
 */

public class MethodReferenceTest01 {

    public static void main(String[] args) {


        /**
         * 案例1  Consumer
         */
        Consumer<String> consumer1 = new Consumer<String>(){
            @Override
            public void accept(String str){
                System.out.println(str);
            }
        };
        consumer1.accept("Hello world~~~~1");

        //lambda表达式
        Consumer<String> consumer2 = str -> System.out.println(str);
        consumer2.accept("Hello world~~~~2");

        //方法引用
        //TODO 只要接口中的方法返回值类型和这里的方法返回值类型保持一致就可以这么写。
        Consumer<String> consumer3 = System.out :: println;
        consumer3.accept("Hello world~~~~3");

        //方法引用
        PrintStream printStream = System.out;
        Consumer<String> consumer4 = printStream :: println;
        consumer4.accept("Hello world~~~~4");


        /**
         * 案例2  Supplier
         */
        Employee employee = new Employee(1001,"name01",11,1111);
        Supplier<String> supplier1 = new Supplier<String>() {
            @Override
            public String get() {
                return employee.getName();
            }
        };
        System.out.println("Hello world~~~~5 : " + supplier1.get());

        //lambda表达式
        Supplier<String> supplier2 = () -> employee.getName();
        System.out.println("Hello world~~~~6 : " + supplier2.get());

        //方法引用
        Supplier<String> supplier3 = employee :: getName;
        System.out.println("Hello world~~~~7 : " + supplier3.get());


    }

}

类::静态方法

package com.feature.jdk8.methodreference;

import java.util.Comparator;
import java.util.function.Function;

/**
 * @Author: yalong
 * @Description: 方法引用
 * 举例:
 * Integer :: compare
 * 格式:
 * 类(或对象) :: 方法名
 * 理解:
 * 方法引用,可以看做是基于lambda表达式的进一步刻画。
 * 当需要提供一个函数式接口的实例时,那么可以使用lambda表达式提供此实例。
 * 当满足一定的条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。
 * 本质:
 * 方法引用作为了函数式接口的实例。 --> "万事万物皆对象"
 *
 * 情况2: 类 :: 静态方法
 * 要求: 函数式接口中的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值类型都相同/一致(多态场景:装箱拆箱、父类)。
 * 此时,可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。
 * 注意:此方法b是静态方法,需要对象调用。
 *
 * @Date: Created in 2023/5/1 19:57
 * @Modified:
 */

public class MethodReferenceTest02 {

    public static void main(String[] args) {


        /**
         * 案例1  Comparator
         */
        Comparator<Integer> comparator1 = new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                return Integer.compare(o1,o2);
            }
        };
        System.out.println("Hello world~~~~1 : " + comparator1.compare(1,2));

        //lambda表达式
        Comparator<Integer> comparator2 = (o1,o2) -> Integer.compare(o1,o2);
        System.out.println("Hello world~~~~2 : " + comparator2.compare(2,1));

        //方法引用
        Comparator<Integer> comparator3 = Integer :: compare;
        System.out.println("Hello world~~~~3 : " + comparator3.compare(1,1));


        /**
         * 案例2  Function
         */
        Function<Double,Long> function1 = new Function<Double,Long>(){
            @Override
            public Long apply(Double d){
                return Math.round(d);
            }
        };
        System.out.println("Hello world~~~~4 : " + function1.apply(1.1D));

        //lambda表达式
        Function<Double,Long> function2 = D1 -> Math.round(D1);
        System.out.println("Hello world~~~~5 : " + function2.apply(1.2D));

        //方法引用
        Function<Double,Long> function3 = Math :: round;
        System.out.println("Hello world~~~~6 : " + function3.apply(0.9D));




    }

}

类::实例方法

package com.feature.jdk8.methodreference;

import com.feature.jdk8.common.Employee;

import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Function;

/**
 * @Author: yalong
 * @Description: 方法引用
 * 举例:
 * Integer :: compare
 * 格式:
 * 类(或对象) :: 方法名
 * 理解:
 * 方法引用,可以看做是基于lambda表达式的进一步刻画。
 * 当需要提供一个函数式接口的实例时,那么可以使用lambda表达式提供此实例。
 * 当满足一定的条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。
 * 本质:
 * 方法引用作为了函数式接口的实例。 --> "万事万物皆对象"
 *
 * 情况3: 类 :: 实例方法
 * 要求: 函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的返回值类型相同。
 * 同时,抽象方法a中有n个参数,方法b中有n-1个参数,且抽象方法a的第一个参数作为方法b的调用者,
 * 且抽象方法a的后n-1个参数与方法b的n-1个参数的类型相同(或一致)。
 * 则可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。
 *
 * 注意:此方法b是非静态方法,需要对象调用。但是形式上,写出对象a所属的类。
 *
 * @Date: Created in 2023/5/1 19:57
 * @Modified:
 */

public class MethodReferenceTest03 {

    public static void main(String[] args) {

        /**
         * 案例一:
         * Comparator-compare
         * String-compareTo
         */
        Comparator<String> comparator1 = new Comparator<String>(){
            @Override
            public int compare(String s1,String s2){
                return s1.compareTo(s2);
            }
        };
        System.out.println("Hello world~~~~1 : " + comparator1.compare("123","abc"));

        //lambda表达式
        Comparator<String> comparator2 = (s1,s2) -> s1.compareTo(s2);
        System.out.println("Hello world~~~~2 : " + comparator2.compare("abc","123"));

        //方法引用
        Comparator<String> comparator3 = String :: compareTo;
        System.out.println("Hello world~~~~3 : " + comparator3.compare("abc","abc"));

        /**
         * 案例二:
         * BiPredicate-test
         * String-equals
         */
        BiPredicate<String,String> biPredicate1 = new BiPredicate<String,String>(){
            @Override
            public boolean test(String s1,String s2){
                return s1.equals(s2);
            }
        };
        System.out.println("Hello world~~~~4 : " + biPredicate1.test("abc","abc"));

        //lambda表达式
        BiPredicate<String,String> biPredicate2 = (s1,s2) -> s1.equals(s2);
        System.out.println("Hello world~~~~5 : " + biPredicate2.test("abc","123"));

        //方法引用
        BiPredicate<String,String> biPredicate3 = String :: equals;
        System.out.println("Hello world~~~~5 : " + biPredicate3.test("123","abc"));

        /**
         * 案例三:
         * Function-apply
         * 对象自定义方法
         */
        Employee employee = new Employee(1001,"name01",11,1111);
        Function<Employee, String> function1 = new Function<Employee,String>(){
            @Override
            public String apply(Employee emp){
                return emp.getName();
            }
        };
        System.out.println("Hello world~~~~6 : " + function1.apply(employee));

        //lambda表达式
        Function<Employee,String> function2 = emp -> emp.getName();
        System.out.println("Hello world~~~~7 : " + function2.apply(employee));

        //方法引用
        Function<Employee,String> function3 = Employee:: getName;
        System.out.println("Hello world~~~~8 : " + function3.apply(employee));

    }

}

构造器引用

package com.feature.jdk8.constructorreference;

import com.feature.jdk8.common.Employee;

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

/**
 * @Author: yalong
 * @Description:
 * 构造器引用
 * 格式   类名 :: new
 * 调用了类名对应的类中的某一个确定的构造器。
 * 具体调用的哪一个构造器取决于函数式接口的抽象方法的形参列表!
 *
 * 数组引用
 * 格式   数组名[] :: new
 *
 * @Date: Created in 2023/5/3 6:39
 * @Modified:
 */

public class ConstructorReferenceTest01 {

    /**
     * 构造器引用
     * @param args
     */
    public static void main(String[] args) {

        /**
         * 案例一:
         * Supplier-get
         */
        Supplier<Employee> supplier1 = new Supplier<Employee>(){
            @Override
            public Employee get(){
                return new Employee();
            }
        };
        System.out.println("Hello world~~~~1 : " + supplier1.get());

        //lambda表达式
        Supplier<Employee> supplier2 = () -> new Employee();
        System.out.println("Hello world~~~~2 : " + supplier2.get());

        //方法引用
        Supplier<Employee> supplier3 = Employee:: new;
        System.out.println("Hello world~~~~3 : " + supplier3.get());


        /**
         * 案例二:
         * Function-apply
         */
        Function<Integer, Employee> function1 = new Function<Integer, Employee>(){
            @Override
            public Employee apply(Integer id){
                return new Employee(id);
            }
        };
        System.out.println("Hello world~~~~4 : " + function1.apply(1));

        //lambda表达式
        Function<Integer, Employee> function2 = id -> new Employee(id);
        System.out.println("Hello world~~~~5 : " + function2.apply(2));

        //方法引用
        Function<Integer, Employee> function3 = Employee:: new;
        System.out.println("Hello world~~~~6 : " + function3.apply(3));


        /**
         * 案例三:
         * BiFunction-apply
         */
        BiFunction<Integer,String, Employee> biFunction1 = new BiFunction<Integer,String, Employee>(){
            @Override
            public Employee apply(Integer id, String name){
                return new Employee(id,name);
            }
        };
        System.out.println("Hello world~~~~7 : " + biFunction1.apply(1001,"testname1"));

        //lambda表达式
        BiFunction<Integer,String, Employee> biFunction2 = (id, name) -> new Employee(id,name);
        System.out.println("Hello world~~~~8 : " + biFunction2.apply(1002,"testname2"));

        //方法引用
        BiFunction<Integer,String, Employee> biFunction3 = Employee:: new;
        System.out.println("Hello world~~~~9 : " + biFunction3.apply(1003,"testname3"));


    }


}

数组引用

package com.feature.jdk8.constructorreference;

import com.feature.jdk8.common.Employee;

import java.util.function.Function;

/**
 * @Author: yalong
 * @Description:
 * 构造器引用
 * 格式   类名 :: new
 * 调用了类名对应的类中的某一个确定的构造器。
 * 具体调用的哪一个构造器取决于函数式接口的抽象方法的形参列表!
 *
 * 数组引用
 * 格式   数组名[] :: new
 *
 * @Date: Created in 2023/5/3 6:39
 * @Modified:
 */

public class ConstructorReferenceTest02 {

    /**
     * 数组引用
     * @param args
     */
    public static void main(String[] args) {

        /**
         * 案例一:
         * Function-apply
         */
        Function<Integer, Employee[]> function4 = new Function<Integer, Employee[]>(){
            @Override
            public Employee[] apply(Integer length){
                return new Employee[length];
            }
        };
        System.out.println("Hello world~~~~10 : " + function4.apply(10).length);

        //lambda表达式
        Function<Integer, Employee[]> function5 = length -> new Employee[length];
        System.out.println("Hello world~~~~11 : " + function5.apply(11)[0]);

        //方法引用
        Function<Integer, Employee[]> function6 = Employee[] :: new;
        System.out.println("Hello world~~~~12 : " + function6.apply(12).toString());


    }


}

Stream

StreamAPI使用三环节:实例化、中间操作、终止操作。

1)Stream API VS 集合框架

Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU。

集合关注的是数据的存储,面向内存。

Stream API之于集合,类似于SQL之于数据表的查询。

2)使用说明

Stream自己不会存储元素。

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

Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生最终结果并结束Stream。

Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。

3)Stream执行流程

步骤一:Stream的实例化

(一个数据源,如集合、数组,获取一个流。)

步骤二:一系列的中间操作

(每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。

因为中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。)

步骤三:执行终止操作

(终止操作的方法返回值类型就不再是Stream了,因为一旦执行终止操作,就结束整个Stream操作了。

一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。)

image.png

实例化

package com.feature.jdk8.streamapi;

import com.feature.jdk8.common.Employee;
import com.feature.jdk8.common.EmployeeData;

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

/**
 * @Author: yalong
 * @Description: StreamAPI使用三环节:实例化、中间操作、终止操作。
 *
 * 1)Stream API VS 集合框架
 * Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU。
 * 集合关注的是数据的存储,面向内存。
 * Stream API之于集合,类似于SQL之于数据表的查询。
 *
 * 2)使用说明
 * Stream自己不会存储元素。
 * Stream不会改变原对象,相反,它们会返回一个持有结果的新Stream。
 * Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生最终结果并结束Stream。
 * Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。
 *
 * 3)Stream执行流程
 * 步骤一:Stream的实例化
 * (一个数据源,如集合、数组,获取一个流。)
 * 步骤二:一系列的中间操作
 * (每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。
 * 因为中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。)
 * 步骤三:执行终止操作
 * (终止操作的方法返回值类型就不再是Stream了,因为一旦执行终止操作,就结束整个Stream操作了。
 * 一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。)
 * @Date: Created in 2023/5/3 7:18
 * @Modified:
 */

public class StreamAPITest01 {

    /**
     * 步骤一:Stream实例化
     * @param args
     */
    public static void main(String[] args) {

        /**
         * 创建Stream方式一:集合
         */
        List<Employee> list = EmployeeData.getEmployee();
        /**
         * 返回一个顺序流
         *     default Stream<E> stream() {
         *         return StreamSupport.stream(spliterator(), false);
         *     }
         */
        Stream<Employee> stream1 = list.stream();
        System.out.println("Hello world~~~~1 : " + stream1);
        /**
         * 返回一个并行流
         *     default Stream<E> parallelStream() {
         *         return StreamSupport.stream(spliterator(), true);
         *     }
         */
        Stream<Employee> stream2 = list.parallelStream();
        System.out.println("Hello world~~~~2 : " + stream2);

        /**
         * 创建Stream方式二:数组
         */
        Integer[] arr1 = new Integer[]{1,2,3,4,5};
        Stream<Integer> stream3 = Arrays.stream(arr1);
        System.out.println("Hello world~~~~3 : " + stream3);

        int[] arr2 = new int[]{1,2,3,4,5};
        IntStream stream4 = Arrays.stream(arr2);
        System.out.println("Hello world~~~~4 : " + stream4);


        /**
         * 创建Stream方式三:通过Stream的of()
         */
        Stream<String> stream5 = Stream.of("a","b");
        System.out.println("Hello world~~~~5 : " + stream5);


    }


}

中间操作01

package com.feature.jdk8.streamapi;

import com.feature.jdk8.common.Employee;
import com.feature.jdk8.common.EmployeeData;

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

/**
 * @Author: yalong
 * @Description: StreamAPI使用三环节:实例化、中间操作、终止操作。
 *
 * 1)Stream API VS 集合框架
 * Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU。
 * 集合关注的是数据的存储,面向内存。
 * Stream API之于集合,类似于SQL之于数据表的查询。
 *
 * 2)使用说明
 * Stream自己不会存储元素。
 * Stream不会改变原对象,相反,它们会返回一个持有结果的新Stream。
 * Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生最终结果并结束Stream。
 * Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。
 *
 * 3)Stream执行流程
 * 步骤一:Stream的实例化
 * (一个数据源,如集合、数组,获取一个流。)
 * 步骤二:一系列的中间操作
 * (每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。
 * 因为中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。)
 * 步骤三:执行终止操作
 * (终止操作的方法返回值类型就不再是Stream了,因为一旦执行终止操作,就结束整个Stream操作了。
 * 一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。)
 * @Date: Created in 2023/5/3 7:18
 * @Modified:
 */

public class StreamAPITest02 {

    /**
     * 步骤二:一系列的中间操作
     * 筛选与切片
     * @param args
     */
    public static void main(String[] args) {

        List<Employee> list1 = EmployeeData.getEmployee();
        Stream<Employee> stream1 = list1.stream();

        /**
         * 接收lambda,从流中排除某些元素。
         * Stream<T> filter(Predicate<? super T> predicate);
         */
        stream1.filter(employee -> employee.getSalary() > 7777).forEach(System.out :: println);

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

        //错误的,因为stream在上方已经执行了终止操作foreach,所以就不可以再调用其他的中间操作或终止操作了。
        //stream1.limit(2).forEach(System.out :: println);
        /**
         * 截断流,使其元素不超过给定数量。若元素不足,那么返回一个空流,与skip一样。
         * Stream<T> limit(long maxSize);
         */
        list1.stream().limit(0).forEach(System.out :: println);

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

        /**
         * 跳过元素,返回一个扔掉前n个元素的流。若元素不足n个,则返回一个空流,与limit一样。
         * Stream<T> skip(long n);
         */
        list1.stream().skip(7).forEach(System.out :: println);

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

        /**
         * 筛选,通过流生成元素的hashCode()和equals()来去除重复元素。
         * 如果去掉Employee中重写的hashCode()和equals(),那么就不会有distinct()的效果了。
         * Stream<T> distinct();
         */
        list1.stream().distinct().forEach(System.out :: println);

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

    
    }


}

中间操作02

package com.feature.jdk8.streamapi;

import com.feature.jdk8.common.Employee;
import com.feature.jdk8.common.EmployeeData;

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

/**
 * @Author: yalong
 * @Description: StreamAPI使用三环节:实例化、中间操作、终止操作。
 *
 * 1)Stream API VS 集合框架
 * Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU。
 * 集合关注的是数据的存储,面向内存。
 * Stream API之于集合,类似于SQL之于数据表的查询。
 *
 * 2)使用说明
 * Stream自己不会存储元素。
 * Stream不会改变原对象,相反,它们会返回一个持有结果的新Stream。
 * Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生最终结果并结束Stream。
 * Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。
 *
 * 3)Stream执行流程
 * 步骤一:Stream的实例化
 * (一个数据源,如集合、数组,获取一个流。)
 * 步骤二:一系列的中间操作
 * (每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。
 * 因为中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。)
 * 步骤三:执行终止操作
 * (终止操作的方法返回值类型就不再是Stream了,因为一旦执行终止操作,就结束整个Stream操作了。
 * 一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。)
 * @Date: Created in 2023/5/3 7:18
 * @Modified:
 */

public class StreamAPITest03 {

    /**
     * 步骤二:一系列的中间操作
     * 映射
     * @param args
     */
    public static void main(String[] args) {

        /**
         * 接收一个函数作为参数,将元素转换为其他形式或提取信息,该函数被应用到每个元素。
         * <R> Stream<R> map(Function<? super T, ? extends R> mapper);
         */

        //练习1

        List<String> list = Arrays.asList("a","b");

        //lambda表达式
        list.stream().map(str -> str.toUpperCase()).forEach(System.out :: println);
        System.out.println("---------------------------------------");
        //方法引用
        list.stream().map(String :: toUpperCase).forEach(System.out :: println);
        System.out.println("---------------------------------------");

        //练习2

        List<Employee> employees = EmployeeData.getEmployee();

        //lambda表达式
        employees.stream().filter(employee -> employee.getSalary() > 3333).forEach(System.out :: println);
        System.out.println("---------------------------------------");
        employees.stream().filter(employee -> employee.getSalary() > 5555).map(employee -> employee.getName()).forEach(System.out :: println);
        System.out.println("---------------------------------------");
        //方法引用
        employees.stream().filter(employee -> employee.getId() >= 1008).map(Employee::getId).distinct().forEach(System.out :: println);
        System.out.println("---------------------------------------");


    }


}

中间操作03

package com.feature.jdk8.streamapi;

import com.feature.jdk8.common.Employee2;
import com.feature.jdk8.common.EmployeeData2;

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

/**
 * @Author: yalong
 * @Description: StreamAPI使用三环节:实例化、中间操作、终止操作。
 *
 * 1)Stream API VS 集合框架
 * Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU。
 * 集合关注的是数据的存储,面向内存。
 * Stream API之于集合,类似于SQL之于数据表的查询。
 *
 * 2)使用说明
 * Stream自己不会存储元素。
 * Stream不会改变原对象,相反,它们会返回一个持有结果的新Stream。
 * Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生最终结果并结束Stream。
 * Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。
 *
 * 3)Stream执行流程
 * 步骤一:Stream的实例化
 * (一个数据源,如集合、数组,获取一个流。)
 * 步骤二:一系列的中间操作
 * (每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。
 * 因为中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。)
 * 步骤三:执行终止操作
 * (终止操作的方法返回值类型就不再是Stream了,因为一旦执行终止操作,就结束整个Stream操作了。
 * 一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。)
 * @Date: Created in 2023/5/3 7:18
 * @Modified:
 */

public class StreamAPITest04 {

    /**
     * 步骤二:一系列的中间操作
     * 排序
     * TODO 自然排序默认升序,原数组并没有因为升序而做调整。
     * @param args
     */
    public static void main(String[] args) {

        /**
         * 案例一
         */

        Integer[] arr1 = new Integer[]{41,6,31,3,64,91,5,4};
        String[] arr2 = new String[]{"f","32","#","a"};

        Arrays.stream(arr1).sorted().forEach(System.out :: println);
        System.out.println(Arrays.toString(arr1));
        //上下二者方法最终都是调toString(x),不过上述是静态的,下述是重写java.lang.Object中的toString(x),二者都for循环打印每个字符。
        //System.out.println(Arrays.asList(arr1));

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

        Arrays.stream(arr2).sorted().forEach(System.out :: println);
        System.out.println(Arrays.asList(arr2));

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

        //降序    TODO 前面加-负号就降序了
        Arrays.stream(arr2).sorted((s1,s2) -> -s1.compareTo(s2)).forEach(System.out :: println);
        //升序
        Arrays.stream(arr2).sorted(String :: compareTo).forEach(System.out :: println);

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

        /**
         * 案例二
         * 因为Employee没有实现Comparable接口,所以报错!
         * Employee cannot be cast to class java.lang.Comparable
         * TODO 还未找到为啥要实现Comparable接口,源码中的关系,sorted默认形参是Comparator。
         */

        //自然排序
        List<Employee2> list = EmployeeData2.getEmployee();
        list.stream().sorted().forEach(System.out :: println);

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

        //定制排序
        //TODO 注意sorted中的参数对应Comparator中的实现方法int compare(T o1, T o2);
        list.stream().sorted((e1,e2) -> e2.getAge() - e1.getAge()).forEach(System.out :: println);




    }


}

终止操作01

package com.feature.jdk8.streamapi;

import com.feature.jdk8.common.Employee;
import com.feature.jdk8.common.EmployeeData;

import java.util.Iterator;
import java.util.List;

/**
 * @Author: yalong
 * @Description: StreamAPI使用三环节:实例化、中间操作、终止操作。
 *
 * 1)Stream API VS 集合框架
 * Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU。
 * 集合关注的是数据的存储,面向内存。
 * Stream API之于集合,类似于SQL之于数据表的查询。
 *
 * 2)使用说明
 * Stream自己不会存储元素。
 * Stream不会改变原对象,相反,它们会返回一个持有结果的新Stream。
 * Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生最终结果并结束Stream。
 * Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。
 *
 * 3)Stream执行流程
 * 步骤一:Stream的实例化
 * (一个数据源,如集合、数组,获取一个流。)
 * 步骤二:一系列的中间操作
 * (每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。
 * 因为中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。)
 * 步骤三:执行终止操作
 * (终止操作的方法返回值类型就不再是Stream了,因为一旦执行终止操作,就结束整个Stream操作了。
 * 一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。)
 * @Date: Created in 2023/5/3 7:18
 * @Modified:
 */

public class StreamAPITest05 {

    /**
     * 步骤三:终止操作
     * 匹配与查找
     * @param args
     */
    public static void main(String[] args) {

        List<Employee> list = EmployeeData.getEmployee();

        /**
         * 检查是否匹配所有元素
         * boolean allMatch(Predicate<? super T> predicate);
         */
        //检查是否所有员工年龄>55
        System.out.println(list.stream().allMatch(employee -> employee.getAge() > 55));
        System.out.println("---------------------------------------");
        /**
         * 检查是否至少匹配一个元素
         * boolean anyMatch(Predicate<? super T> predicate);
         */
        //检查是否存在ID>1008的员工
        System.out.println(list.stream().anyMatch(employee -> employee.getId() > 1008));
        System.out.println("---------------------------------------");
        /**
         * 返回第一个元素
         * TODO 默认升序的第一个元素
         * Optional<T> findFirst();
         */
        System.out.println(list.stream().findFirst().get());
        System.out.println("---------------------------------------");
        /**
         * 返回流中元素的总个数
         * long count();
         */
        System.out.println(list.stream().filter(employee -> employee.getSalary() > 8888).count());
        System.out.println("---------------------------------------");
        /**
         * 返回流中的最大值
         * Optional<T> max(Comparator<? super T> comparator);
         */
        //返回最高/最低的工资:方式1
        System.out.println(list.stream().max((employee1,employee2) -> Double.compare(employee1.getSalary(),employee2.getSalary())).get());
        /**
         * 返回流中的最小值
         * Optional<T> min(Comparator<? super T> comparator);
         */
        //返回最高/最低的工资:方式2
        System.out.println(list.stream().map(employee -> employee.getSalary()).min((salary1,salary2) -> Double.compare(salary1,salary2)).get());
        //System.out.println(list.stream().map(employee -> employee.getAge()).distinct().max(Integer :: compare).get());
        System.out.println(list.stream().map(employee -> employee.getAge()).max(Integer :: compare).get());
        System.out.println("---------------------------------------");
        System.out.println("-----------------内部迭代----------------------");
        /**
         * 内部迭代
         * void forEach(Consumer<? super T> action);
         */
        list.stream().forEach(System.out :: println);
        System.out.println("----------------集合:在JDK8中增加的遍历list.forEach-----------------------");
        //集合:在JDK8中增加的遍历方法
        list.forEach(System.out :: println);
        //集合:其他三种遍历方法
        System.out.println("---------------集合:iterator------------------------");
        Iterator<Employee> employeeIterator = list.iterator();
        while(employeeIterator.hasNext()){
            System.out.println(employeeIterator.next());
        }
        System.out.println("---------------集合:增强for------------------------");
        for(Employee employee : list){
            System.out.println(employee);
        }
        System.out.println("---------------集合:一般for------------------------");
        for (int i = 0; i < list.size();i++){
            System.out.println(list.get(i));
        }

    }


}

终止操作02

package com.feature.jdk8.streamapi;

import com.feature.jdk8.common.Employee;
import com.feature.jdk8.common.EmployeeData;

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

/**
 * @Author: yalong
 * @Description: StreamAPI使用三环节:实例化、中间操作、终止操作。
 *
 * 1)Stream API VS 集合框架
 * Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU。
 * 集合关注的是数据的存储,面向内存。
 * Stream API之于集合,类似于SQL之于数据表的查询。
 *
 * 2)使用说明
 * Stream自己不会存储元素。
 * Stream不会改变原对象,相反,它们会返回一个持有结果的新Stream。
 * Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生最终结果并结束Stream。
 * Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。
 *
 * 3)Stream执行流程
 * 步骤一:Stream的实例化
 * (一个数据源,如集合、数组,获取一个流。)
 * 步骤二:一系列的中间操作
 * (每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。
 * 因为中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。)
 * 步骤三:执行终止操作
 * (终止操作的方法返回值类型就不再是Stream了,因为一旦执行终止操作,就结束整个Stream操作了。
 * 一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。)
 * @Date: Created in 2023/5/3 7:18
 * @Modified:
 */

public class StreamAPITest06 {

    /**
     * 步骤三:终止操作
     * 归约
     * @param args
     */
    public static void main(String[] args) {

        /**
         * T reduce(T identity, BinaryOperator<T> accumulator);
         * identity为初始值,后续计算在此初始值的基础上进行计算。
         */
        //计算1-10的自然数的和
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        System.out.println(list.stream().reduce(10,(x1,x2) -> x1 + x2));
        System.out.println(list.stream().reduce(0,(x1,x2) -> x1 + x2).compareTo(5));
        System.out.println(list.stream().reduce(0,(x1,x2) -> x1 + x2).compareTo(45));
        System.out.println(list.stream().reduce(0,(x1,x2) -> x1 + x2).compareTo(55));
        System.out.println("---------------------------------------");
        System.out.println(list.stream().reduce(0,(x1,x2) -> Integer.sum(x1,x2)));
        System.out.println("---------------------------------------");
        System.out.println(list.stream().reduce(0,Integer :: sum));
        System.out.println("---------------------------------------");
        List<Employee> employeeList = EmployeeData.getEmployee();
        System.out.println(employeeList.stream().map(employee -> employee.getSalary()).reduce(Double :: sum));
        System.out.println(employeeList.stream().map(employee -> employee.getSalary()).reduce(Double :: sum).get());

    }


}

终止操作03

package com.feature.jdk8.streamapi;

import com.feature.jdk8.common.Employee;
import com.feature.jdk8.common.EmployeeData;

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

/**
 * @Author: yalong
 * @Description: StreamAPI使用三环节:实例化、中间操作、终止操作。
 *
 * 1)Stream API VS 集合框架
 * Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU。
 * 集合关注的是数据的存储,面向内存。
 * Stream API之于集合,类似于SQL之于数据表的查询。
 *
 * 2)使用说明
 * Stream自己不会存储元素。
 * Stream不会改变原对象,相反,它们会返回一个持有结果的新Stream。
 * Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生最终结果并结束Stream。
 * Stream一旦执行了终止操作,就不能再调用其他中间操作或终止操作了。
 *
 * 3)Stream执行流程
 * 步骤一:Stream的实例化
 * (一个数据源,如集合、数组,获取一个流。)
 * 步骤二:一系列的中间操作
 * (每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。
 * 因为中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。)
 * 步骤三:执行终止操作
 * (终止操作的方法返回值类型就不再是Stream了,因为一旦执行终止操作,就结束整个Stream操作了。
 * 一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。)
 * @Date: Created in 2023/5/3 7:18
 * @Modified:
 */

public class StreamAPITest07 {

    /**
     * 步骤三:终止操作
     * 收集
     * @param args
     */
    public static void main(String[] args) {

        List<Employee> employeeList = EmployeeData.getEmployee();

        /**
         * 将流转换为其他形式,接收一个Collector接口的实现,用于给Stream做元素汇总的方法。
         * <R, A> R collect(Collector<? super T, A, R> collector);
         */

        //案例一
        List<Employee> employeeList1 = employeeList.stream().filter(employee -> employee.getSalary() > 5555).collect(Collectors.toList());
        System.out.println("---------------------------------------");
        employeeList1.stream().forEach(System.out :: println);
        System.out.println("---------------------------------------");
        employeeList.stream().forEach(System.out :: println);

        //案例二
        System.out.println("---------------------------------------");
        List<Double> employeeList2 = employeeList.stream().map(employee -> employee.getSalary()).sorted(Double :: compare).collect(Collectors.toList());
        employeeList2.stream().forEach(System.out :: println);

    }


}

接口

公共类

package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 *
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 *
 * @Date: Created in 2023/5/8 2:30
 * @Modified:
 */

public class InterfaceMainTest01 {
    public static void main(String[] args) {

        /**
         * 知识点1
         * 接口中声明的静态方法只能被接口来调用,不能使用其实现类调用。
         */
        InterfaceTest01.method1();
        System.out.println("--------------");
        /**
         * 知识点2
         * 接口中声明的默认方法可以被实现类继承,实现类在没有重写此方法的情况下,默认调用接口中声明的默认方法。
         * 如果实现类重写了此方法,则调用的是自己重写的方法。
         */
        SubClassTest01 subClassTest01 = new SubClassTest01();
        //调用接口中声明的默认方法
        subClassTest01.method21();
        //调用子类中重写的接口默认方法
        subClassTest01.method22();
        System.out.println("--------------");
        /**
         * 知识点3:接口冲突
         * 类实现了两个接口。
         * 而两个接口中定义了同名同参数的默认方法,则实现类在没有重写此两个接口默认方法的前提下,会报错。
         * 要求:此时实现类必须要重写接口中定义的同名同参数的方法。
         * 既看做是对A的重写,也看做是对B的重写。
         */
        SubClassTest02 subClassTest02 = new SubClassTest02();
        subClassTest02.method3();
        System.out.println("--------------");
        /**
         * 知识点4:类优先原则(类和接口的地位不同)
         * 子类/实现类继承了父类并实现了接口。
         * 父类和接口中声明了同名同参数的方法(其中,接口中的方法是default默认方法)。
         * 默认情况下,子类/实现类在没有重写此方法的情况下,调用的是父类中的方法。
         */
        SubClassTest03 subClassTest03 = new SubClassTest03();
        subClassTest03.method4();
        System.out.println("--------------");
        /**
         * 知识点5
         * 在子类中调用自己类中的方法。
         * 在子类中调用父类中(被重写)的方法。
         * 在子类中调用接口中(被重写)的方法。
         */
        SubClassTest04 subClassTest04 = new SubClassTest04();
        subClassTest04.testMethod5();

    }
}

静态/默认/子类重写/多接口相同方法

package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 2:12
 * @Modified:
 */

public interface InterfaceTest01 {

    /**
     * JDK8:静态方法
     */
    public static void method1(){
        System.out.println("InterfaceTest01:static method1()");
    }

    /**
     * JDK8:默认方法
     */
    public default void method21(){
        System.out.println("InterfaceTest01:default method21()");
    }

    /**
     * JDK8:默认方法-用于子类重写
     */
    public default void method22(){
        System.out.println("InterfaceTest01:default method22()");
    }

    /**
     * JDK8:实现多接口同样的方法
     */
    public default void method3(){
        System.out.println("InterfaceTest01:default method3()");
    }


}
package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 2:12
 * @Modified:
 */

public interface InterfaceTest02 {

    /**
     * JDK8:实现多接口同样的方法
     */
    public default void method3(){
        System.out.println("InterfaceTest02:default method3()");
    }


}
package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 2:29
 * @Modified:
 */

public class SubClassTest01 implements InterfaceTest01{

    /**
     * JDK8:默认方法-用于子类重写
     */
    @Override
    public void method22() {
        System.out.println("SubClassTest01:default method22()");
    }
}
package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 3:20
 * @Modified:
 */

public class SubClassTest02 implements InterfaceTest01,InterfaceTest02{

    /**
     * 接口冲突:
     * 类实现了两个接口。
     * 而两个接口中定义了同名同参数的默认方法,则实现类在没有重写此两个接口默认方法的前提下,会报错。
     * 要求:此时实现类必须要重写接口中定义的同名同参数的方法。
     * 既看做是对A的重写,也看做是对B的重写。
     */
    @Override
    public void method3() {
        System.out.println("SubClassTest02:default method3()");
    }

}

类优先原则

package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 3:37
 * @Modified:
 */

public interface InterfaceTest03 {

    /**
     * JDK8:类优先原则(类和接口的地位不同)
     * 子类/实现类继承了父类并实现了接口。
     * 父类和接口中声明了同名同参数的方法(其中,接口中的方法是default默认方法)。
     * 默认情况下,子类/实现类在没有重写此方法的情况下,调用的是父类中的方法。
     */
    public default void method4(){
        System.out.println("InterfaceTest03:default method4()");
    }

}
package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 3:38
 * @Modified:
 */

public class SuperClassTest01{

    /**
     * JDK8:类优先原则(类和接口的地位不同)
     * 子类/实现类继承了父类并实现了接口。
     * 父类和接口中声明了同名同参数的方法(其中,接口中的方法是default默认方法)。
     * 默认情况下,子类/实现类在没有重写此方法的情况下,调用的是父类中的方法。
     */
    public void method4() {
        System.out.println("SuperClassTest01:default method4()");
    }

}


package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 3:44
 * @Modified:
 */

public class SubClassTest03 extends SuperClassTest01 implements InterfaceTest03{

    /**
     * JDK8:类优先原则(类和接口的地位不同)
     * 子类/实现类继承了父类并实现了接口。
     * 父类和接口中声明了同名同参数的方法(其中,接口中的方法是default默认方法)。
     * 默认情况下,子类/实现类在没有重写此方法的情况下,调用的是父类中的方法。
     */

}

子类(父类/接口)调用

package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 3:37
 * @Modified:
 */

public interface InterfaceTest04 {

    /**
     * 在子类中调用自己类中的方法。
     * 在子类中调用父类中(被重写)的方法。
     * 在子类中调用接口中(被重写)的方法。
     */
    public default void method5(){
        System.out.println("InterfaceTest04:default method5()");
    }

}
package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 3:37
 * @Modified:
 */

public interface InterfaceTest05 {

    /**
     * 在子类中调用自己类中的方法。
     * 在子类中调用父类中(被重写)的方法。
     * 在子类中调用接口中(被重写)的方法。
     */
    public default void method5(){
        System.out.println("InterfaceTest05:default method5()");
    }

}
package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 3:38
 * @Modified:
 */

public class SuperClassTest02 {

    /**
     * 在子类中调用自己类中的方法。
     * 在子类中调用父类中(被重写)的方法。
     * 在子类中调用接口中(被重写)的方法。
     */
    public void method5() {
        System.out.println("SuperClassTest02:default method5()");
    }

}
package com.feature.jdk8.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 3:44
 * @Modified:
 */

public class SubClassTest04 extends SuperClassTest02 implements InterfaceTest04,InterfaceTest05{

    /**
     * 在子类中调用自己类中的方法。
     * 在子类中调用父类中(被重写)的方法。
     * 在子类中调用接口中(被重写)的方法。
     */
    @Override
    public void method5() {
        System.out.println("SubClassTest04:default method5()");
    }

    public void testMethod5(){

        //在子类中调用自己类中的方法
        method5();
        //在子类中调用父类中(被重写)的方法
        super.method5();
        //在子类中调用接口中(被重写)的方法
        InterfaceTest04.super.method5();
        InterfaceTest05.super.method5();

    }


}

Optional(JDK8-11)

package com.feature.jdk8.optional;

import java.util.Optional;

/**
 * @Author: yalong
 * @Description: Optional
 * JDK8新特性
 * JDK9-JDK11新增一些方法
 *
 * Google在著名的guava项目中引入了Optional类,通过检查空值的方式避免空指针异常。
 * Optional<T>是一个容器类,可保存T的值,代表这个值存在,或者仅保存null,表示这个值不存在。
 * @Date: Created in 2023/5/6 2:07
 * @Modified:
 */

public class OptionalTest01 {

    public static void main(String[] args) {

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

        String str = "teststr";
        //实例化
        Optional<String> optional1 = Optional.ofNullable(str);
        String otherStr = "otherstr";
        //不为空输出str,否则输出otherStr。
        String finalStr1 = optional1.orElse(otherStr);
        System.out.println(finalStr1);
        str = null;
        Optional<String> optional2 = Optional.ofNullable(str);
        String finalStr2 = optional2.orElse(otherStr);
        System.out.println(finalStr2);

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

        //空抛出异常
        try {
            optional2.orElseThrow(() -> new RuntimeException(".......RuntimeException........."));
        }catch (Exception e){
            e.printStackTrace();
        }

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

        optional1.ifPresentOrElse(s -> System.out.println("success : " + s),() -> System.out.println("null : open new thread."));
        optional2.ifPresentOrElse(s -> System.out.println("success : " + s),() -> System.out.println("null : open new thread."));

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

        Optional<String> optional3 = Optional.of("test2val");
        System.out.println(optional3.get());

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

        Optional<String> optional4 = Optional.ofNullable(null);

        System.out.println(optional4.isEmpty());

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

        Optional<String> optional5 = Optional.empty();

        System.out.println(optional5);

    }

}

====案例开始JDK9部分

接口私有方法

package com.feature.jdk9.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 4:15
 * @Modified:
 */

public interface InterfaceTest01 {

    public default void method1(){
        System.out.println("InterfaceTest01:method1() before");
        testMethod();
        System.out.println("InterfaceTest01:method1() after");
    }

    public default void method2(){
        System.out.println("InterfaceTest01:method2() before");
        testMethod();
        System.out.println("InterfaceTest01:method2() after");
    }
    /**
     * JDK9
     * 接口中可以定义私有方法,但实现类不能实现接口中的私有方法。
     */
    private void testMethod(){
        System.out.println("InterfaceTest01:private testMethod()");
    }

}
package com.feature.jdk9.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 4:16
 * @Modified:
 */

public class SubClassTest01 implements InterfaceTest01{

    /**
     * JDK9
     * 接口中可以定义私有方法,但实现类不能实现接口中的私有方法。
     */
}
package com.feature.jdk9.interfacetest;

/**
 * @Author: yalong
 * @Description: 接口
 * 接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样,制定好之后都要遵守。
 * 定义接口的关键字:interface
 * 接口内部结构的说明:
 *      可以声明:
 *          属性:必须使用public static final修饰
 *          方法:
 *              JDK8之前,声明抽象方法,修饰为public abstract
 *              JDK8声明静态方法、默认方法
 *              JDK9声明私有方法,但实现类不能实现接口中的私有方法。
 *      不可以声明:
 *          构造器、代码块等。
 * 接口与类的关系:实现关系
 * 格式: class A extends SuperA implements B,C{}
 * @Date: Created in 2023/5/8 4:17
 * @Modified:
 */

public class InterfaceMainTest01 {

    public static void main(String[] args) {

        /**
         * JDK9
         * 接口中可以定义私有方法,但实现类不能实现接口中的私有方法。
         */
        SubClassTest01 subClassTest01 = new SubClassTest01();
        subClassTest01.method1();
        System.out.println("-------------");
        subClassTest01.method2();

    }

}

JSHELL

可在DOS环境中执行,交互式编程环境。

利用jShell在没有创建类的情况下,在命令行里直接声明变量,计算表达式,执行语句。

image.png

image.png

package com.feature.jdk9.jshell;

/**
 * @Author: yalong
 * @Description: jShell
 * 以交互式的方式对语句和表达式进行求值。
 * 利用jShell在没有创建类的情况下,在命令行里直接声明变量,计算表达式,执行语句。
 * @Date: Created in 2023/5/4 10:25
 * @Modified:
 */

public class JShellTest01 {

    public static void main(String[] args) {

        /**
         *
         * D:\software\windows\install\Java\jdk-17\bin>jshell.exe
         * |  欢迎使用 JShell -- 版本 17.0.6
         * |  要大致了解该版本, 请键入: /help intro
         *
         * jshell> int m = 10;
         * m ==> 10
         *
         * jshell> int n = 20;
         * n ==> 20
         *
         * jshell> System.out.println(m + n);
         * 30
         *
         * jshell> System.out.println("hello world!");
         * hello world!
         *
         * jshell> public int add(int m,int n){return m + n;}
         * |  已创建 方法 add(int,int)
         *
         * jshell> int result = add(22,11);
         * result ==> 33
         *
         * jshell> System.out.println(result);
         * 33
         *
         * jshell> /help
         *
         */

    }

}

TRY-CATCH

JDK7-try(声明对象并初始化)自动释放

package com.feature.jdk9.trycatch;

import java.io.*;

/**
 * @Author: yalong
 * @Description: JDK7新特性
 * 在try后面可以增加一个括号(),在括号中可以声明流对象并初始化。
 * try的代码执行完毕(声明的资源无论是否处理/发生异常),都会自动把流/资源对象关闭/释放,就不用手工关闭/写finally了。
 *
 * 这些资源实现类必须实现AutoCloseable或Closeable接口,实现其中的close()。Closeable extends AutoCloseable。
 *
 * @Date: Created in 2023/5/4 10:41
 * @Modified:
 */

public class TryCatchTest01 {

    public static void main(String[] args) {

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

        test1();

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

        test2();

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

    }

    /**
     * 案例一
     * JDK7之前的写法
     * 从A文件中读取内容写入B文件中。
     */
    private static void test1(){
        BufferedReader bufferedReader1 = null;
        BufferedWriter bufferedWriter1 = null;
        try {
            FileInputStream fileInputStream1 = new FileInputStream("test11.txt");
            InputStreamReader inputStreamReader1 = new InputStreamReader(fileInputStream1,"utf-8");
            bufferedReader1 = new BufferedReader(inputStreamReader1);

            FileOutputStream fileOutputStream1 = new FileOutputStream("test12.txt");
            OutputStreamWriter outputStreamWriter1 = new OutputStreamWriter(fileOutputStream1,"gbk");
            bufferedWriter1 = new BufferedWriter(outputStreamWriter1);

            String str;
            while((str = bufferedReader1.readLine()) != null){
                bufferedWriter1.write(str);
                bufferedWriter1.newLine();
                bufferedWriter1.flush();
            }

        } catch (FileNotFoundException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        } catch (IOException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        } finally {
            try {
                if(bufferedWriter1 != null){
                    bufferedWriter1.close();
                }
            } catch (IOException e) {
                //throw new RuntimeException(e);
                e.printStackTrace();
            }

            try {
                if(bufferedReader1 != null) {
                    bufferedReader1.close();
                }
            } catch (IOException e) {
                //throw new RuntimeException(e);
                e.printStackTrace();
            }
        }
    }


    /**
     * 案例二
     * JDK7中的写法
     * 从A文件中读取内容写入B文件中。
     */
    private static void test2(){

        try(
                FileInputStream fileInputStream2 = new FileInputStream("test21.txt");
                InputStreamReader inputStreamReader2 = new InputStreamReader(fileInputStream2,"utf-8");
                BufferedReader bufferedReader2 = new BufferedReader(inputStreamReader2);

                FileOutputStream fileOutputStream2 = new FileOutputStream("test22.txt");
                OutputStreamWriter outputStreamWriter2 = new OutputStreamWriter(fileOutputStream2,"gbk");
                BufferedWriter bufferedWriter2 = new BufferedWriter(outputStreamWriter2);
        ){

                String str;
                while((str = bufferedReader2.readLine()) != null){
                    bufferedWriter2.write(str);
                    bufferedWriter2.newLine();
                    bufferedWriter2.flush();
                }

        } catch (FileNotFoundException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        } catch (IOException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        }

    }


}

JDK9-try(引用对象)自动释放

package com.feature.jdk9.trycatch;

import java.io.*;

/**
 * @Author: yalong
 * @Description: JDK9新特性
 * try前面直接定义流对象,try后面的括号()可以直接引用流对象的名称。
 * try的代码执行完毕,都会自动把流/资源对象关闭/释放,就不用手工关闭/写finally了。
 * 这些资源实现类必须实现AutoCloseable或Closeable接口,实现其中的close()。Closeable extends AutoCloseable。
 *
 * TODO 以下try(X)中的X对象都是final的,不能再被赋值。
 *
 * @Date: Created in 2023/5/4 12:02
 * @Modified:
 */

public class TryCatchTest02 {

    //public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
    public static void main(String[] args) throws IOException {

        FileInputStream fileInputStream3 = new FileInputStream("test31.txt");
        InputStreamReader inputStreamReader3 = new InputStreamReader(fileInputStream3,"utf-8");
        BufferedReader bufferedReader3 = new BufferedReader(inputStreamReader3);

        FileOutputStream fileOutputStream3 = new FileOutputStream("test32.txt");
        OutputStreamWriter outputStreamWriter3 = new OutputStreamWriter(fileOutputStream3,"gbk");
        BufferedWriter bufferedWriter3 = new BufferedWriter(outputStreamWriter3);

        try(
                fileInputStream3;inputStreamReader3;bufferedReader3;
                fileOutputStream3;outputStreamWriter3;bufferedWriter3
        ){

            String str;
            while((str = bufferedReader3.readLine()) != null){
                bufferedWriter3.write(str);
                bufferedWriter3.newLine();
                bufferedWriter3.flush();
            }

        } catch (IOException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        }

    }

}

Iterator

package com.feature.jdk9.iterator;

import java.util.stream.Stream;

/**
 * @Author: yalong
 * @Description: Stream实例化方法:iterator()的使用
 * @Date: Created in 2023/5/4 10:04
 * @Modified:
 */

public class IteratorTest01 {

    public static void main(String[] args) {
        //控制终止方式,之前并没有中间的条件"i -> i < 100"
        Stream.iterate(1,i -> i < 100, i -> i + 1).forEach(System.out :: println);
        Stream.iterate(10,i -> i > 2, i -> i - 1).forEach(System.out :: println);
    }

}

String-char[]改为byte[]

package com.feature.jdk9.string;

/**
 * @Author: yalong
 * @Description: String修改char[]改成使用byte[]存储
 * 跟字符串相关的类StringBuilder和StringBuffer也同样修改
 * @Date: Created in 2023/5/6 0:48
 * @Modified:
 */

public class StringTest01 {

    public static void main(String[] args) {

        String str = new String("teststr");
        System.out.println(str);
        StringBuffer stringBuffer = new StringBuffer("stringBuffer");
        System.out.println(stringBuffer);
        StringBuilder stringBuilder = new StringBuilder("stringBuilder");
        System.out.println(stringBuilder);
    }

}

Stream.ofNullable(X)

package com.feature.jdk9.ofnullable;

import java.sql.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

/**
 * @Author: yalong
 * @Description: Stream实例化方法:ofNullable()的使用
 * java8中的Stream不能完全为null,否则会报空指针异常。
 * 而java9中的ofNullable()方法允许我们创建一个单元素Stream,可以包含一个非空元素,也可以创建一个空Stream。
 * @Date: Created in 2023/5/4 8:13
 * @Modified:
 */

public class OfNullAbleTest01 {

    public static void main(String[] args) {

        //不报异常,允许通过。
        Stream<String> stringStream1 = Stream.of("A","B",null);
        System.out.println(stringStream1.count());
        System.out.println("---------------------------------------");
        //不报异常,允许通过。
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add(null);
        System.out.println(list.stream().count());
        System.out.println("---------------------------------------");
        Stream<Object> objectStream = Stream.ofNullable(null);
        System.out.println(objectStream.count());
        System.out.println("---------------------------------------");
        Stream<String> stringStream2 = Stream.ofNullable("A");
        System.out.println(stringStream2.count());
        System.out.println("---------------------------------------");
        Stream<String> stringStream3 = Stream.ofNullable(null);
        //加get()报错:"No value present"
        //System.out.println(stringStream3.map(s -> s).filter(String :: isBlank).findFirst().get());
        //这里不加get()输出:"Optional.empty"
        System.out.println(stringStream3.map(s -> s).filter(String :: isBlank).findFirst());
        System.out.println("---------------------------------------");



    }

}

====案例开始JDK10部分

var

package com.feature.jdk10;

import java.util.ArrayList;
import java.util.LinkedHashSet;

/**
 * @Author: yalong
 * @Description: JDK10的新特性
 * 使用var来省略通常不必要的局部变量类型声明。
 *
 * 不适用场景:
 * 声明一个成员变量。
 * 声明一个数组变量,并为数组静态初始化(省略new的情况下)。
 * 方法的返回值类型。
 * 方法的参数类型。
 * 没有初始化的方法内的局部变量声明。
 * 作为catch块中异常类型。
 * lambda表达式中函数式接口的类型。
 * 方法引用中函数式接口的类型。
 * 
 * @Date: Created in 2023/5/4 12:12
 * @Modified:
 */

public class VarTest01 {

    public static void main(String[] args) {

        //局部变量的实例化
        var list = new ArrayList<>();
        var set = new LinkedHashSet<>();

        //增强for循环中的索引
        for(var v : list){
            System.out.println(v);
        }

        //传统for循环中
        for(var i = 0;i < 10;i++){
            System.out.println(i);
        }

        //返回值类型复杂泛型结构
        //Iterator<Map.Entry<Integer,String>> iterator = set.iterator();
        var iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }


}

====案例开始JDK11部分

编译运行

package com.feature.jdk11.run;

/**
 * @Author: yalong
 * @Description:
 * 可以不通过"javac X.java和java X"来编译运行java文件。
 * 可直接通过"java X.java"来编译运行java文件。
 * @Date: Created in 2023/5/6 2:55
 * @Modified:
 */

新增String处理方法

package com.feature.jdk11.string;

/**
 * @Author: yalong
 * @Description: JDK11新特性
 * 新增String处理方法
 * @Date: Created in 2023/5/6 0:55
 * @Modified:
 */

public class StringTest01 {

    public static void main(String[] args) {

        System.out.println("判断字符串是否为空白:" + " ".isBlank());
        System.out.println("去除首尾空白:" + " jav a ".strip());
        System.out.println("去除尾部空格:" + " jav a ".stripTrailing());
        System.out.println("去除首部空格:" + " jav a ".stripLeading());
        System.out.println("复制3次字符串在一行:" + " jav a ".repeat(3));
        System.out.println("行数统计(注意'\\n'前面有一行):" + "\nA\nB\nC".lines().count());

    }

}

====案例开始JDK12部分

String实现Constable接口/Optional.of(this)

package com.feature.jdk12;

import java.util.Optional;

/**
 * @Author: yalong
 * @Description: JDK12新特性
 *
 * public final class String
 *     implements java.io.Serializable, Comparable<String>, CharSequence,
 *                Constable, ConstantDesc {
 * ......
 *     @Override
 *     public Optional<String> describeConstable() {
 *         return Optional.of(this);
 *     }
 * ......
 * }
 *
 * 多实现了Constable接口,体现了String是一个常量。
 * public interface Constable {
 *     Optional<? extends ConstantDesc> describeConstable();
 * }
 * 实际上返回的是Optional.of(this);的Optional对象。
 *
 * @Date: Created in 2023/5/6 2:31
 * @Modified:
 */

public class StringOptionalTest01 {

    public static void main(String[] args) {
        String str = "teststrval";
        Optional<String> optional = str.describeConstable();
        System.out.println(optional.get());
    }

}

String新增transform(x)/map(x)

package com.feature.jdk12;

import java.sql.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: yalong
 * @Description: JDK12特性
 * String新增的方法transform
 * @Date: Created in 2023/5/6 2:39
 * @Modified:
 */

public class StringTest02 {

    public static void main(String[] args) {

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

        var result1 = "foo".transform(s -> s + " bar");
        System.out.println(result1);
        var result2 = "foo".transform(s -> s + " bar").transform(String :: toUpperCase);
        System.out.println(result2);

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

        //在某种情况下,该方法应该被称为map。
        List<String> list11 = List.of("java","c","python","c++");
        List<String> list12 = new ArrayList<>(4);
        list11.forEach(s -> list12.add(s.transform(String :: strip).transform(String :: toUpperCase).transform(s1 -> "\nHello : " + s1)));
        list12.forEach(System.out :: print);

        System.out.println("\n------------------------------");

        List<String> list21 = List.of("java","c","python","c++");
        Stream<String> stream22 = list21.stream()
                                            .map(String :: strip)
                                            .map(String :: toUpperCase)
                                            .map(s -> "\nhi:" + s);
        List<String> list22 = stream22.collect(Collectors.toList());
        list22.forEach(System.out :: print);

        System.out.println("\n------------------------------");


    }

}

====案例开始JDK15部分

文本块(JDK13-15)

package com.feature.jdk15;

/**
 * @Author: yalong
 * @Description: 文本块
 * JDK13的预览特性
 * JDK14中的二次预览特性
 * JDK15中的功能转正
 * @Date: Created in 2023/5/5 9:00
 * @Modified:
 */

public class TextBlockTest01 {

    public static void main(String[] args) {
        System.out.println("-------------HTML--------------");
        test1();
        System.out.println("-------------JSON--------------");
        test2();
        System.out.println("-------------SQL---------------");
        test3();
        System.out.println("-------------SQL-JDK14新特性--------------");
        /**
         * JDK14新特性
         * \    取消换行操作
         * \s   表示一个空格
         */
        String JDK14_SQL = """
                SELECT id,name,address
                FROM USER\s\
                WHERE id = 1\s\
                ORDER BY id DESC   
                """;
        System.out.println("JDK14_SQL: \n" + JDK14_SQL);

    }

    /**
     * 案例一:html
     * \n + 与   """
     */
    private static void test1(){
        String info1 = "<html>\n" +
                "   <body>\n" +
                "       <p>hello,world!</p>\n" +
                "   </body>\n" +
                "</html>";
        System.out.println("info1 : \n" + info1);
        System.out.println("-----------");
        String info2 = """
                <html>
                   <body>
                       <p>hello,world!</p>
                   </body>
                </html>
                """;
        System.out.println("info2 : \n" + info2);
    }

    /**
     * 案例二:json
     * \n + 与   """
     */
    private static void test2(){

        String info1 =
                "{\n" +
                    "   \"name\":\"testname\",\n" +
                    "   \"address\":\"beijing\"\n" +
                "}"
                ;
        System.out.println("info1 : \n" + info1);
        System.out.println("-----------");
        String info2 = """
                {
                    "name":"testname",
                    "address":"beijing"
                }
                """;
        System.out.println("info2 : \n" + info2);

    }


    /**
     * 案例三:sql
     * \n + 与   """
     */
    private static void test3(){

        String info1 =
                        "SELECT\n" +
                        "    id,name,address\n" +
                        "FROM\n" +
                        "    USER\n" +
                        "WHERE\n" +
                        "    id = 1\n" +
                        "ORDER BY id DESC    "
                ;
        System.out.println("info1 : \n" + info1);
        System.out.println("-----------");
        String info2 = """
                SELECT
                    id,name,address
                FROM
                    USER
                WHERE
                    id = 1
                ORDER BY id DESC        
                """;
        System.out.println("info2 : \n" + info2);

    }

}

====案例开始JDK16部分

Instanceof(JDK14-16)

package com.feature.jdk16.instanceoftest;

/**
 * @Author: yalong
 * @Description:
 * JDK14预览特性
 * JDK15第二次预览
 * JDK16转正特性
 * @Date: Created in 2023/5/4 19:37
 * @Modified:
 */

public class InstanceOfTest01 {

    public static void main(String[] args) {

        /**
         * JDK14之前:先判断类型然后转换。
         */
        Object obj1 = new String("hello,world.");
        if(obj1 instanceof String){
            String str = (String) obj1;
            System.out.println(str.contains("hello"));
        }else{
            System.out.println("非String类型。");
        }

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

        /**
         * JDK14之后:自动匹配模式。
         */
        Object obj2 = new String("helloWorld");
        if(obj2 instanceof String str){
            System.out.println(str.contains("World"));
        }else{
            System.out.println("非String类型。");
        }

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

    }

}
package com.feature.jdk16.instanceoftest;

/**
 * @Author: yalong
 * @Description:
 * JDK14预览特性
 * JDK15第二次预览
 * JDK16转正特性
 * @Date: Created in 2023/5/4 19:54
 * @Modified:
 */

public class InstanceOfTest02 {

    private String model;
    private double price;

    //JDK14之前
    public boolean equals1(Object obj) {
        if(obj instanceof InstanceOfTest02){
            InstanceOfTest02 other = (InstanceOfTest02) obj;
            if(this.model.equals(other.model) && this.price == other.price){
                return true;
            }
        }
        return false;
    }

    //JDK14之后
    public boolean equals2(Object obj) {
        if(obj instanceof InstanceOfTest02 other){
            return this.model.equals(other.model) && this.price == other.price;
        }
        return false;
    }
  
}

record类(JDK14-16)

普通类与record类

package com.feature.jdk16.recordtest;

import java.util.Objects;

/**
 * @Author: yalong
 * @Description: record
 *
 * JDK14预览特性
 * JDK15第二次预览特性
 * JDK16转正特性
 *
 * record全新类型,本质上是final类,同时所有的属性都是final修饰。
 * 实现简单的数据载体类,为避免编写:构造函数(只有一个)、访问器、get(区别普通类)、set、equals()、hashcode()、toString()等,减少代码量。
 *
 * record的设计目标是提供一种将数据建模为数据的好方法。
 * 它也不是javabeans的直接替代品,因为record的方法不符合Javabeans的get标准。
 * 另外,Javabeans通常是可变的,而记录是不可变的。
 * 尽管它们的用途有点像,但记录并不会以某种方式取代javabeans。
 *
 * 可在record中定义静态字段。
 * 可在record中定义静态方法。
 * 可在record中定义构造器。
 * 可在record中定义实例方法。
 * 不能在record中定义实例字段。
 * record类不能声明为abstract。
 * record类不能显示的声明父类,因为有明确的父类Record,就不能再指定了(enum父类Enum同理)。当然定义子类也不行。
 *
 * @Date: Created in 2023/5/5 11:36
 * @Modified:
 */

public class RecordOrderTest01 {

    private final int orderId;
    private final String orderName;

    public RecordOrderTest01(int orderId, String orderName) {
        this.orderId = orderId;
        this.orderName = orderName;
    }

    public int getOrderId() {
        return orderId;
    }

    public String getOrderName() {
        return orderName;
    }

    @Override
    public boolean equals(Object obj){
        if(this == obj){
            return true;
        }
        if(obj == null || getClass() != obj.getClass()){
            return false;
        }
        RecordOrderTest01 order = (RecordOrderTest01)obj;
        return getOrderId() == order.getOrderId() && Objects.equals(getOrderName(),order.getOrderName());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getOrderId(),getOrderName());
    }

    @Override
    public String toString() {
        return "RecordOrderTest01{" +
                "orderId=" + orderId +
                ", orderName='" + orderName + '\'' +
                '}';
    }

}
package com.feature.jdk16.recordtest;

/**
 * @Author: yalong
 * @Description: record
 *
 * JDK14预览特性
 * JDK15第二次预览特性
 * JDK16转正特性
 *
 * record全新类型,本质上是final类,同时所有的属性都是final修饰。
 * 实现简单的数据载体类,为避免编写:构造函数(只有一个)、访问器、get(区别普通类)、set、equals()、hashcode()、toString()等,减少代码量。
 *
 * record的设计目标是提供一种将数据建模为数据的好方法。
 * 它也不是javabeans的直接替代品,因为record的方法不符合Javabeans的get标准。
 * 另外,Javabeans通常是可变的,而记录是不可变的。
 * 尽管它们的用途有点像,但记录并不会以某种方式取代javabeans。
 *
 * 可在record中定义静态字段。
 * 可在record中定义静态方法。
 * 可在record中定义构造器。
 * 可在record中定义实例方法。
 * 不能在record中定义实例字段。
 * record类不能声明为abstract。
 * record类不能显示的声明父类,因为有明确的父类Record,就不能再指定了(enum父类Enum同理)。当然定义子类也不行。
 *
 * @Date: Created in 2023/5/5 11:21
 * @Modified:
 */

public record RecordTest01(int orderId, String orderName) {
}
package com.feature.jdk16.recordtest;

import java.util.HashSet;

/**
 * @Author: yalong
 * @Description: record
 *
 * JDK14预览特性
 * JDK15第二次预览特性
 * JDK16转正特性
 *
 * record全新类型,本质上是final类,同时所有的属性都是final修饰。
 * 实现简单的数据载体类,为避免编写:构造函数(只有一个)、访问器、get(区别普通类)、set、equals()、hashcode()、toString()等,减少代码量。
 *
 * record的设计目标是提供一种将数据建模为数据的好方法。
 * 它也不是javabeans的直接替代品,因为record的方法不符合Javabeans的get标准。
 * 另外,Javabeans通常是可变的,而记录是不可变的。
 * 尽管它们的用途有点像,但记录并不会以某种方式取代javabeans。
 *
 * 可在record中定义静态字段。
 * 可在record中定义静态方法。
 * 可在record中定义构造器。
 * 可在record中定义实例方法。
 * 不能在record中定义实例字段。
 * record类不能声明为abstract。
 * record类不能显示的声明父类,因为有明确的父类Record,就不能再指定了(enum父类Enum同理)。当然定义子类也不行。
 *
 * @Date: Created in 2023/5/5 21:43
 * @Modified:
 */

public class RecordMainTest01 {

    public static void main(String[] args) {

        test1();
        System.out.println("---------------------------------");
        test2();
        System.out.println("---------------------------------");
        test3();

    }

    private static void test1(){

        RecordOrderTest01 recordOrder1 = new RecordOrderTest01(1001,"orderA");
        System.out.println(recordOrder1);
        System.out.println(recordOrder1.getOrderId());
        System.out.println(recordOrder1.getOrderName());

        RecordOrderTest01 recordOrder2 = new RecordOrderTest01(1001,"orderA");
        System.out.println(recordOrder1.equals(recordOrder2));

        HashSet<RecordOrderTest01> set = new HashSet<>(2);
        set.add(recordOrder1);
        set.add(recordOrder2);
        System.out.println(set);

    }

    private static void test2(){

        RecordTest01 record1 = new RecordTest01(1002,"orderB");
        System.out.println(record1);
        System.out.println(record1.orderId());
        System.out.println(record1.orderName());

        RecordTest01 record2 = new RecordTest01(1002,"orderB");
        System.out.println(record2.equals(record1));

        HashSet<RecordTest01> set = new HashSet<>(2);
        set.add(record1);
        set.add(record2);
        System.out.println(set);

    }

    /**
     * record类不能显示的声明父类,因为有明确的父类Record,就不能再指定了(enum父类Enum同理)。具体原因看RecordMainTest01。
     */
    private static void test3(){

        Class<RecordTest02> clazz1 = RecordTest02.class;
        //class java.lang.Record
        System.out.println(clazz1.getSuperclass());
        System.out.println("--------------");
        Class<RecordEnumTest01> clazz2 = RecordEnumTest01.class;
        //class java.lang.Enum
        System.out.println(clazz2.getSuperclass());

    }


}

获取record/enum父类与record定义规则

package com.feature.jdk16.recordtest;

/**
 * @Author: yalong
 * @Description: record
 *
 * JDK14预览特性
 * JDK15第二次预览特性
 * JDK16转正特性
 *
 * record全新类型,本质上是final类,同时所有的属性都是final修饰。
 * 实现简单的数据载体类,为避免编写:构造函数(只有一个)、访问器、get(区别普通类)、set、equals()、hashcode()、toString()等,减少代码量。
 *
 * record的设计目标是提供一种将数据建模为数据的好方法。
 * 它也不是javabeans的直接替代品,因为record的方法不符合Javabeans的get标准。
 * 另外,Javabeans通常是可变的,而记录是不可变的。
 * 尽管它们的用途有点像,但记录并不会以某种方式取代javabeans。
 *
 * 可在record中定义静态字段。
 * 可在record中定义静态方法。
 * 可在record中定义构造器。
 * 可在record中定义实例方法。
 * 不能在record中定义实例字段。
 * record类不能声明为abstract。
 * record类不能显示的声明父类,因为有明确的父类Record,就不能再指定了(enum父类Enum同理)。当然定义子类也不行。
 *
 * @Date: Created in 2023/5/5 22:38
 * @Modified:
 */

public enum RecordEnumTest01{
}


package com.feature.jdk16.recordtest;

/**
 * @Author: yalong
 * @Description: record
 *
 * JDK14预览特性
 * JDK15第二次预览特性
 * JDK16转正特性
 *
 * record全新类型,本质上是final类,同时所有的属性都是final修饰。
 * 实现简单的数据载体类,为避免编写:构造函数(只有一个)、访问器、get(区别普通类)、set、equals()、hashcode()、toString()等,减少代码量。
 *
 * record的设计目标是提供一种将数据建模为数据的好方法。
 * 它也不是javabeans的直接替代品,因为record的方法不符合Javabeans的get标准。
 * 另外,Javabeans通常是可变的,而记录是不可变的。
 * 尽管它们的用途有点像,但记录并不会以某种方式取代javabeans。
 *
 * 可在record中定义静态字段。
 * 可在record中定义静态方法。
 * 可在record中定义构造器。
 * 可在record中定义实例方法。
 * 不能在record中定义实例字段。
 * record类不能声明为abstract。
 * record类不能显示的声明父类,因为有明确的父类Record,就不能再指定了(enum父类Enum同理)。当然定义子类也不行。
 *
 * @Date: Created in 2023/5/5 22:20
 * @Modified:
 */

public record RecordTest02(int id,String name) {

    //可在record中定义静态字段
    static String info = "info";

    //可在record中定义静态方法
    public static void show(){
        System.out.println("show()");
    }

    //可在record中定义构造器
    public RecordTest02() {
        this(1,"name");
    }
    //可在record中定义构造器
    public RecordTest02(int id, String name) {
        this.id = id;
        this.name = name;
    }

    //可在record中定义实例方法
    @Override
    public boolean equals(Object obj) {
        return false;
    }
    //可在record中定义实例方法
    @Override
    public int hashCode() {
        return 0;
    }
    //可在record中定义实例方法
    @Override
    public String toString() {
        return null;
    }

    //不能在record中定义实例字段
    //private final int num;

}
//record类不能声明为abstract
//abstract record RecordAbstractTest02(int id){}
//record类不能显示的声明父类,因为有明确的父类Record,就不能再指定了(enum父类Enum同理)。当然定义子类也不行。具体原因看RecordMainTest01。
//record RecordAbstractTest03 extends Thread(){}
//record类不能显示的声明父类,因为有明确的父类Record,就不能再指定了(enum父类Enum同理)。当然定义子类也不行。具体原因看RecordMainTest01。
//record RecordAbstractTest04 extends RecordTest02{}

====案例开始JDK17部分

AppletAPI

package com.feature.jdk17.applet;

/**
 * @Author: yalong
 * @Description: AppletAPI
 * JDK9标记为过时。
 * JDK17标记为删除。
 * @Date: Created in 2023/5/6 2:57
 * @Modified:
 */

Switch表达式

传统switch

package com.feature.jdk17.switchtest;

/**
 * @Author: yalong
 * @Description:
 * JDK12预览特性:switch表达式
 * JDK13二次预览特性:switch表达式
 * JDK14转正特性:switch表达式
 * JDK17预览特性:switch的模式匹配
 * @Date: Created in 2023/5/5 5:09
 * @Modified:
 */

public class SwitchTest01 {

    /**
     * 传统switch语句
     * @param args
     */
    public static void main(String[] args) {

        //正确实现
        test1();
        System.out.println("-------------------------------------");
        //错误实现
        test2();

    }

    private static void test1(){
        SwitchTest01Enum01 day = SwitchTest01Enum01.FRIDAY;
        switch(day){
            case MONDAY:
                int num = 1;
                System.out.println(1);
                break;
            case TUESDAY:
                //变量名不能重复
                //String num = "";
                System.out.println(2);
            case WEDNESDAY:
                System.out.println(3);
            case THURSDAY:
                System.out.println(4);
                break;
            case FRIDAY:
                System.out.println(5);
                break;
            case SATURDAY:
                System.out.println(6);
            case SUNDAY:
                System.out.println(7);
                break;
            default:
                throw new RuntimeException("what day is today?" + day);

        }
    }

    private static void test2(){

        SwitchTest01Enum01 day = SwitchTest01Enum01.FRIDAY;
        switch(day.ordinal()){
            case 1|2|3://这里使用的位运算,下述同理
                int num = 1;
                System.out.println(1);
                break;
            case 4|5|6:
                //变量名不能重复
                //String num = "";
                System.out.println(2);
            case 7|9|8|10:
                System.out.println(3);
            case 4|6:
                System.out.println(4);
                break;
            case 21:
                System.out.println(5);
                break;
            case 99:
                System.out.println(6);
            case 66:
                System.out.println(7);
                break;
            default:
                throw new RuntimeException("what day is today?" + day);

        }

    }

}
enum SwitchTest01Enum01{
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}

JDK12: ”case L ->” 代替break并合并一行

package com.feature.jdk17.switchtest;

/**
 * @Author: yalong
 * @Description:
 * JDK12预览特性:switch表达式
 * JDK13二次预览特性:switch表达式
 * JDK14转正特性:switch表达式
 * JDK17预览特性:switch的模式匹配
 * @Date: Created in 2023/5/5 5:09
 * @Modified:
 */

public class SwitchTest02 {

    /**
     *
     * JDK12预览特性:switch表达式
     *
     * 使用case L -> 替代以前的break。
     * 多个case合并到一行。
     * case中依然可以使用;,但是;和->不能同时使用。
     * 变量接收switch表达式的结果。
     * @param args
     */
    public static void main(String[] args) {

        /**
         * 案例一
         * 使用case -> 省去break
         */
        SwitchTest02Enum01 day1 = SwitchTest02Enum01.FRIDAY;
        switch (day1){
            case MONDAY -> System.out.println(1);
            case TUESDAY,WEDNESDAY,THURSDAY -> System.out.println(2);
            case FRIDAY -> System.out.println(3);
            case SATURDAY,SUNDAY -> System.out.println(4);
            default -> throw new RuntimeException("what day is today?" + day1);
        }

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

        /**
         * 案例二
         * 变量接收switch表达式的结果
         */
        SwitchTest02Enum01 day2 = SwitchTest02Enum01.FRIDAY;
        int result2 = switch(day2){
            case MONDAY -> 1;
            case TUESDAY,WEDNESDAY,THURSDAY -> 2;
            case FRIDAY -> 3;
            case SATURDAY,SUNDAY -> 4;
            default -> throw new RuntimeException("what day is today?" + day1);
        };
        System.out.println("result2 : " + result2);

    }

}

enum SwitchTest02Enum01{
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}

JDK13:yield返回值

package com.feature.jdk17.switchtest;

/**
 * @Author: yalong
 * @Description:
 * JDK12预览特性:switch表达式
 * JDK13二次预览特性:switch表达式
 * JDK14转正特性:switch表达式
 * JDK17预览特性:switch的模式匹配
 * @Date: Created in 2023/5/5 5:09
 * @Modified:
 */

public class SwitchTest03 {

    /**
     *
     * JDK13二次预览特性:switch表达式
     *
     * 引入了yield关键字,用于返回指定的数据,结束switch结构。
     * 这意味着,switch表达式有返回值用yield,switch表达式无返回值用break。
     * yield和return区别:
     * yield只会跳出当前switch块。
     * return会直接跳出当前方法。
     * @param args
     */
    public static void main(String[] args) {

        /**
         * 写法一
         * 使用return     case -> yield
         */
        test1();

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

        /**
         * 写法二
         * 使用return     case : yield
         */
        test2();
    }

    private static void test1(){

        SwitchTest03Enum01 day = SwitchTest03Enum01.FRIDAY;
        int result = switch (day){
            case MONDAY -> {
                System.out.println(1);
                yield 1;
            }
            case TUESDAY,WEDNESDAY -> {
                System.out.println(2);
                yield 2;
            }
            case THURSDAY,FRIDAY -> {
                System.out.println(3);
                yield 3;
            }
            case SATURDAY,SUNDAY -> {
                System.out.println(4);
                yield 4;
            }
            default -> {
                System.out.println(5);
                //throw new RuntimeException("what day is today?" + day);
                //上下二者不能共存
                yield 5;
            }
        };

        System.out.println("result : " + result);

    }

    private static void test2(){

        SwitchTest03Enum01 day = SwitchTest03Enum01.SATURDAY;
        int result = switch (day){
            case MONDAY : {
                System.out.println(1);
                yield 1;
            }
            case TUESDAY,WEDNESDAY : {
                System.out.println(2);
                yield 2;
            }
            case THURSDAY,FRIDAY : {
                System.out.println(3);
                yield 3;
            }
            case SATURDAY,SUNDAY : {
                System.out.println(4);
                yield 4;
            }
            default : {
                System.out.println(5);
                //throw new RuntimeException("what day is today?" + day);
                //上下二者不能共存
                yield 5;
            }
        };

        System.out.println("result : " + result);

    }

}

enum SwitchTest03Enum01{
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}

JDK17:模式匹配

package com.feature.jdk17.switchtest;

/**
 * @Author: yalong
 * @Description:
 * JDK12预览特性:switch表达式
 * JDK13二次预览特性:switch表达式
 * JDK14转正特性:switch表达式
 * JDK17预览特性:switch的模式匹配
 * @Date: Created in 2023/5/5 5:09
 * @Modified:
 */

public class SwitchInstanceOfTest04 {

    /**
     * JDK17预览特性:switch的模式匹配
     * @param args
     */
    public static void main(String[] args) {

        /**
         * JDK17之前的用法
         */
        Double dd = 11.11D;
        test1(dd);

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

        /**
         * JDK17的用法:switch的模式匹配是预览特性,默认情况下禁用。
         * TODO 注意事项
         * 使用--enable-preview以启用patterns in switch statements
         * 或者
         * IDEA中选择"17(preview)-pattern matching for switch"
         */
        Boolean bool = true;
        test2(bool);
    }

    private static void test1(Object obj1){
        String formatted = "-unknown-";
        if(obj1 instanceof Integer i){
            formatted = "Integer:" + i;
        }else if(obj1 instanceof Long l){
            formatted = "Long:" + l;
        }else if(obj1 instanceof Double d){
            formatted = "Double:" + d;
        }else if(obj1 instanceof String s){
            formatted = "String:" + s;
        }
        System.out.println(formatted);
    }

    private static void test2(Object obj2){

        String formatted = "-unknown-";

        formatted = switch (obj2){
            case Integer i -> {
                yield "Integer:" + i;
            }
            case Long l -> {
                yield "Long:" + l;
            }
            case Double d -> {
                yield "Double:" + d;
            }
            case String s -> {
                yield "String:" + s;
            }
            default -> {
                yield formatted + obj2.toString();
            }
        };
        System.out.println(formatted);
    }

}

密封类sealed

package com.feature.jdk17.sealed;

/**
 * @Author: yalong
 * @Description: 密封类
 *
 * JDK15预览特性
 * JDK16二次预览特性
 * JDK17转正特性
 *
 * 指定类继承。
 * 通过密封的类和接口来限制超类的使用,密封的类和接口限制其他可能继承或实现它们的其他类或接口。
 *
 * 使用修饰符sealed,可以将一个类声明为密封类。
 * 密封的类使用保留关键字permits列出可以直接扩展(即extends)它的类。
 * sealed修饰的类的机制具有传递性,它的子类必须使用指定的关键字进行修饰,且只能是final、sealed、non-sealed三者之一。
 *
 * @Date: Created in 2023/5/5 23:00
 * @Modified:
 */

public sealed class SealedTest01 permits SealedStudentTest01,SealedTeacherTest01,SealedWorkerTest01{
}

/**
 * final不能被继承
 */
final class SealedStudentTest01 extends SealedTest01{}

/**
 * sealed只能被指定类继承且必须被指定子类继承。
 * 子类需强制声明为sealed、non-sealed或final。
 */
sealed class SealedTeacherTest01 extends SealedTest01 permits SealedTeacher2Test01{}
/**
 * non-sealed恢复类继承机制
 * 但与不加non-sealed的区别是父类是指定的,但子类已恢复原继承机制。、
 * 子类需强制声明为sealed、non-sealed或final
 */
non-sealed class SealedWorkerTest01 extends SealedTest01{}
/**
 * 继承sealed的类SealedTeacherTest01
 * 子类需强制声明为sealed、non-sealed或final
 */
final class SealedTeacher2Test01 extends SealedTeacherTest01{}

/**
 * 继承non-sealed的类SealedWorkerTest01
 * 子类已经不用再强制声明为sealed、non-sealed或final
 */
class SealedWorker2Test01 extends SealedWorkerTest01{}
/**
 * 继承non-sealed的类SealedWorkerTest01
 * 子类已经不用再强制声明为sealed、non-sealed或final
 */
class SealedWorker3Test01 extends SealedWorkerTest01{}

标题:JDK新特性8-17
作者:yazong
地址:https://blog.llyweb.com/articles/2023/05/08/1683526070227.html