当前位置: 首页 > news >正文

java学习笔记16——java8的其他新特性

Java 8新特性简介

总结:

1.截止目前,JDK比较重要的时间节点和版本说明
1996            JDK1.0
2004            JDK5.0 最重要的一个里程碑式的版本
2014            JDK8.0 排第二的里程碑式的版本---> LTS
2017.9          JDK9.0 从此版本开始,每半年发布一个新的版本
2018.9          JDK11  ----> LTS
2021.9          JDK17  ----> LTS

2.如何学习新特性?
> 角度1:新的语法规则(多关注)
自动装箱、自动拆箱、注解、enum、Lambda表达式、方法引用、switch表达式、try-catch变化、record等
> 角度2:增加、过时、删除API
StringBuilder、ArrayList、新的日期时间的API、Optional等
> 角度3:底层的优化、JVM参数的调整、GC的变化、内存结构(永久代--->元空间)

Lambda 表达式

总结:

 

1.Lambda表达式的使用举例:
(o1,o2)->Integer.compare(o1,o2);
2.Lambda表达式的格式举例:

3.Lambda表达式的格式:
-> : lambda操作符或箭头操作符
-> 的左边: lambda形参列表,对应着要重写的接口中的抽象方法的形参列表。
-> 的右边: lambda体,对应着接口的实现类要重写的方法的方法体。
4.Lambda表达式的本质:
> 一方面,lambda表达式作为接口的实现类的对象。 ----> "万事万物皆对象
> 另一方面,lambda表达式是一个匿名函数。
5.函数式接口:
5.1 什么是函数式接口?为什么需要函数式接口?
> 如果接口中只声明有一个抽象方法,则此接口就称为函数式接口。
> 因为只有给函数式接口提供实现类的对象时,我们才可以使用lambda表达式。
5.2 api中函数式接口所在的包
jdk8中声明的函数式接口都在java.util.function包下
5.3 4个基本的函数式接口
         接口              对应的抽象方法
消费型接口:Consumer<T>      void accept(T t)
供给型接口:Supplier<T>      T get()
函数型接口:Function<T,R>    R apply(T t)
判断型接口:Predicate<T>     boolean test(T t)

6.Lambda表达式的语法规则总结
-> 的左边:lambda形参列表,参数的类型都可以省略。如果形参只有一个,则一对()也可以省略。
-> 的右边:lambda体,对应着重写的方法的方法体。如果方法体中只有一行执行语向,则一对{}可以省略。
                                            如果有return关键字,则必须一并省略。

代码:

public class LambdaTest {
    @Test
    public void test1(){
        Runnable r1 = new Runnable(){
            @Override
            public void run() {
                System.out.println("我爱北京天安门");
            }
        };
        r1.run();
        System.out.println("*******************");
        //Lambda表达式的写法:
        Runnable r2 = () -> {
            System.out.println("我爱上海东方明珠");
        };
        r2.run();
    }
    @Test
    public void test2(){
        Comparator<Integer> com1 = new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        int compare1 = com1.compare(12,21);
        System.out.println(compare1); //-1
        System.out.println("*************************");
        //Lambda表达式的写法
        Comparator<Integer> com2 = (Integer o1, Integer o2)->Integer.compare(o1,o2);
        int compare2 = com2.compare(23,21);
        System.out.println(compare2); //1
        System.out.println("*****************");
        //方法引用
        Comparator<Integer> com3 = Integer :: compare;
        int compare3 = com3.compare(23,21);
        System.out.println(compare3); //1
    }
}

 代码2:

public class LambdaTest1 {
    //语法格式一:无参,无返回值
    @Test
    public void test1() {
        Runnable r1 = new Runnable() {
            public void run() {
                System.out.println("我爱北京天安门");
            }
        };
        r1.run();
        System.out.println("*****************");
        Runnable r2 = () -> {
            System.out.println("我爱北京天安门");
        };
        r2.run();
    }

    //语法格式二:Lambda需要一个参数,但是没有返回值
    @Test
    public void test2() {
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("谎言和誓言的区别是什么?");
        System.out.println("***************");
        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("一个是说的人当真了,一个是听的人当真了");
    }

    //语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
    @Test
    public void test3() {
        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("如果大学可以重来,你最想重来的事是啥?");
        System.out.println("********************");
        Consumer<String> con2 = (s) -> {
            System.out.println(s);
        };
        con1.accept("谈一场轰轰烈烈的爱情");
    }

    @Test
    public void test3_1() {
        int[] arr = {1, 2, 3, 4, 5}; //类型推断
        HashMap<String, Integer> map = new HashMap<>(); //类型推断
        var entrySet = map.entrySet();//类型推断,在jdk10及之后可以用
    }

    //语法格式四:Lambda若只需要一个参数时,参数的小括号可以省略
    @Test
    public void test4() {
        Consumer<String> con1 = (s) -> {
            System.out.println(s);
        };
        con1.accept("世界那么大,我想去看看");
        System.out.println("****************");
        Consumer<String> con2 = s -> {
            System.out.println(s);
        };
        con1.accept("世界那么大,我想去看看");
    }

