Java8-17新特性(宋红康2023笔记)

发布时间:2023年12月20日

Java8-17新特性

JDK8新特性

lambda表达式

格式

lambda形参列表(要重写的接口中的抽象方法的形参列表) -> lambda体(接口的实现类要重写的方法的方法体)

本质

一方面,lambda作为接口的实现类的对象;另一方面,lambda是一个匿名函数

函数式接口

是什么? 接口中仅仅声明有一个抽象方法

只有给函数式接口提供实现类的对象时,我们才可以使用lambda表达式

4个基本的函数式接口

接口对应抽象方法
消费型接口Consumervoid accept(T t)
供给型接口SupplierT get()
函数型接口Function<T,R>R apply(T t)
判断型接口Predicateboolean test(T t)
实例总结
package com.atguigu.newfeatures;

import org.junit.Test;

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

public class LambdaTest {
    //格式1:无参 无返回值
    @Test
    public void test1() {
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱天安门");
            }
        };
        r1.run();
        System.out.println("=============================");
        Runnable r2 = () -> {
            System.out.println("我爱天安门");
        };
        r2.run();
    }
    //格式2:有参 无返回值
    @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("定义不一样");
    }
    //格式3:数据类型可以由编译器推断得出
    @Test
    public void test3() {
        Consumer<String> c1 = (String s) -> {
            System.out.println(s);
        };
        c1.accept("你想干什么,如果大学可以重来");
        System.out.println("=============================");
        Consumer<String> c2 = (s) -> {
            System.out.println(s);
        };
        c2.accept("我想睡觉");
    }
    //格式4:只需要一个参数时,参数的小括号可以省略
    @Test
    public void test4() {
        Consumer<String> c1 = (String s) -> {
            System.out.println(s);
        };
        c1.accept("关于我是谁,双枪会给出答案");
        System.out.println("=============================");
        Consumer<String> c2 = s -> {
            System.out.println(s);
        };
        c2.accept("关于我是谁,双枪会给出答案");
    }
    //格式5:有两个及以上的参数,多条执行语句,有返回值
    @Test
    public void test5() {
        Comparator<Integer> con1 = 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(con1.compare(12,21));
        System.out.println("=============================");
        Comparator<Integer> con2 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(con2.compare(12,21));
    }
    //格式6:lambda体仅有一条语句,return与大括号都可以省略
    @Test
    public void test6() {
        Comparator<Integer> con1 = (o1, o2) -> {
            return o1.compareTo(o2);
        };
        System.out.println(con1.compare(12,21));
        System.out.println("=============================");
        Comparator<Integer> con2 = (o1, o2) -> o1.compareTo(o2);
        System.out.println(con2.compare(12,16));
    }
}

方法引用

格式

类(或者对象) :: 方法名

本质

方法引用作为了函数式接口的实例

具体使用情况

1.对象 :: 实例方法

要求:函数式接口的抽象方法**a(get)与其内部实现时调用的对象的某个方法b(getName)**的形参列表和返回值类型都相同(满足多态)。

注意:b是非静态方法,需要对象调用

2.类 :: 静态方法

要求:函数式接口的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值类型都相同(满足多态)。

注意:b是静态方法,需要类调用

3.类 :: 实例方法

要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的返回值相同。

同时,抽象方法a中有n个参数,方法b中有n-1个参数,而且抽象方法a的第一个参数作为方法b的调用者抽象方法a的后n-1个参数与方法b的n-1个参数的类型相同(或一致)

注意:b是非静态方法,需要对象调用。形式上,写出对象a所属的类

实例总结
package com.atguigu.newfeatures;

import org.junit.Test;

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

public class MethodsTest {
    //情况1:对象 :: 实例方法
    @Test
    public void test1() {
        Consumer<String> con1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("藏好了吗,再给你一首歌的时间");
        Consumer<String> con2 = s -> System.out.println(s);
        con2.accept("藏好了吗,再给你一首歌的时间");
        Consumer<String> con3 = System.out::println;
        con3.accept("藏好了吗,再给你一首歌的时间");
    }

