java新特性

java新特性

文章目录

  • java新特性
    • OpenJDK和JDK的区别
    • java8
      • 函数式接口
      • Lambda表达式
      • Lambda表达式 vs 匿名类
      • 方法引用
      • 接口默认方法
      • Optional 类
      • Stream
      • 日期时间 API
    • java9
    • java10
    • java11
    • java12
    • 参考

OpenJDK和JDK的区别

  • openjdk是jdk的开放源代码版本,是以GPL形式开放出来的
  • 授权协议不同
  • openjdk不包含部署功能
  • openjdk源代码不完整
  • openjdk不能使用java商标

java8

函数式接口

  • 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口

  • 在java中通过@FunctionalInterface注解声明一个函数式接口,这个注解只是对你的接口类做了限制,限定只能有一个抽象方法,如果普通接口也满足函数式接口的要求那么这个注解并不是必须的,如下:

     @FunctionalInterface
      public  interface MathCalculate {
      		// 以下两个抽象接口只能保留一个,否则会报错
            int calculate(int a, int b);
    		//int calculate(int a);
        }
     
     //以下接口虽然没有@FunctionalInterface注解,但其满足只有一个抽象方法,因此也是函数式接口
      public  interface MathCalculate {
            int calculate(int a, int b);
        }
    
  • 有一点需要注意的是,如果一个接口定义了一个抽象方法,而这个抽象方法覆盖了java.lang.Object类里的public方法,那么这个方法不能算是抽象方法;这么说可能比较抽象,下面举例说明:

    //以下定义两个方法并不会报错,因为toString方法是属于java.lang.Object类里的public方法,因此不算是抽象方法
     @FunctionalInterface
      public  interface MathCalculate {
            int calculate(int a, int b);
    		String toString();
        }
    
  • 以上的规定也不难理解,因为所有具体类都会直接或间接继承Object类,因此Object类中的方法不能算是抽象方法

  • 函数式接口的实例可以由Lambda表达式,方法引用,构造引用三种方式来创建,以下用三种方式作下对比:

    
    public class AAA{
    	@FunctionalInterface
    	interface Test<T>{
    		T get();
    	}
    	@FunctionalInterface
    	interface Test2<T,U>{
    		boolean get(T t,U u);
    	}
     	public static void main(String[] args) {
    
    		//Lambda表达式
    		Test<AAA> t1=()-> new AAA();
    
    		//方法引用,又分为三种情况
    		AAA a=new AAA();
    		Test<AAA> t2=AAA::aaa;//类::类方法引用
    		Test<AAA> t3=a::aa;//对象::实例方法引用
    		Test2<String,String> t4=String::equals;//类::实例方法引用,第一个参数就是调用者,第二个参数就是被调用方法的参数
    		System.out.println(t4.get("aaa","bbb"));//输出false,相当于"aaa".equals("bbb")
    		System.out.println(t4.get("aaa","aaa"));//输出true
    
    		//构造引用
    		Test<AAA> t5=AAA::new;
     	}
    	public static AAA aaa(){
    		return new AAA();
    	}
    	public  AAA aa(){
    		return new AAA();
    	}
    }
    
  • java8在包java.util.function下定义了很多函数式接口,基本能满足日常的需求,如有特殊需求完全可以按照函数式接口的定义去自己实现

  • 核心接口

    函数式接口 参数类型 返回类型 用途
    Consumer T void 对类型T参数操作,无返回结果,包含方法 void accept(T t)
    Supplier T 返回T类型参数,方法时 T get()
    Function T R 对类型T参数操作,返回R类型参数,包含方法 R apply(T t)
    Predicate T boolean 断言型接口,对类型T进行条件筛选操作,返回boolean,包含方法 boolean test(T t)
  • 该包中的函数式接口

    序号 接口 & 描述
    1 BiConsumer
    代表了一个接受两个输入参数的操作,并且不返回任何结果
    2 BiFunction
    代表了一个接受两个输入参数的方法,并且返回一个结果
    3 BinaryOperator
    代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
    4 BiPredicate
    代表了一个两个参数的boolean值方法
    5 BooleanSupplier
    代表了boolean值结果的提供方
    6 Consumer
    代表了接受一个输入参数并且无返回的操作
    7 DoubleBinaryOperator
    代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。
    8 DoubleConsumer
    代表一个接受double值参数的操作,并且不返回结果。
    9 DoubleFunction
    代表接受一个double值参数的方法,并且返回结果
    10 DoublePredicate
    代表一个拥有double值参数的boolean值方法
    11 DoubleSupplier
    代表一个double值结构的提供方
    12 DoubleToIntFunction
    接受一个double类型输入,返回一个int类型结果。
    13 DoubleToLongFunction
    接受一个double类型输入,返回一个long类型结果
    14 DoubleUnaryOperator
    接受一个参数同为类型double,返回值类型也为double 。
    15 Function
    接受一个输入参数,返回一个结果。
    16 IntBinaryOperator
    接受两个参数同为类型int,返回值类型也为int 。
    17 IntConsumer
    接受一个int类型的输入参数,无返回值 。
    18 IntFunction
    接受一个int类型输入参数,返回一个结果 。
    19 IntPredicate
    接受一个int输入参数,返回一个布尔值的结果。
    20 IntSupplier
    无参数,返回一个int类型结果。
    21 IntToDoubleFunction
    接受一个int类型输入,返回一个double类型结果 。
    22 IntToLongFunction
    接受一个int类型输入,返回一个long类型结果。
    23 IntUnaryOperator
    接受一个参数同为类型int,返回值类型也为int 。
    24 LongBinaryOperator
    接受两个参数同为类型long,返回值类型也为long。
    25 LongConsumer
    接受一个long类型的输入参数,无返回值。
    26 LongFunction
    接受一个long类型输入参数,返回一个结果。
    27 LongPredicate
    R接受一个long输入参数,返回一个布尔值类型结果。
    28 LongSupplier
    无参数,返回一个结果long类型的值。
    29 LongToDoubleFunction
    接受一个long类型输入,返回一个double类型结果。
    30 LongToIntFunction
    接受一个long类型输入,返回一个int类型结果。
    31 LongUnaryOperator
    接受一个参数同为类型long,返回值类型也为long。
    32 ObjDoubleConsumer
    接受一个object类型和一个double类型的输入参数,无返回值。
    33 ObjIntConsumer
    接受一个object类型和一个int类型的输入参数,无返回值。
    34 ObjLongConsumer
    接受一个object类型和一个long类型的输入参数,无返回值。
    35 Predicate
    接受一个输入参数,返回一个布尔值结果。
    36 Supplier
    无参数,返回一个结果。
    37 ToDoubleBiFunction
    接受两个输入参数,返回一个double类型结果
    38 ToDoubleFunction
    接受一个输入参数,返回一个double类型结果
    39 ToIntBiFunction
    接受两个输入参数,返回一个int类型结果。
    40 ToIntFunction
    接受一个输入参数,返回一个int类型结果。
    41 ToLongBiFunction
    接受两个输入参数,返回一个long类型结果。
    42 ToLongFunction
    接受一个输入参数,返回一个long类型结果。
    43 UnaryOperator
    接受一个参数为类型T,返回值类型也为T