    //语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
    @Test
    public void test5() {
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare(12, 21));
        System.out.println("**********************");
        Comparator<Integer> com2 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(com1.compare(12, 21));
    }
    //语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
    @Test
    public void test6(){
        Comparator<Integer> com1 = (o1,o2)->{
            return o1.compareTo(o2);
        };
        System.out.println(com1.compare(12, 21));
        System.out.println("**************");
        Comparator<Integer> com2 = (o1,o2)-> o1.compareTo(o2);
    }
}

 function文件:

public class MyFunctionalInterfaceTest {
    @Test
    public void test1(){
        MyFunctionalInterface m = () -> System.out.println("hello");
        m.method();
    }
}

@FunctionalInterface
public interface MyFunctionalInterface {
    void method();
//    void method1();
}

函数式接口

方法引用与构造器引用

方法引用总结:

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

 构造器数组引用总结:

1.构造器引用
1.1 格式:
类名 :: new
1.2 说明:
> 调用了类名对应的类中的某一个确定的构造器
> 具体调用的是类中的哪一个构造器呢?取决于函数式接口的抽象方法的形参列表!
2.数组引用
格式:
格式:数组名[]::new

代码:

data文件

Employee 
public class Employee {
    int id;
    String name;
    int age;
    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;
    }

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

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

//    @Override
//    public boolean equals(Object o) {
//        if (o == null || getClass() != o.getClass()) return false;
//        Employee employee = (Employee) o;
//        return id == employee.id && age == employee.age && Double.compare(salary, employee.salary) == 0 && Objects.equals(name, employee.name);
//    }
//
//    @Override
//    public int hashCode() {
//        return Objects.hash(id, name, age, salary);
//    }

    @Override
    public boolean equals(Object o) {
        if(this == o)
            return true;
        if(o==null||getClass()!=o.getClass())
            return false;
        Employee employee = (Employee)o;
        if(id!=employee.id)
            return false;
        if(age!=employee.age)
            return false;
        if(Double.compare(employee.salary,salary)!=0)
            return false;
        return name != null ? name.equals(employee.name) : employee.name == null;
    }

    @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;
    }
}
EmployeeDate 
public class EmployeeDate {
    public static List<Employee> getEmployees() {
        List<Employee> list = new ArrayList<>();
        list.add(new Employee(1001, "马化腾", 34, 6000.38));
        list.add(new Employee(1002, "马云", 2, 19876.12));
        list.add(new Employee(1003, "刘强东", 33, 3000.82));
        list.add(new Employee(1004, "雷军", 26, 7657.37));
        list.add(new Employee(1005, "李彦宏", 65, 5555.32));
        list.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
        list.add(new Employee(1007, "任正非", 26, 4333.32));
        list.add(new Employee(1008, "扎克伯格", 35, 2500.32));
        return list;
    }
}

 方法引用代码:

public class MethodRefTest {
    //情况一:类(或对象)::方法名
    //Consumer中的void accept(T t)
    //PrintStream中的void println(T t)
    @Test
    public void test1() {
        //1.
        Consumer<String> con1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("hello!");
        //2.lambda表达式
        Consumer<String> con2 = s -> System.out.println(s);
        con2.accept("hello!");
        //3.方法引用
        PrintStream ps = System.out;
        Consumer<String> con3 = ps::println;
        con3.accept("hello!");
    }

    //Supplier中的T get()
    //Employee中的String getName()
    @Test
    public void test2() {
        Employee emp = new Employee(1001, "马化腾", 34, 6000.38);
        //1.
        Supplier<String> sup1 = new Supplier<String>() {
            @Override
            public String get() {
                return emp.getName();
            }
        };
        System.out.println(sup1.get());
        //2.lambda表达式
        Supplier<String> sup2 = () -> emp.getName();
        System.out.println(sup2.get());
        //3.方法引用
        Supplier<String> sup3 = emp::getName;
        System.out.println(sup3.get());
    }