    @Test
    public void test2() {
        Hero mk = new Hero("暗影游猎", 1);
        Supplier<String> sup1 = new Supplier<String>() {
            @Override
            public String get() {
                return mk.getName();
            }
        };
        System.out.println(sup1.get());
        Supplier<String> sup2 = () -> mk.getName();
        System.out.println(sup2.get());
        Supplier<String> sup3 = mk::getName;
        System.out.println(sup3.get());
    }

    //情况2:类 :: 实例方法
    @Test
    public void test3() {
        Comparator<Integer> c1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        System.out.println(c1.compare(12, 21));
        Comparator<Integer> c2 = (o1, o2) -> Integer.compare(o1, o2);
        System.out.println(c2.compare(25, 66));
        Comparator<Integer> c3 = Integer::compare;
        System.out.println(c3.compare(89, 88));
    }

    @Test
    public void test4() {
        Function<Double, Long> fun1 = new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        Function<Double, Long> fun2 = aDouble -> Math.round(aDouble);
        Function<Double, Long> fun3 = Math::round;
    }

    //情况3:类 :: 实例方法
    @Test
    public void test5() {
        Comparator<String> com1 = new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare("EstarPro", "KSG"));
        Comparator<String> com2 = (o1, o2) -> o1.compareTo(o2);
        System.out.println(com2.compare("ag", "ttg"));
        Comparator<String> com3 = String::compareTo;
    }

    @Test
    public void test6() {
        BiPredicate<String, String> biPredicate1 = new BiPredicate<String, String>() {
            @Override
            public boolean test(String s1, String s2) {
                return s1.equals(s2);
            }
        };
        System.out.println(biPredicate1.test("hero", "wolves"));
        BiPredicate<String, String> biPredicate2 = (s1, s2) -> s1.equals(s2);
        System.out.println(biPredicate2.test("edgm", "rngm"));
        BiPredicate<String, String> biPredicate3 = String::equals;
        System.out.println(biPredicate3.test("t", "u"));
    }

    @Test
    public void test7() {
        Hero al = new Hero("祈雪灵祝",2);
        Function<Hero, String> fun1 = new Function<Hero, String>() {
            @Override
            public String apply(Hero hero) {
                return hero.getName();
            }
        };
        System.out.println(fun1.apply(al));
        Function<Hero, String> fun2 = (hero -> hero.getName());
        System.out.println(fun2.apply(al));
        Function<Hero, String> fun3 = Hero::getName;
        System.out.println(fun3.apply(al));
    }

}

class Hero {
    public String name;
    public int id;

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

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

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

构造器引用+数组引用

格式

类名 :: new

数组名[] :: new

说明

构造器引用

  • 调用了类名对应的类中的某个确定的构造器
  • 具体调用的是类中的哪一个构造器取决于函数式接口的抽象方法形参列表
实例总结
package com.atguigu.newfeatures;

import org.junit.Test;

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

public class ConstructorTest {
    @Test
    public void test1() {
        Supplier<Hero> supplier1 = new Supplier<Hero>() {
            @Override
            public Hero get() {
                return new Hero();
            }
        };
        System.out.println(supplier1.get());

        Supplier<Hero> supplier2 = Hero::new;
        System.out.println(supplier2.get());
    }

    @Test
    public void test2() {
        Function<Integer, Hero> function1 = new Function<Integer, Hero>() {
            @Override
            public Hero apply(Integer integer) {
                return new Hero(integer);
            }
        };
        System.out.println(function1.apply(12));

        Function<Integer, Hero> function2 = Hero::new;
        System.out.println(function2.apply(22));
    }

    @Test
    public void test3() {
        BiFunction<Integer, String, Hero> biFunction1 = new BiFunction<Integer, String, Hero>() {
            @Override
            public Hero apply(Integer integer, String s) {
                return new Hero(s, integer);
            }
        };
        System.out.println(biFunction1.apply(55, "老板"));

        BiFunction<String, Integer, Hero> biFunction2 = Hero::new;
        System.out.println(biFunction2.apply("Tony", 17));
    }