Lambda表达式

  • 语法:(parameters) -> expression或(parameters) ->{statements; }

  • 简单示例:

    // 1. 不需要参数,返回值为 5  
    () -> 5  
      
    // 2. 接收一个参数(数字类型),返回其2倍的值  
    x -> 2 * x  
      
    // 3. 接受2个参数(数字),并返回他们的差值  
    (x, y) -> x – y  
      
    // 4. 接收2个int型整数,返回他们的和  
    (int x, int y) -> x + y  
      
    // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
    (String s) -> System.out.print(s)
    
  • lambda可以用来替换匿名内部类,使得代码更加简洁

    Lambda表达式 vs 匿名类

    既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对二者做一个比较分析。一个关键的不同点就是关键字 this。匿名类的 this 关键字指向匿名类,而lambda表达式的 this 关键字指向包围lambda表达式的类。另一个不同点是二者的编译方式。Java编译器将lambda表达式编译成类的私有方法。使用了Java 7的 invokedynamic 字节码指令来动态绑定这个方法。

    // Java 8之前:
    new Thread(new Runnable() {
        @Override
        public void run() {
        System.out.println("Before Java8, too much code for too little to do");
        }
    }).start();
    
    //Java 8方式:
    new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
    
  • 计算器示例:

    public class Calculate {
        interface MathCalculate {
            int calculate(int a, int b);
        }
    
        public static void main(String[] args) {
    
            Calculate c=new Calculate();
            //加法器
            MathCalculate add = (a, b) -> a + b;
            //减法器
            MathCalculate sub = (a, b) -> a - b;
    
            System.out.println(c.calculate(1, 2, add)); //输出3
            System.out.println(c.calculate(1, 2, sub)); //输出-1
    
        }
    
        private int calculate(int a, int b, MathCalculate mc) {
            return mc.calculate(a, b);
        }
    }
    
  • forEach示例:

    // Java 8之前:
    List ls= Arrays.asList("1", "2", "3");
    for (String s: ls) {
        System.out.println(s);
    }
    
    // Java 8之后:
    List ls= Arrays.asList("1", "2", "3");
    ls.forEach(n -> System.out.println(n));
     
    // 使用Java 8的方法引用更方便,方法引用由::双冒号操作符标示,
    // 看起来像C++的作用域解析运算符
    ls.forEach(System.out::println);
    
  • Predicate示例:

    public static void main(args[]){
        List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
     
     	Predicate<String> p1 = (item) ->item.startsWith("J");
        System.out.println("Languages which starts with J :");
        filter(languages, p1);
    
        System.out.println("Languages which ends with a ");
        filter(languages, (item) ->item.startsWith("a"));
        
     	Predicate<String> p2= (item) ->item.length() > 3;
        System.out.println("Print language whose length greater than 3:");
        filter(languages, p2);
    
    	Predicate<String> p3 = p1.and(p2);
    	System.out.println("Print language whose length greater than 3 and starts with J:");
        filter(languages, p3);
    }
    
    public static void filter(List names, Predicate condition) {
        names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
            System.out.println(name + " ");
        });
    }
    
    输出:
    Languages which starts with J :
    Java
    Languages which ends with a
    Java
    Scala
    Print language whose length greater than 3:
    Java
    Scala
    Haskell
    Lisp
    Print language whose length greater than 3 and starts with J:
    Java
    
  • map与reduce示例:

    // 不使用lambda表达式为每个订单加上12%的税
    List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
    for (Integer cost : costBeforeTax) {
        double price = cost + .12*cost;
        System.out.println(price);
    }
     
    // 使用lambda表达式
    List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
    costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);
    
    
    // 为每个订单加上12%的税
    // 老方法:
    List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
    double total = 0;
    for (Integer cost : costBeforeTax) {
        double price = cost + .12*cost;
        total = total + price;
    }
    System.out.println("Total : " + total);
     
    // 新方法:
    List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
    double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get();
    System.out.println("Total : " + bill);
    