    //情况二:类 :: 静态方法
    //Comparator中的int compare(T t1,T t2)
    //Integer中的int compare(T t1,T t2)
    @Test
    public void test3() {
        //1.
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        System.out.println(com1.compare(12, 21));
        //2.
        Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);
        System.out.println(com2.compare(21, 34));
        //3.方法引用
        Comparator<Integer> com3 = Integer::compare;
        System.out.println(com3.compare(34, 34));
    }

    //Function中的R apply(T t)
    //Math中的Lang round(Double d)
    @Test
    public void test4() {
        //1.
        Function<Double, Long> fun1 = new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        //2.
        Function<Double, Long> fun2 = aDouble -> Math.round(aDouble);
        //3.方法引用
        Function<Double, Long> fun3 = Math::round;
    }

    //情况三:类 ::实例方法(难)
    //Comparator中的int compare(T t1,T t2)
    //String中的int t1.compareTo(t2)
    @Test
    public void test5() {
        //1.
        Comparator<String> com1 = new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare("abc", "abb"));
        //2.
        Comparator<String> com2 = (s1, s2) -> s1.compareTo(s2);
        System.out.println(com2.compare("abc", "abb"));
        //3.
        Comparator<String> com3 = String::compareTo;
        System.out.println(com3.compare("abc", "abb"));
    }

    //BiPredicate中的boolean test(T t1,T t2)
    //String中的boolean t1.equals(t2)
    @Test
    public void test6() {
        BiPredicate<String,String> biPre1 = new BiPredicate<String, String>() {
            @Override
            public boolean test(String s1,String s2){
                return s1.equals(s2);
            }
        };
        //2.
        BiPredicate<String,String> biPre2 = (s1,s2) -> s1.equals(s2);
        //3.方法引用
        BiPredicate<String,String> biPre3 = String :: equals;
    }
    //Function中的R apply(T t)
    //Employee中的String getName()
    @Test
    public void test7(){
        Employee emp = new Employee(1001, "马化腾", 34, 6000.38);
        //1
        Function<Employee,String> fun1 = new Function<Employee,String>(){
            @Override
            public String apply(Employee employee) {
                return employee.getName();
            }
        };
        System.out.println(fun1.apply(emp));
        //2.
        Function<Employee,String> fun2 = employee -> employee.getName();
        System.out.println(fun2.apply(emp));
        //3.方法引用
        Function<Employee,String> fun3 = Employee :: getName;
        System.out.println(fun3.apply(emp));
    }
}

构造器引用代码:

 

public class ConstructorRefTest {
    //构造器引用
    //Supplier中的T get()
    @Test
    public void test1(){
        //1.
        Supplier<Employee> sup1 = new Supplier<Employee>(){
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println(sup1.get());
        //2.方法引用
        Supplier<Employee> sup2 = Employee :: new; //调用的是Employee类中空参的构造器
        System.out.println(sup2.get());
    }
    //Function中的R apply(T t)
    @Test
    public void test2(){
        //1.
        Function<Integer,Employee> func1 = new Function<Integer,Employee>() {
            @Override
            public Employee apply(Integer id) {
                return new Employee(id);
            }
        };
        System.out.println(func1.apply(12));
        //2.构造器引用
        Function<Integer, Employee> func2 = Employee::new; //调用的是Employee类中参数是Integer/int类型的构造器
        System.out.println(func2.apply(11));
    }
    //BiFunction中的R apply(T t,U u)
    @Test
    public void test3(){
        //1.
        BiFunction<Integer,String,Employee> func1 = new BiFunction<Integer, String, Employee>() {
            @Override
            public Employee apply(Integer id, String name) {
                return new Employee(id,name);
            }
        };
        System.out.println(func1.apply(10, "Tom"));
        //2.
        BiFunction<Integer, String, Employee> func2 = Employee::new; //调用的是Employee类中参数是Integer/int、String类型的构造器
        System.out.println(func2.apply(11, "Tony"));

    }
    //数组引用
    //Function中的R apply(T t)
    @Test
    public void test4(){
        //1.
        Function<Integer,Employee[]> func1 = new Function<Integer,Employee[]>(){
            @Override
            public Employee[] apply(Integer length) {
                return new Employee[length];
            }
        };
        System.out.println(func1.apply(10).length);
        //2.
        Function<Integer,Employee[]> func2 = Employee[]::new;
        System.out.println(func2.apply(11).length);
    }
}

强大的Stream API

强大的Stream APICollectors