    @Test
    public void test4() {
        Function<Integer, Hero[]> function1 = new Function<Integer, Hero[]>() {
            @Override
            public Hero[] apply(Integer integer) {
                return new Hero[integer];
            }
        };
        System.out.println(function1.apply(11).length);

        Function<Integer, Hero[]> function2 = Hero[]::new;
        System.out.println(function2.apply(12).length);
    }
}

常用的函数式接口

函数式接口函数描述符
PredicateT->boolean
ConsumerT->void
Function<T,R>T->R
Supplier()->T
UnaryOperatorT->T
BinaryOperator(T,T)->T
BiPredicate<L,R>(L,R)->boolean
BiConsumer<T,U>(T,U)->void
BiFunction<T,U,R>(T,U)->R

Stream API

Stream API VS 集合
  • Stream API 关注的是多个数据的计算,面向CPU
  • 集合关注的是数据的存储,面向内存
使用说明
  1. Stream 自己不会存储元素
  2. Stream 不会改变源对象 他们会返回一个持有结果的新Stream
  3. Stream 操作是延迟执行的 意味着他们会等到需要结果的时候才执行
  4. Stream 一旦执行了终止操作 就不能调用其他中间操作或终止操作了
Stream 执行流程
  1. Stream的实例化
  2. 一系列的中间操作
  3. 执行终止操作
实例总结
package com.atguigu.newfeatures;

import org.junit.Test;

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

public class StreamAPITest {
    @Test
    //创建方式一 集合
    public void test1() {
        List<Employee> list = EmployeeData.getEmployees();
        //顺序流
        Stream<Employee> stream1 = list.stream();
        //并行流
        Stream<Employee> stream2 = list.parallelStream();
    }
    @Test
    //创建方式二 数组
    public void test2() {
        Integer[] arr = new Integer[]{1,2,3,4,5};
        Stream<Integer> stream = Arrays.stream(arr);
        int[] intArr = new int[]{1,2,3,4};
        IntStream intStream = Arrays.stream(intArr);
    }
    @Test
    //创建方式三 of()
    public void test3() {
        Stream<String> stream = Stream.of("aa", "bb", "cc");
    }

    @Test
    public void test4() {
        //查询薪水大于7000的员工 过滤
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        stream.filter(e -> e.getSal() > 7000).forEach(System.out::println);
        System.out.println();
        //截断
        list.stream().limit(4).forEach(System.out::println);
        System.out.println();
        //跳过
        list.stream().skip(5).forEach(System.out::println);
        System.out.println();
        //去重 (注意要重写hashCode和equals方法)
        list.add(new Employee(1007, "任正非", 24, 4333.38));
        list.add(new Employee(1007, "任正非", 24, 4333.38));
        list.stream().distinct().forEach(System.out::println);
    }

    //映射map
    @Test
    public void test5() {
        //转换为大写
        List<String> list = Arrays.asList("aa","bb","cc","dd");
        list.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
        list.stream().map(String::toUpperCase).forEach(System.out::println);

        //获取员工姓名大于3的员工的姓名
        List<Employee> employees = EmployeeData.getEmployees();
        employees.stream().filter(e -> e.getName().length() > 3).map(e -> e.getName()).forEach(System.out::println);
        employees.stream().map(e -> e.getName()).filter(name -> name.length() > 3).forEach(System.out::println);
        employees.stream().map(Employee::getName).filter(name -> name.length() > 3).forEach(System.out::println);
    }

    //排序sorted
    @Test
    public void test6() {
        Integer[] arr1 = new Integer[]{12,33,374,293};
        Arrays.stream(arr1).sorted().forEach(System.out::println);

        String[] arr2 = new String[]{"GG","JJ","MM","BB","NN"};
        Arrays.stream(arr2).sorted((s1,s2)->s1.compareTo(s2)).forEach(System.out::println);
        System.out.println();
        Arrays.stream(arr2).sorted(String::compareTo).forEach(System.out::println);

    }

