博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

JavaEE - 16JDK8新特性

Posted on 2020-12-10 17:58  Kingdomer  阅读(233)  评论(0编辑  收藏  举报

JavaEE - 16JDK8新特性 

(1)JDK8新特性介绍

  • Java 8(又称JDK 1.8)是Java语言开发的一个主要版本。
  • Java 8是Oracle公司于2014年3月发布,可以看成是自Java 5以来最具革命性的版本。
  • Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。
    • 速度更快
    • 代码更少(增加了新的语法:Lambda表达式
    • 强大的 Stream API
    • 便于并行
    • 最大化减少空指针异常: Optional
    • Nashorn引擎,允许在JVM上运行JS应用
  • 并行流与串行流
    • 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比较串行的流,并行的流可以很大程度上提高程序的执行效率。
    • Java 8中将并行进行了优化,我们可以很容易的对数据进行并行操作。
    • Stream API 可以声明性地通过 parallel()与 sequential()在并行流与顺序流之间进行切换。

 

(2)Lambda表达式

  • Lambda是一个匿名函数,可以理解为一段可以传递的代码(将代码像数据一样进行传递)。
    • 使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
    • Comparator<Integer> com = (o1,o2) -> Integer.compare(o1, o2);
      • ->:    lambda 操作符或箭头操作符
      • ->左边: lambda 形参列表(接口中的抽象方法的形参列表)
      • ->右边: lambda 体(重写的抽象方法的方法体)
  • Lambda左边:形参列表的参数类型可以省略(类型推断),只有一个参数,大括号可以省略
  • Lambda右边:Lambda体使用{}包裹;如果只有一条执行语句,可以省略{} 和return 语句
        Comparator<Integer> com = (o1,o2) -> Integer.compare(o1, o2);
        int rs = com.compare(32,3);
        System.out.println(rs);
        // 方法引用
        Comparator<Integer> com2 = Integer::compare;
        int rs2 = com2.compare(3,32);
        System.out.println(rs2);

(2.1)语法格式1: 无参,无返回值

   @Test
    public void test1(){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("天安门");
            }
        };
        r1.run();
        
        Runnable r2 = () -> System.out.println("我爱山东");
        r2.run();
    }

(2.2) 语法格式2: Lamdba需要一个参数,但是无返回值

        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con.accept("con ......");
        con1.accept("con1 ......");

(2.3)语法格式3: 数据类型可以省略,可由编译器推断得出,称为"类型推断"。

        Consumer<String> con2 = (s) ->{
            System.out.println(s);
        };
        con2.accept("con2 ......");

(2.4)语法格式4: Lamdba只需要一个参数时,参数的小括号可以省略

        Consumer<String> con3 = s -> {
            System.out.println(s);
        };
        con3.accept("con3 ......");

(2.5)语法格式5: Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值

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

(2.6)语法格式6: 当lambda体只有一条语句时, return 与大括号 如有,都可以省略

        Comparator<Integer> com = (o1,o2) -> Integer.compare(o1, o2);
        int rs = com.compare(32,3);
        System.out.println(rs);

 

(3)函数式(Functional)接口

(3.1)什么是函数式接口

  • 只包含一个抽象方法的接口,称为函数式接口
  • 可以通过Lambda表达式来创建该接口的对象。
    • 若Lambda表达式抛出一个受检异常(非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明。
  • 在一个接口上使用@FunctionalInterface注解,可以检查是否是一个函数式接口。
    • 同时javaDoc也会包含一条声明,说明这个接口是函数式接口。
  • 在java.util.function包下定义了Java 8的丰富的函数式接口
@FunctionalInterface
public interface MyInterface {
    void method1();
//    void method2();
}

(3.2)理解函数式接口

  • 随着python、scala等语言的兴起和新技术挑战,为支持更加广泛的技术要求,java不但可以支持OOP,还可以支持OOF(面向函数编程)
  • 在Java 8中,Lambda表达式是对象,而不是函数,它必须依附于一类特别的对象类型 -- 函数式接口
  • 在Java 8中,Lambda表达式是一个函数式接口的实例。只要一个对象是函数式接口的实例,就可以用Lambda表达式来表示。
  • 以前用匿名实现类表示的都可以用Lambda表达式来写。

(3.3)Java内置核心函数式接口

函数式接口 参数类型 返回类型 用途
Consumer<T>  消费型接口  T void 对类型为T的对象应用操作,包含方法: void accept(T t)
Supplier<T>  供给型接口 T 返回类型为T的对象, 包含方法: T get()
Functional<T,R> 函数型接口 T R 对类型为T的对象应用操作,并返回结果为R类型的对象。R apply(T t)
Predicate<T> 断定型接口 T boolean 确定类型为T的对象是否满足某约束,返回boolean值。 boolean test(T t)
BiFunction<T,U,R> T,U R 对类型为T,U参数应用操作,返回R类型的结果。 R apply(T t, U u);
UnaryOperator<T>  Functional子接口 T T 对类型为T的对象进行一元运算,并返回T类型的结果。 T apply(T t)
BinaryOperator<T> BiFunction子接口 T,T T 对类型为T的对象进行二元运算,并返回T类型的结果。 T apply(T t1,T t2)
BiConsumer<T,U> T,U void 对类型为T,U参数应用操作。void accept(T t, U u)
BiPredicate<T,U> T,U boolean boolean test(T t, U u)

ToIntFunction<T>

ToLongFunction<T>

ToDoubleFunction<T>

T

int

long

double

分别计算int、long、double值的函数

IntFunction<R>

LongFunction<R>

DoubleFunction<R>

int

long

double

R 参数分别为int、long、double类型的函数
 
 
 
 
 
 
 
 
 
 
 
 
 

 

 

 

 

 

 

 

 

 

 

 

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

    @Test
    public void test1(){
        happyTime(50, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("买吃的:"+ aDouble);
            }
        });

        happyTime(60, money -> System.out.println("买喝的:" + money));
    }