方法引用

  • 方法引用通过方法的名字来指向一个方法
    方法引用可以使语言的构造更紧凑简洁,减少冗余代码
    方法引用是一种更简洁易懂的Lambda表达式
    方法引用使用一对冒号::

  • 示例:

    Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));
    //方法引用,比上面的写法更简洁易懂
    Arrays.sort(stringsArray, String::compareToIgnoreCase);
    

接口默认方法

  • Java 8 新增了接口的默认方法。
    简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
    我们只需在方法名前面加个 default 关键字即可实现默认方法。
  • 同时还可以声明静态方法,示例如下:
    public interface Vehicle {
       default void print(){
          System.out.println("我是一辆车!");
       }
        // 静态方法
       static void blowHorn(){
          System.out.println("按喇叭!!!");
       }
    }
    

Optional 类

  • Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
    Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
    Optional 类的引入很好的解决空指针异常。

  • 示例:

    import java.util.Optional;
     
    public class Java8Tester {
       public static void main(String args[]){
       
          Java8Tester java8Tester = new Java8Tester();
          Integer value1 = null;
          Integer value2 = new Integer(10);
            
          // Optional.ofNullable - 允许传递为 null 参数
          Optional<Integer> a = Optional.ofNullable(value1);
            
          // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
          Optional<Integer> b = Optional.of(value2);
          System.out.println(java8Tester.sum(a,b));
       }
        
       public Integer sum(Optional<Integer> a, Optional<Integer> b){
        
          // Optional.isPresent - 判断值是否存在
            
          System.out.println("第一个参数值存在: " + a.isPresent());
          System.out.println("第二个参数值存在: " + b.isPresent());
            
          // Optional.orElse - 如果值存在,返回它,否则返回默认值
          Integer value1 = a.orElse(new Integer(0));
            
          //Optional.get - 获取值,值需要存在
          Integer value2 = b.get();
          return value1 + value2;
       }
    }
    
  • Optional中map与flatmap的区别:

    • map中获取的返回值自动被Optional包装,即返回值 -> Optional<返回值>
    • flatMap中返回值保持不变,但必须是Optional类型,即Optional<返回值> -> Optional<返回值>