    //匹配与查找
    @Test
    public void test7() {
        List<Employee> list = EmployeeData.getEmployees();
        //年龄是否都大于18
        System.out.println(list.stream().allMatch(e -> e.getAge() > 18));

        //是否存在年龄大于18岁的
        System.out.println(list.stream().anyMatch(e -> e.getAge() > 18));

        //返回第一个对象
        System.out.println(list.stream().findFirst());

        //返回元素个数
        System.out.println(list.stream().count());

        //返回最高工资员工
        System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSal(), e2.getSal())).get().getSal());

        //返回最低工资员工
        System.out.println(list.stream().map(Employee::getSal).min((sal1, sal2) -> Double.compare(sal1, sal2)).get());
        System.out.println(list.stream().map(Employee::getSal).min(Double::compare).get());

        //遍历list
        list.forEach(System.out::println);
    }

    //归约
    @Test
    public void test8() {
        //计算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(10, (x1, x2) -> x1 + x2));

        //计算员工工资总和
        List<Employee> employeeList = EmployeeData.getEmployees();
        System.out.println(employeeList.stream().map(e -> e.getSal()).reduce(Double::sum));
    }

    //收集
    @Test
    public void test9() {
        List<Employee> list = EmployeeData.getEmployees();
        List<Employee> employeeList = list.stream().filter(e -> e.getSal() > 5000).collect(Collectors.toList());
        employeeList.forEach(System.out::println);
    }
}

API的变化

Optional类
  1. 为什么需要Optional类->为了避免代码中空指针异常
  2. 如何实例化->static <T> Optional<T> ofNullable(T value)
  3. 常用方法->orElse(T other)

示例:

package com.atguigu.newfeatures;

import org.junit.Test;

import java.util.Optional;

public class OptionalTest {
    @Test
    public void test1() {
        String star = "迪丽热巴";
//        star = null;

        Optional<String> optional = Optional.ofNullable(star);

        System.out.println(optional.get());

        String finalstar = "杨幂";
        String s = optional.orElse(finalstar);

        System.out.println(s.toString());
    }
}

JDK9新特性

Java的REPL工具:jShell命令

Java拥有了像Python和Scala语言的REPL工具(交互式编程环境):jShell

可在命令行里直接声明变量,计算表达式,执行语句。无需使用main这句“废话”。

异常处理之try-catch资源关闭

try的前面可以定义流对象,try后面的()中可以直接引用流对象的名称。在try代码执行完毕后,流对象也可以释放掉,也不用写finally了。

格式:

A a = new A();
B b = new B();
try(a;b) {
    异常代码
} catch(异常类名 变量名) {
    异常处理逻辑
}

JDK10新特性

var-局部变量类型推断

不能使用的情况:

  • 声明成员变量
  • 声明数组变量,并为数组静态初始化
  • 方法返回值类型
  • 方法参数类型
  • 没有初始化的方法内的局部变量声明
  • catch块中的异常类型
  • 函数式接口类型

示例:

var list = new ArrayList<>();

JDK12新特性

switch+模式匹配

  • JDK12预览特性
  • JDK13二次预览
  • JDK14转正特性
  • JDK17预览特性,模式匹配

传统switch声明语句的弊端:

  • 匹配自上而下,忘记写break,case不论匹配与否都会执行
  • 所有case共用一个块范围,不同case语句定义的变量名不能重复
  • 不能在一个case里写多个执行结果一致的条件
  • 整个switch不能作为表达式返回值

示例:

package com.atguigu.newfeatures;

import org.junit.Test;

public class SwitchTest {
    //->操作符
    @Test
    public void test1() {
        int n = 1;
        switch (n) {
            case 1 -> System.out.println(1);
            case 2,3,4 -> System.out.println(2);
            default -> throw new RuntimeException("num" + n);
        }

        int m = 3;
        int res = switch (m) {
            case 1 -> 1;
            case 2,3,4 -> 2;
            default -> throw new RuntimeException("num" + m);
        };
        System.out.println(res);
    }

