JDK版本特性(一)JDK8

发布时间 2023-12-18 13:10:28作者: Tod4

Java8新特性

  • 速度更快:如HashMap底层使用红黑树
  • 代码更少
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常:Optional
  • Nashorn引擎:在JVM上运行JS应用

1 Lambda表达式

1.1 Lambda表达式的格式
(o1, o2) -> Integer.compare(o1, o2)
  • ->:lambda操作符 或者 箭头操作符
  • 左边:lambda形参列表,也即是接口中抽象方法的形参列表
  • 右边:lambda体重写的抽象方法的方法体
  • Lambda表达式的本质是作为接口的实例
1.2 为什么使用Lambda表达式
  • Lambda表达式是一个匿名函数,可以理解为一段可以传递的代码(将代码像数据一样进行传递)
  • 可以写出更简洁、更灵活的代码
  • Lambda表达式只能用于只含有一个抽象方法的、并且被@FunctionalInterface标识的接口
  • ->即为Lambda操作符或者箭头操作符
  • :: 为方法引用
    public static void main(String[] args) {
        Runnable runnable1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("111");
            }
        };
        runnable1.run();

        Runnable runnable2 = () -> {
            System.out.println("222");
        };
        runnable2.run();

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

        Comparator<Integer> comparator2 = (o1, o2) -> Integer.compare(o1, o2);
        System.out.println(comparator2.compare(2, 1));

        Comparator<Integer> comparator3 = Integer::compare;
        System.out.println(comparator3.compare(1, 1));

    }
1.3 Lambda的使用

​ 总结:

  • ->左边的Lambda形参列表
    • Lambda形参列表的参数类型都可以省略(类型推断)
    • 如果只有一个参数则可以省略小括号
  • ->右边的Lambda体
    • 如果只有一条执行语句,则可以省略大括号,如果有返回值,return关键字需要省略

​ 情况举例:

  • 1 无参、无返回值:

            Runnable runnable2 = () -> {
                System.out.println("222");
            };
            runnable2.run();
    
  • 2 需要参数,但无返回值:

    Consumer<String> consumer = new Consumer<String>() {
                @Override
                public void accept(String s) {
                    System.out.println(s);
                }
            };
            consumer.accept("123");
    
            Consumer<String> consumer1 = (String s) -> {
                System.out.println(s);
            };
            consumer1.accept("123");
    
  • 3 数据类型可以省略,因为编译器可以推断得出,称为类型推断,像使用泛型创建对象的时候就不必写后面的类型,也是一种编译时的类型推断

            Consumer<String> consumer1 = (s) -> {
                System.out.println(s);
            };
            consumer1.accept("123");
    
  • 4 Lambda若只需要一个参数,则参数的小括号可以省略

            Consumer<String> consumer1 = s -> {
                System.out.println(s);
            };
            consumer1.accept("123");
    
  • 5 Lambda需要两个或者两个以上的参数,且可以有返回值

            Comparator<Integer> comparator2 = (o1, o2) -> {
                return Integer.compare(o1, o2);
            };
    
  • 6 如果语句只有一条,则大括号可以省略,且带返回值的return可以省略

            Comparator<Integer> comparator2 = (o1, o2) -> Integer.compare(o1, o2);
            System.out.println(comparator2.compare(2, 1));
    

2 函数式接口

  • Lambda在使用的时候,准确来说是作为函数式接口的实例存在

  • 如果接口中只声明了一个抽象方法,则这个接口就是函数式接口

  • @FunctinalInterface仅仅起到一个标识检查的作用,检查标识的接口是否满足函数式接口的定义

    @FunctionalInterface
    public interface MyFunctionalInterface {
        void method1();
        //void method2();
    }
    
  • 以前使用匿名实现类表示的,现在都可以使用Lambda表达式来写

2.1 Java内置的四大核心函数式接口

​ 出现这四种接口,均可以使用Lambda表达式进行接口实例化

  • 消费型接口 Consumer<T>:void accept(T t),有参数无返回值

    public class LambdaTest2 {
        @Test
        public void test() {
            happyTime(500, money -> System.out.println("消费" + 500));
            happyTime(500, System.out::println);
        }
    
        public void happyTime(double money, Consumer<Double> consumer) {
            consumer.accept(money);
        }
    }
    
    
  • 供给型接口 Supplier:T get(),无参数有返回值

  • 函数型接口 Funcational<R, T>:R apply(T t),有参数有返回值

  • 断定型接口 Predicate<T>:boolean test(T t),有参数,有返回值且为boolean

        @Test
        public void test() {
            //happyTime(500, money -> System.out.println("消费" + 500));
            List<String> list = Arrays.asList("北京", "南京", "天津");
            List<String> strings = filterString(list, str -> str.contains("京"));
            System.out.println(strings);
        }
    
    	public List<String> filterString(List<String> list, Predicate<String> predicate) {
            List<String> filterStringList = new ArrayList<>();
            for(String str : list) {
                if(predicate.test(str)) {
                    filterStringList.add(str);
                }
            }
            return filterStringList;
        }
    
2.2 其他接口

3 方法引用

  • 当要传递给Lambda体的操作,已经有相同的实现方法的时候,就可以使用方法引用

    相同的实现方法要求实现接口的抽象方法的参数列表和返回值类型必须和参数引用的一致

  • 方法引用就是一个lambda表达式,也就是函数接口的一个实例

  • 就是通过方法的名字指向一个方法,可以认为是Lambda的一个语法糖

  • 具体分为下面三种情况:

    • 对象 :: 非静态方法
    • 类 :: 静态方法
    • 类 :: 非静态方法

类 :: 静态方法

    @Test
    public void test1() {
        Consumer<String> consumer = str -> System.out.println(str);
        consumer.accept("Hello");


        Consumer<String> consumer1 = System.out::println;
        consumer.accept("World!");
    }

如Consumer的参数列表返回值类型和方法引用System.out::println的相同,因此可以直接使用方法引用进行替换。

对象 :: 非静态方法

    @Test
    public void test2() {
        Employee employee = new Employee(1001L, "Tom", 5600.0);
        //Supplier<String> supplier = () -> employee.getName();
        Supplier<String> supplier = employee::getName;
        System.out.println(supplier.get());

    }

4 构造器引用

  • 和方法引用类似

  • 无参构造器对应supplier供给型接口 T get()

    @Test
    public void test() {
        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println(sup.get());
        
        Supplier<Employee> sup1 = Employee::new;
        System.out.println(sup1.get());
    }
    
  • 有参构造器对应Function函数型接口 R apply(T t),如果有两个参数则使用BiFunction R apply(T t, S s)

        @Test
        public void testAllConstruct() {
            Function<String, Employee> fun = Employee::new;
            System.out.println(fun.apply("zhang san"));
    
        }
    
        @Test
        public void testBiAllConstructor() {
            BiFunction<String, Integer, Employee> fun = Employee::new;
            System.out.println(fun.apply("zhangsan", 18));
        }
    

5 数组引用

    @Test
    public void testArrayRef() {
        Function<Integer, String[]> fun = new Function<Integer, String[]>() {
            @Override
            public String[] apply(Integer integer) {
                return new String[integer];
            }
        } ;
        System.out.println(Arrays.toString(fun.apply(10)));

        Function<Integer, String[]> fun2 = String[]::new;
        System.out.println(Arrays.toString(fun2.apply(10)));
    }