java新特性

32 篇文章 0 订阅

java新特性

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下定义了很多函数式接口,基本能满足日常的需求,如有特殊需求完全可以按照函数式接口的定义去自己实现

  • 核心接口

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值