    //yield相当于return
    //与return的区别是return退出整个switch 而yield仅仅退出case
    @Test
    public void test2() {
        int m = 3;
        int res = switch (m) {
            case 1 -> {
                yield 1;
            }
            case 2,3,4 -> {
                yield 2;
            }
            default -> throw new RuntimeException("num" + m);
        };
        System.out.println(res);
    }   
}

模式匹配:

之前版本:

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

JDK17:

static String formatterSwitch(Object o) {
    String formatted = switch(o) {
        case Integer i:
            yield "int" + i;
        case Long l:
            yield "long" + l;
    }
    return formatted;
}

JDK13新特性

文本块的使用

  • JDK13的预览特性
  • JDK14中二叉预览特性
  • JDK15中转正

示例:

package com.atguigu.newfeatures;

import org.junit.Test;

public class BlockTest {
    @Test
    public void test1() {
        String s0 = "<el-alert\n" +
                "    title=\"成功提示的文案\"\n" +
                "    type=\"success\">\n" +
                "  </el-alert>";
        System.out.println(s0);

        String s1 = """
                <el-alert
                    title="成功提示的文案"
                    type="success">
                </el-alert>
                """;
        System.out.println(s1);

        String s2 = """
                <el-alert \
                    title="成功提示的文案" \
                    type="success">
                \s</el-alert>
                """;
        System.out.println(s2);
    }
}

JDK14新特性

instanceOf模式匹配

JDK14前,遇见一个女生,先谈恋爱再…

JDK14后,遇见一个女生,孩子名字都想好了

  • JDK14预览
  • JDK15第二次预览
  • JDK16转正

示例:

if(obj instanceof String) {
    String str = (String) obj;
    ...
}

等于以下代码:

if (obj instanceof String str) {
    ...
}

Record

  • JDK14预览
  • JDK15第二次预览
  • JDK16转正

定义一个类:

package com.atguigu.newfeatures;

import java.util.Objects;

public class Order {
    public int id;
    public String name;

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

    public int id() {
        return id;
    }

    public String name() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Order order = (Order) o;
        return id == order.id && Objects.equals(name, order.name);
    }

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

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

等价于:

package com.atguigu.newfeatures;

public record Order1(int id, String name) {
}

示例:

package com.atguigu.newfeatures;

import org.junit.Test;

import java.util.HashSet;

public class OrderTest {
    @Test
    public void test1() {
        Order order1 = new Order(1,"马云");
        System.out.println(order1);

        System.out.println(order1.id());
        System.out.println(order1.name());

        Order order2 = new Order(1,"马云");
        System.out.println(order1.equals(order2));

        HashSet<Order> set = new HashSet<>();
        set.add(order1);
        set.add(order2);
        System.out.println(set);
    }

    @Test
    public void test2() {
        Order1 order1 = new Order1(1,"马云");
        System.out.println(order1);

        System.out.println(order1.id());
        System.out.println(order1.name());

        Order1 order2 = new Order1(1,"马云");
        System.out.println(order1.equals(order2));

        HashSet<Order1> set = new HashSet<>();
        set.add(order1);
        set.add(order2);
        System.out.println(set);
    }
}

注意:

  • getter以变量名来命名

record声明的类中可以定义静态字段、静态方法、构造器或实例方法,例如:

static String info = "you are a man";

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

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

public void eat() {
    System.out.println("人吃饭");
}

不能在record声明的类中定义实例字段,类不能声明为abstract,不能声明显式父类等

final int age;
abstract record Dog(int id){}
record Cat(int id) extends Thread{}

JDK15新特性

密封类

  • JDK15预览
  • JDK16二次预览
  • JDK17转正

示例:

package com.atguigu.newfeatures;

//密封类只能被指定的类继承
public sealed class Person permits A, B, C{
}

//指定的子类必须是final sealed non-sealed 之一
final class A extends Person {}

sealed class B extends Person permits D{}

non-sealed class D extends B{}

non-sealed class C extends Person{}
文章来源:https://blog.csdn.net/fffffall/article/details/135033529
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。