Stream

  • Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
    Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
    Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码
  • 集合接口有两个方法生成流:
    • stream() :为集合创建串行流。
    • parallelStream() : 为集合创建并行流
  • 值得注意的是,parallelStream并不是线程安全的

日期时间 API

  • 新的日期API放在java.time包下,主要类是LocalDateTime,LocalDate,LocalTime,ZonedDateTime,ZoneId
     // 获取当前的日期时间
          LocalDateTime currentTime = LocalDateTime.now();
          System.out.println("当前时间: " + currentTime);//输出2019-04-26T18:53:48.134
            
          LocalDate date1 = currentTime.toLocalDate();
          System.out.println("date1: " + date1);//输出2019-04-26
            
          Month month = currentTime.getMonth();
          int day = currentTime.getDayOfMonth();
          int seconds = currentTime.getSecond();
            
          System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);//输出月: APRIL, 日: 26, 秒: 48
            
          LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2015);
          System.out.println("date2: " + date2);//输出2015-10-26T18:53:48.134
            
          // 12 december 2014
          LocalDate date3 = LocalDate.of(2015, Month.DECEMBER, 10);
          System.out.println("date3: " + date3);//输出2015-12-10
            
          // 22 小时 15 分钟
          LocalTime date4 = LocalTime.of(10, 16);
          System.out.println("date4: " + date4);//输出10:16
            
          // 解析字符串
          LocalTime date5 = LocalTime.parse("21:15:33");
          System.out.println("date5: " + date5);//输出21:15:33
    

java9

java10

java11

2018年发布,长期支持版本

java12

参考

Java 8 Lambda 表达式 | 菜鸟教程
http://www.runoob.com/java/java8-lambda-expressions.html
java8学习之深入函数式接口与方法引用 - cexo - 博客园
https://www.cnblogs.com/webor2006/p/8135873.html
Java8新特性 Lambda表达式 (二)方法引用和构造器引用 - 成长是一辈子的事 - CSDN博客
https://blog.csdn.net/xcy1193068639/article/details/80602513
jdk8 Optional使用详解 - 狂风骤起 - 博客园
https://www.cnblogs.com/xifenglou/p/9448683.html

你可能感兴趣的:(后台,android)