 总结:

1.Stream API vs 集合框架
> Stream API 关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU的。
    集合关注的数据的存储,向下内存的。
> Stream API 之于集合,类似于SQL之于数据表的查询。
2.使用说明
① stream 自己不会存储元素。
② stream 不会改变源对象。相反,他们会返回一个持有结果的新stream。
③ stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生结果
④ Stream一旦执行了终止操作,就不能再调用其它中间操作或终止操作了。
3.Stream 执行流程
步骤1:Stream的实例化
步骤2:一系列的中间操作
步骤3:执行终止操作

代码:

StreamAPITest 
public class StreamAPITest {
    //创建Stream方式一:通过集合
    @Test
    public void test1(){
        List<Employee> list = EmployeeDate.getEmployees();
        //default Stream<E> stream():返回一个顺序流
        Stream<Employee> stream = list.stream();
        //default Stream<E> parallelStream(): 返回一个并行流
        Stream<Employee> stream1 = list.parallelStream();
        System.out.println(stream);
        System.out.println(stream1);
    }
    //创建Stream方式二:通过数组
    @Test
    public void test2(){
        //调用Arrays类的static <T> Stream<T> stream(T[] array):返回一个流
        Integer[] arr = new Integer[]{1,2,3,4,5};
        Stream<Integer> stream = Arrays.stream(arr);
        int[] arr1 = new int[]{1,2,3,4,5};
        IntStream stream1 = Arrays.stream(arr1);
    }
    //创建Stream方式三:通过Stream的of()
    @Test
    public void test3(){
        Stream<String> stream = Stream.of("AA", "BB", "CC", "SS", "DD");
        System.out.println(stream);
    }
}

代码2:

 

public class StreamAPITest1 {
    //1-筛选与切片
    @Test
    public void test1(){
        //filter(Predicate p)——接受Lambda,从流中排除某些元素
        //练习:查询员工表中薪资大于7000的员工信息
        List<Employee> list = EmployeeDate.getEmployees();
        Stream<Employee> stream = list.stream();
        stream.filter(emp -> emp.getSalary() > 7000).forEach(System.out::println);
        System.out.println();
        //limit(n)——截断流,使其元素不超过给定数量
        //错误的,因为Stream已经执行了终止操作,就不可以再调用其他的中间操作或终止操作了
//        stream.limit(2).forEach(System.out::println);
        list.stream().limit(4).forEach(System.out::println);
        System.out.println();
        //获取薪资大于7000的前两个
        list.stream().filter(emp->emp.getSalary()>7000).limit(2).forEach(System.out::println);
        System.out.println();
        //skip(n) —— 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit
        list.stream().skip(5).forEach(System.out::println);
        System.out.println();
        //distinct()——筛选,通过流所生成元素的hashCode()和equals()去除重复元素
        list.add(new Employee(1009, "马斯克", 40, 12500.32));
        list.add(new Employee(1009, "马斯克", 40, 12500.32));
        list.add(new Employee(1009, "马斯克", 40, 12500.32));
        list.add(new Employee(1009, "马斯克", 40, 12500.32));
        list.stream().distinct().forEach(System.out::println);
    }
    //映射
    @Test
    public void test2(){
        //map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上
        //练习:转换成大写
        List<String> list = Arrays.asList("aa","bb","cc","dd");
        //方式1:
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
        //方式2:
        list.stream().map(String :: toUpperCase).forEach(System.out::println);
        //练习:获取员工姓名长度大于3的员工
        List<Employee> employees = EmployeeDate.getEmployees();
        employees.stream().filter(emp->emp.getName().length()>3).forEach(System.out::println);
        //练习:获取员工姓名长度大于3的员工姓名
        //方式1:
        employees.stream().filter(emp -> emp.getName().length() > 3).map(emp -> emp.getName()).forEach(System.out::println);
        //方式2:
        employees.stream().map(emp -> emp.getName()).filter(name -> name.length() > 3).forEach(System.out::println);
        //方式3:
        employees.stream().map(Employee::getName).filter(name->name.length()>3).forEach(System.out::println);
    }
    //3-排序
    @Test
    public void test3(){
        //sorted()——自然排序
        Integer[] arr = new Integer[]{345,3,64,3,46,7,3,34,65,68};
        String[] arr1 = new String[]{"GG", "DD", "MM", "SS", "JJ"};
        Arrays.stream(arr).sorted().forEach(System.out::println);
        System.out.println(Arrays.toString(arr)); //arr数组并没有因为升序,被调整
        Arrays.stream(arr1).sorted().forEach(System.out::println);
        //因为Employee没有实现Comparable接口,所以报错!
//        List<Employee> list = EmployeeDate.getEmployees();
//        list.stream().sorted().forEach(System.out::println);
        //sorted(Comparator com)——定制排序
        List<Employee> list = EmployeeDate.getEmployees();
        list.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).forEach(System.out::println);
        //针对于字符串从大到小排序
        Arrays.stream(arr1).sorted((s1, s2) -> s1.compareTo(s2)).forEach(System.out::println);
        Arrays.stream(arr1).sorted(String::compareTo).forEach(System.out::println);
    }
}

代码3:

 

public class StreamAPITest2 {
    //1-匹配与查找
    @Test
    public void test1(){
        //allMatch(Predicate p)——检查是否匹配所有元素
        //练习:是否所有的员工的年龄都大于18
        List<Employee> list = EmployeeDate.getEmployees();
        System.out.println(list.stream().allMatch(emp -> emp.getAge() > 18)); //false
        //anyMatch(Predicate p)——检查是否至少匹配一个元素
        //练习:是否存在年龄大于18岁的员工
        System.out.println(list.stream().anyMatch(emp->emp.getAge()>18));
        //练习:是否存在员工的工资大于10000
        System.out.println(list.stream().anyMatch(emp -> emp.getSalary() > 10000));
        //findFirst——返回第一个元素
        System.out.println(list.stream().findFirst().get());
    }
    @Test
    public void test2(){
        //count——返回流中元素的总个数
        List<Employee> list = EmployeeDate.getEmployees();
        System.out.println(list.stream().count());
        System.out.println(list.stream().filter(emp->emp.getSalary()>7000).count());
        //max(Comparator c)———返回流中最大值
        //练习:返回最高工资的员工
        System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        //练习:返回最高的工资
        //方式1:
        System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).get().getSalary());
        //方式2:
        System.out.println(list.stream().map(emp -> emp.getSalary()).max((salary1, salary2) -> Double.compare(salary1, salary2)).get());
        System.out.println(list.stream().map(emp->emp.getSalary()).max(Double::compare).get());
        //min(Comparator c)——返回流中最小值
        //练习:返回最低工资的员工
        System.out.println(list.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        //forEach(Consumer c)——内部迭代
        list.stream().forEach(System.out::println);

        //针对于集合,jdk8中增加了一个遍历的方法
        list.forEach(System.out::println);
        //针对于List来说,遍历的方式:①使用Iterator ②增强for ③一般for ④forEach()

    }
    //2-归约
    @Test
    public void test3(){
        //reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
        //练习1:计算1-10的自然数的和
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        System.out.println(list.stream().reduce(0, (x1, x2) -> x1 + x2));
        System.out.println(list.stream().reduce(0, (x1, x2) -> Integer.sum(x1, x2)));
        System.out.println(list.stream().reduce(0, Integer::sum));
        System.out.println(list.stream().reduce(10,(x1,x2)->x1+x2));
        //reduce(BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
        // 练习2:计算公司所有员工工资的总和
        List<Employee> employeeList = EmployeeDate.getEmployees();
        employeeList.stream().map(emp -> emp.getSalary()).reduce((salary1, salary2) -> Double.sum(salary1, salary2));
        employeeList.stream().map(emp -> emp.getSalary()).reduce(Double::sum);
    }
    //3-收集
    @Test
    public void test4(){
        List<Employee> list = EmployeeDate.getEmployees();
        //collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
        //练习1:查找工资大于6000的员工,结果返回为一个List或Set
        List<Employee> list1 = list.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toList());
        list1.forEach(System.out::println);
        //固定到了list当中,可以根据list做一些其他操作
        System.out.println();
        list.forEach(System.out::println);
        System.out.println();
        //练习2:按照员工的年龄进行排序,返回到一个新的List中
        List<Employee> list2 = list.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).collect(Collectors.toList());
        list2.forEach(System.out::println);
    }
}