Predicate 根据条件过滤集合中元素

    // 根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定。
    public List<String> filterString(List<String> list, Predicate<String> pre){
        ArrayList<String> filterList = new ArrayList<>();
        for(String s : list){
            if(pre.test(s)){
                filterList.add(s);
            }
        }
        return filterList;
    }

    @Test
    public void test2(){
        List<String> list = Arrays.asList("北京","南京","东京","天津","西京");
        List<String> rsList = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("京");
            }
        });
        System.out.println(rsList);  //[北京, 南京, 东京, 西京]

        List<String> filterStrs = filterString(list, s -> s.contains("京"));
        System.out.println(filterStrs);
    }

 

(4)方法引用与构造器引用

(4.1)方法引用(Method References)

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
  • 方法引用可以看做是Lambda表达式深层次的表达。方法引用就是Lambda表达式,函数式接口的一个实例
    • 通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
  • 要求: 实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致。(针对情况1和情况2)
  • 格式: 使用操作符"::" 将类(或对象)与方法名分隔开来。如下三种主要使用情况:
    • 对象::实例方法名
    • 类::静态方法名
    • 类::实例方法名

情况1: 对象::实例方法

        // Consumer中的void accept(T t)
        Consumer<String> con = str -> System.out.println(str);
        con.accept("北京");
        // PrintStream 中的 void println(T t)
        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        con2.accept("南京");

Supplier中的T get() / Employee中的String getName()

        Employee emp = new Employee(1010,"Tom",23,5000);
        Supplier<String> sup = () -> emp.getName();
        System.out.println(sup.get());

        Supplier<String> sup2 = emp::getName;
        System.out.println(sup.get());

情况2:  类::静态方法  

Comparator中的 int compare(T t1, T t2) / Integer 中的 int compare(T t1, T t2) 

        Comparator<Integer> com = (t1,t2) -> Integer.compare(t1,t2);
        System.out.println(com.compare(12,21));   // -1

        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com2.compare(21,12));  // 1

Function中的 R apply(T t) / Math中的Long round(Double d)

       Function<Double, Long> func = new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        System.out.println(func.apply(12.6));  // 13

        Function<Double, Long> fun2 = d -> Math.round(d);
        System.out.println(fun2.apply(12.3));  // 12

        Function<Double, Long> fun3 = Math::round;
        System.out.println(fun3.apply(12.4));  // 12

情况3: 类::实例方法

Comparator 中的int compare(T t1, T t2) / String 中的 int t1.compareTo(t2) 

        Comparator<String> com = (s1,s2) -> s1.compareTo(s2);
        System.out.println(com.compare("abc","abd"));  // -1

        Comparator<String> com1 = String::compareTo;
        System.out.println(com1.compare("As","as"));  // -32

BiPredicate 中的 boolean test(T t1, T t2) / String 中的 boolean t1.equals(t2)

        BiPredicate<String, String> pre = (s1,s2) -> s1.equals(s2);
        System.out.println(pre.test("abc", new String("abc")));  // true
        
        BiPredicate<String, String> pre2 = String::equals;       
        System.out.println(pre2.test("abc","abd"));              // false

Function 中的 R apply(T t) / Employee 中的 String getName()

        Employee employee = new Employee(1010,"Tom",23,5000);
        Function<Employee,String> func = e -> e.getName();
        System.out.println(func.apply(employee));

        Function<Employee,String> fun2 = Employee::getName;
        System.out.println(fun2.apply(employee));

(4.2)构造器引用

Supplier 中的 get()  

        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println(sup.get());

        Supplier<Employee> sup2 = () -> new Employee();
        System.out.println(sup2.get());
        Supplier<Employee> sup3 = Employee::new;
        System.out.println(sup3.get());

Function 中的 R apply(T t)

        Function<Integer,Employee> fun = id -> new Employee(id);
        Employee employee = fun.apply(1001);
        System.out.println(employee);

        Function<Integer,Employee> fun2 = Employee::new;
        Employee employee2 = fun2.apply(1002);
        System.out.println(employee2);

BiFunction中的 R apply(T t, U u)

        BiFunction<Integer,String, Employee> fun = (id, name) -> new Employee(id,name);
        Employee employee = fun.apply(1001,"Tom");
        System.out.println(employee);

        BiFunction<Integer,String, Employee> fun2 = Employee::new;
        Employee employee2 = fun2.apply(1002,"Jerry");
        System.out.println(employee2);

(4.3)数组引用

Function 中的 R apply(T t)

        Function<Integer, String[]> func = length -> new String[length];
        String[] arr = func.apply(5);
        System.out.println(Arrays.toString(arr));

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