Optional

 总结:

JDK8的新特性,JDK9-11中新增了一些方法。
1.为什么需要0ptional类?
为了避免代码中出现空指针异常。
2.如何实例化?
static <T> Optional<T> ofNullable(T value):用来创建一个Optional实例,value可能是空,也可能非空
3.常用方法

代码 :

public class OptionalTest {
    @Test
    public void test(){
        String star = "迪丽热巴";
        star = null;
        //使用Optional避免空指针的问题
        //1.实例化:
        //ofNullable(T value):用来创建一个Optional实例,value可能是空,也可能非空
        Optional<String> optional = Optional.ofNullable(star);
        //orElse(t other):如果Optional实例内部的value属性不为null,则返回value,如果value为null
        //则返回other
        String otherStar = "杨幂";
        String finalStar = optional.orElse(otherStar);

        System.out.println(finalStar.toString());
    }
    @Test
    public void test2(){
        String star = "迪丽热巴";
//        star = null;
        Optional<String> optional = Optional.ofNullable(star);
        //get():取出内部的value值
        System.out.println(optional.get());
    }
}

 JDK 9 的发布

一、JDK JRE 目录结构的改变

二、模块化系统: Jigsaw ——>Modularity

三、JavaREPL工具: jShell命令

四、语法改进:接口的私有方法

六、语法改进:try语句

七、String存储结构变更

八、集合工厂方法:快速创建只读集合

九、InputStream 加强

十、增强的 Stream API

十一、Optional获取Stream的方法

十二、Javascript引擎升级:Nashorn

Java 10 新特性

JDK1012JEP

一、局部变量类型推断

二、集合新增创建不可变集合的方法

Java 11 新特性

一、新增了一系列字符串处理方法

二、Optional 加强

三、局部变量类型推断升级

四、全新的HTTP 客户端API

五、更简化的编译运行程序

六、废弃Nashorn引擎

七、ZGC

八、其它新特性

总结及代码 

jshell:

这是JDK9的新特性
1.命令行中通过指令jshell,调取jshell工具
2.常用指令:
/help:获取关使用 jshell 工具的信息
/help intro : jshell 工具的简介
/list :列出当前 session 里所有有效的代码片段
/vars :查看当前 session 下所有创建过的变量
/methods :查看当前 session 下所有创建过的方法
/imports :列出导入的包
/history :键入的内容的历史记录
/edit :使用外部代码编辑器来编写 Java 代码
/exit :退出 jshell 工具

try-catch:

public class TryCatchTest {
    /**
     * 举例1:
     * JDK7之前的写法
     */
    @Test
    public void test01() {
        FileWriter fw = null;
        BufferedWriter bw = null;
        try {
            fw = new FileWriter("test.txt");
            bw = new BufferedWriter(fw);
            bw.write("hello,世界");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bw != null)
                    bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fw != null)
                    fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 举例1:
     * JDK7中的写法
     */
    @Test
    public void test02() {
        try (FileWriter fw = new FileWriter("test.txt");
             BufferedWriter bw = new BufferedWriter(fw)) {
            bw.write("hello,世界");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 举例2:从test.txt(utf-8)文件中,读取内容,写出到abc.txt(gbk)文件中
     * JDK7之前的写法
     */
    @Test
    public void test03() {
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            FileInputStream fis = new FileInputStream("test.txt");
            InputStreamReader isr = new InputStreamReader(fis, "utf-8");
            br = new BufferedReader(isr);
            FileOutputStream fos = new FileOutputStream("abc.txt");
            OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
            bw = new BufferedWriter(osw);
            String str;
            while ((str = br.readLine()) != null) {
                bw.write(str);
                bw.newLine();
                bw.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 举例2:从test.txt(utf-8)文件中,读取内容,写出到abc.txt(gbk)文件中
     * JDK7中的写法
     */
    @Test
    public void test04() {
        try (
                FileInputStream fis = new FileInputStream("test.txt");
                InputStreamReader isr = new InputStreamReader(fis, "utf-8");
                BufferedReader br = new BufferedReader(isr);
                FileOutputStream fos = new FileOutputStream("abc.txt");
                OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
                BufferedWriter bw = new BufferedWriter(osw);
        ) {
            String str;
            while ((str = br.readLine()) != null) {
                bw.write(str);
                bw.newLine();
                bw.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //jdk9中举例:
    @Test
    public void test05(){
        InputStreamReader reader = new InputStreamReader(System.in);
        OutputStreamWriter writer = new OutputStreamWriter(System.out);
        try(reader;writer){
            //reader、writer是final的,不可再被赋值

        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

局部变量类型推断

这是JDK10的新特性。
public class VarTest {
    //可以使用的场景
    @Test
    public void test01(){
        //1.局部变量的实例化
        var list = new ArrayList<String>();
        var set = new LinkedHashSet<Integer>();
        //2.增强for循环中的索引
        for(var v:list){
            System.out.println(v);
        }
        //3.传统for循环中
        for(var i = 0;i<100;i++){
            System.out.println(i);
        }
        //4.返回值类型含复杂泛型结构
        var iterator = set.iterator();
        HashMap<String,Integer> map = new HashMap<>();
        var entrySet = new HashMap<>();
//        Iterator<Map.Entry<Integer, Student>> iterator = set.iterator();
    }
    /**
     * 声明一个成员变量
     * 声明一个数组变量,并为数组静态初始化(省略new的情况下)
     * 方法的返回值类型
     * 方法的参数类型
     * 没有初始化的方法内的局部变量声明
     * 作为catch块中异常类型
     * Lambda表达式中函数式接口的类型
     * 方法引用中函数式接口的类型
     */
    //声明一个成员变量
//    var i;
//    var j = 0;
    @Test
    public void test2(){
        // 声明一个数组变量,并为数组静态初始化(省略new的情况下)
        var arr = new int[]{1,2,3,4,5};
//        var arr = {1,2,3,4,5};
    }
    //没有初始化的方法内的局部变量声明
    //方法的参数类型
    //方法的返回值类型
//    public var method(int i,var m){
//        var i = 0;
//    }
    @Test
    public void test3(){
//        try{
//            System.out.println(10/0);
//        }catch(var e){ //作为catch块中异常类型
//            e.printStackTrace();
//        }
        //方法引用中函数式接口的类型
//        var com = (s1,s2)->s1.compareTo(s2); //Lambda表达式中函数式接口的类型
    }
}

instanceof模型匹配

JDK14中预览特性。
JDK15中第二次预览。
JDK16中转正特性。
JDK14之前:
// 先判断类型
if(obj instanceof string){
    // 然后转换
    String s=(string)obj;
    // 然后才能使用
}
JDK14:(自动匹配模式)
if(obj instanceof string s){
    //如果类型匹配 直接使用
}else {
    //如果类型不匹配则不能直接使用
}
public class InstanceOfTest {
    /**
     * 举例1:
     * JDK14之前
     */
    @Test
    public void test1(){
        Object obj = new String("hello,Java14");
        if(obj instanceof String){
            String str = (String)obj;
            System.out.println(str.contains("Java"));
        }else{
            System.out.println("非String类型");
        }
    }
    /**
     * 举例1:
     * JDK14中
     */
    @Test
    public void test2(){
        Object obj = new String("hello,Java14");
        if(obj instanceof String str){
            System.out.println(str.contains("Java"));
        }else{
            System.out.println("非String类型");
        }
    }
}
/**
 * 举例2:
 */
class Computer{
    private String model; //型号
    private double price;//价格
    //方式1:
//    public boolean equals(Object o){
//        if(o instanceof Computer) {
//            Computer other = (Computer)o;
//            if(this.model.equals(other.model)&&this.price==other.price){
//                return true;
//            }
//        }
//        return false;
//    }
    //方式2:
//    public boolean equals(Object o){
//        if(o instanceof Computer other){
//            return this.model.equals(other.model)&&this.price==other.price;
//        }
//        return false;
//    }
    public boolean equals(Object o) {
        return o instanceof Computer other && this.model.equals(other.model) && this.price == other.price;
    }
}

switch表达式

JDK12中预览特性:switch表达式
JDK13中二次预览特性:switch表达式
JDK14中转正特性:switch表达式

JDK17的预览特性:switch的模式匹配
public class SwitchPatternTest {
    public static void main(String[] args){
        System.out.println(formatter(12));
        System.out.println(formatterSwitchPattern(12));
    }
    /**
     * JDK17之前
     */
    static String formatter(Object o){
        String formatted = "unknown";
        if(o instanceof Integer i){
            formatted = "int" + i;
        }else if(o instanceof Long l){
            formatted = "long" + l;
        }else if(o instanceof Double d){
            formatted = "double" + d;
        }else if(o instanceof String s){
            formatted = "String" + s;
        }
        return formatted;
    }
    /**
     * JDK17中switch的模式匹配
     */
    static String formatterSwitchPattern(Object o){
        String formatted = switch(o){
            case Integer i:
                yield "int" + i;
            case Long l:
                yield "long" + l;
            case Double d:
                yield "double" + d;
            case String s:
                yield "String" + s;
            default:
                yield o.toString();
        };
        return formatted;
    }
}
enum Week{
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}
public class SwitchExceptionTest {
    /**
     * 举例1:
     * JDK12之前的写法
     */
    @Test
    public void test1(){
        Week day = Week.FRIDAY;
        int num=0;
        switch(day){
            case MONDAY:
                num = 20;
                System.out.println(1);
                break;
            case TUESDAY:
            case WEDNESDAY:
            case THURSDAY:
                num = 20;
                System.out.println(2);
                break;
            case FRIDAY:
                System.out.println(3);
                break;
            case SATURDAY:
            case SUNDAY:
                System.out.println(4);
                break;
            default:
                throw new RuntimeException("What day is today?"+day);
        }
    }
    /**
     * 举例1:
     * jdk12中的写法:switch表达式,省去了break语句,避免了因少写break而出现case穿透
     */
    @Test
    public void test2() {
        Week day = Week.FRIDAY;
        int num = 0;
        switch (day) {
            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?" + day);
        }
    }
    /**
     * 举例1:
     * jdk12中的写法:还可以使用变量接收switch表达式的结果
     */
    @Test
    public void test3(){
        Week day = Week.FRIDAY;
        int num = 0;
        int result = switch (day) {
            case MONDAY -> 1;
            case TUESDAY, WEDNESDAY, THURSDAY ->2;
            case FRIDAY -> 3;
            case SATURDAY, SUNDAY -> 4;
            default -> throw new RuntimeException("What day is today?" + day);
        };
        System.out.println(result);
    }
    /**
     * 举例1:(在default中返回值5)
     * JDK13中的写法:引入了yield关键字,用于返回指定的数据,结束switch结构。
     * 这意味着,switch表达式(返回值)应该使用yield,switch语句(不返回值)应该使用break。
     * 和return的区别在于:return会直接跳出当前方法,而yield只会跳出当前switch块。
     */
    @Test
    public void test4(){
        Week day = Week.FRIDAY;
        int num = 0;
        int result = switch (day) {
            case MONDAY -> {
                yield 1;
            }
            case TUESDAY, WEDNESDAY, THURSDAY -> {
                yield 2;
            }
            case FRIDAY -> {
                yield 3;
            }
            case SATURDAY, SUNDAY -> {
                yield 4;
            }
            default -> {
                System.out.println("值未找到");
                yield 5;
            }
        };
        System.out.println(result);
    }
    @Test
    public void test5(){
        Week day = Week.FRIDAY;
        int num = 0;
        int result = switch (day) {
            case MONDAY:
                yield 1;
            case TUESDAY, WEDNESDAY, THURSDAY:
                yield 2;
            case FRIDAY:
                yield 3;
            case SATURDAY, SUNDAY:
                yield 4;
            default:
                yield 5;
        };
        System.out.println(result);
    }

}

block:

JDK13的预览特性
JDK14中二次预览特性
JDK15中功能转正
public class BlockTest {
    //对比1:
    @Test
    public void test1() {
        String info = "<html>\n" +
                " <body>\n" +
                "  <p>Hello,尚硅谷</p>\n" +
                " </body>\n" +
                "</html>";
        System.out.println(info);
    }

    @Test
    public void test2() {
        String info = """
                <html>
                  <body>
                    <p>Hello,尚硅谷</p>
                  </body>
                </html>
                """;
        System.out.println(info);
    }
    //对比2:
    @Test
    public void test3(){
        String myJson = "{\n" +
                " \"name\":\"Song Hongkang\",\n" +
                " \"gender\":\"男\",\n" +
                " \"address\":\"www.atguigu.com\"\n" +
                "}";
        System.out.println(myJson);
    }
    @Test
    public void test4(){
        String myJson1 = """
                {
                 "name":"Song Hongkang",
                 "gender":"男",
                 "address":"www.atguigu.com"
                }
                """;
        System.out.println(myJson1);
    }
    //对比3
    @Test
    public void test5(){
        String query = "SELECT employee_id,last_name,salary,department_id\n"+
                "FROM employees\n" +
                "WHERE department_id IN (40,50,60)\n" +
                "ORDER BY department_id ASC";
    }
    @Test
    public void test6(){
        String newQuery = """
                        SELECT employee_id,last_name,salary,department_id
                        FROM employees
                        WHERE department_id IN (40,50,60)
                        ORDER BY department_id ASC
                """;
        System.out.println(newQuery);
    }
    /**
     * JDK14新特性:
     * \:取消换行操作
     * \s:表示一个空格
     */
    @Test
    public void test7(){
        String newQuery1 = """
                SELECT id,name,email \
                FROM customers\s\
                WHERE id > 4 \
                ORDER BY email DESC
                """;
        System.out.println(newQuery1);
    }
}

record:

JDK14中预览特性
JDK15中第二次预览特性
JDK16中转正特性
public class OrderTest {
    @Test
    public void test1(){
        Order order1 = new Order(1001,"orderAA");
        //测试toString()
        System.out.println(order1);
        //测试getter()
        System.out.println(order1.orderId());
        System.out.println(order1.orderName());
        Order order2 = new Order(1001,"orderAA");
        //测试equals()
        System.out.println(order1.equals(order2));
        //测试HashCode()和equals()
        HashSet<Order> set = new HashSet<>();
        set.add(order1);
        set.add(order2);
        System.out.println(set);
    }
    //测试Record
    @Test
    public void test2(){
        Order1 order1 = new Order1(1001,"orderAA");
        //测试toString()
        System.out.println(order1);
        //测试getter()
        System.out.println(order1.orderId());
        System.out.println(order1.orderName());
        Order1 order2 = new Order1(1001,"orderAA");
        //测试equals()
        System.out.println(order1.equals(order2));
        //测试HashCode()和equals()
        HashSet<Order1> set = new HashSet<>();
        set.add(order1);
        set.add(order2);
        System.out.println(set);
    }
    @Test
    public void test3(){
        Class<Person> clazz = Person.class;
        System.out.println(clazz.getSuperclass());
    }
}
Person
public record Person(int id, String name) {
    //-还可以在record声明类中定义静态字段、静态方法、构造器或实例方法。
    static String info = "我是一个人";

    public static void show() {
        System.out.println("我是一个人!");
    }

    public Person() {
        this(0, null);
    }

    public void test() {
        System.out.println("人吃饭");
    }
    //-不能在record声明的类中定义实例字段:类不能声明为abstract;不能声明显式的父类等。
    //   final int age;
}
//abstract record Dog(int id){}
//record Cat(int id) extends Thread{}
//class Student extends Person{} //record声明的类不能有子类

Order 
public class Order {
    //属性:private final修饰
    private final int orderId;
    private final String orderName;
    //构造器中初始化属性
    public Order(int orderId,String orderName){
        this.orderId = orderId;
        this.orderName = orderName;
    }
    //提供属性的getter方法

    public int orderId() {
        return orderId;
    }

    public String orderName() {
        return orderName;
    }

    //equals()和hashCode()
    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) return false;
        Order order = (Order) o;
        return orderId == order.orderId && Objects.equals(orderName, order.orderName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(orderId, orderName);
    }

    @Override
    public String toString() {
        return "Order{" +
                "orderId=" + orderId +
                ", orderName='" + orderName + '\'' +
                '}';
    }
}
Order1
public record Order1(int orderId,String orderName) {
}

密封类的使用:

JDK15的预览特性J
DK16二次预览特性
JDK17转正特性
//Person是一个密封类,可以被指定的子类所继承,非指定的类不能继承Person类
public sealed class Person permits Student, Teacher, Worker {
}
//要求指定的子类必须是final、sealed、non-sealed三者之一
final class Student extends Person {

} //Student类不能被继承了
sealed class Teacher extends Person permits SeniorTeacher {

} //Teacher类只能被指定的子类继承
non-sealed class SeniorTeacher extends Teacher{}
non-sealed class Worker extends Person {

} //Worker类在被继承时,没有任何限制
class WatchWorker extends Worker{}
//class Farmer extends Person{}

相关文章:

  • 遇到git提交报错:413
  • Nginx常用工具
  • cs224w课程学习笔记-第10课
  • Linux系统使用lshw生成硬件报告方法
  • 循环神经网络 - LSTM 网络的各种变体
  • Go语言中的垃圾回收是如何工作的?
  • 面向基于发布-订阅的物联网网络的匿名 MQTT 分析
  • SVMSPro分布式综合安防管理平台-->以S3存储革新,开启智能安防新纪元
  • Git 分支整合策略:Cherry-pick、Merge、Rebase 三者之间对比
  • 【图像分类】【深度学习】系列学习文章目录
  • 部署Windows域
  • JAVA:SpringBoot 实现图片防盗链的技术指南
  • 24-栅格布局详解(CSS3)
  • 虚拟机和WSL对比
  • c# 运用策略模式与模板方法模式实例
  • 解决Ubuntu20.04安装ROS2的问题(操作记录)
  • LangGraph 概述
  • 栈栈栈栈栈
  • DDR4_CRC
  • html简易实现推箱子小游戏原理(易上手)
  • 网站架设教程/本网站三天换一次域名
  • 西安网站运营/网站模板下载
  • 龙岩建设网/seo网上课程
  • 成都旅游攻略景点必去/seo公司怎么样
  • 学生网站建设的总结与评价/app推广策略
  • the7 wordpress 下载/江门网站优化公司