殁舞

导航

 

前言

Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。

 

简介

Java8 新增了非常多的特性,主要关注以下几个(摘自官网,机翻):

  • Java编程语言

    • Lambda Expressions是一种新的语言功能,已在此版本中引入。它们使您可以将功能视为方法参数,或将代码视为数据。Lambda表达式允许您更紧凑地表示单方法接口(称为功能接口)的实例。

    • 方法引用为已经具有名称的方法提供易于阅读的lambda表达式。

    • 默认方法允许将新功能添加到库的接口,并确保与为这些接口的旧版本编写的代码的二进制兼容性。

    • 重复注释提供了对同一声明或类型使用多次应用相同注释类型的功能。

    • 类型注释提供了在使用类型的任何地方应用注释的功能,而不仅仅是在声明上。与可插拔类型系统一起使用时,此功能可以改进代码的类型检查。

    • 改进的类型推断。

    • 方法参数反射。

  • 集合

    • java.util.stream中的类提供Stream API以支持对元素流的功能样式操作。Stream API集成到Collections API中,可以对集合进行批量操作,例如顺序或并行map-reduce转换。

    • 具有hash冲突的HashMaps的性能改进

  • 安全

    • 默认情况下启用客户端TLS 1.2

    • 更强大的基于密码加密的算法

    • SHA-224消息摘要

  • 国际化

    • Unicode增强功能,包括对Unicode 6.2.0的支持

    • 采用Unicode CLDR数据和java.locale.providers系统属性

    • 新日历和区域设置API

    • 能够将自定义资源包安装为扩展

  • 日期时间包 - 一组新的包,提供全面的日期时间模型。

  • IO和NIO

    • 减小<JDK_HOME>/jre/lib/charsets.jar文件的大小

    • java.lang.String(byte[], *)构造函数和java.lang.String.getBytes()方法的性能改进

  • java.lang和java.util包

    • 并行阵列排序

    • 标准编码和解码Base64

    • 无符号算术支持

  • 并发

    • 类和接口已添加到java.util.concurrent包中。

    • 已将java.util.concurrent.ConcurrentHashMap添加到类中以支持基于新添加的流工具和lambda表达式的聚合操作。

    • 已将类添加到java.util.concurrent.atomic包中以支持可伸缩的可更新变量。

    • 方法已添加到java.util.concurrent.ForkJoinPool类中以支持公共池。

    • java.util.concurrent.locks.StampedLock班已添加到提供基于能力的锁有三种模式控制读/写访问。

  • 热点

    • 去除PermGen。

 

本文主要围绕以下几点进行介绍

  • Lambda 表达式 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)

  • 方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

  • 默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。

  • Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。

  • Date Time API − 加强对日期与时间的处理。

  • Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。

  • HashMap改进

 

Lambda表达式

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda表达式有两个特点:一是匿名函数,二是可传递。

匿名函数的应用场景是:
通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用Lambda表达式。lambda表达式所表示的匿名函数的内容应该是很简单的,如果复杂的话,干脆就重新定义一个函数了,使用lambda就有点过于执拗了。

可传递使用场景是:
就是将Lambda表达式传递给其他的函数,它当做参数,Lambda作为一种更紧凑的代码风格,使Java的语言表达能力得到提升。

 

语法

(parameters) ->{ statements; }

Lambda表达式在Java语言中引入了一个新的语法元素和操作符。这个操作符为"->",该操作符被称为Lambda操作符或箭头操作符,它将Lambda分为两个部分:

左侧:指定了Lambda表达式所需要的所有参数
右侧:指定了Lambda体,即Lambda表达式所要执行的功能。

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体只有一个语句,就可以不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

举个🌰:

// 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)

//6. 接收2个参数(数字),并返回他们相除的结果
(x,y) -> {
      if(x<0){
            return 0;
      }
      return y/x;
}

 

接下来是个完整的例子:

public class Java8Tester {
   public static void main(String args[]){
      Java8Tester tester = new Java8Tester();
        
      // 类型声明
      MathOperation addition = (int a, int b) -> a + b;
        
      // 不用类型声明
      MathOperation subtraction = (a, b) -> a - b;
        
      // 大括号中的返回语句
      MathOperation multiplication = (int a, int b) -> { return a * b; };
        
      // 没有大括号及返回语句
      MathOperation division = (int a, int b) -> a / b;
        
      System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
      System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
      System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));
        
      // 不用括号
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);
        
      // 用括号
      GreetingService greetService2 = (message) ->
      System.out.println("Hello " + message);
        
      greetService1.sayMessage("Runoob");
      greetService2.sayMessage("Google");
   }
    
   interface MathOperation {
      int operation(int a, int b);
   }
    
   interface GreetingService {
      void sayMessage(String message);
   }
    
   private int operate(int a, int b, MathOperation mathOperation){
      return mathOperation.operation(a, b);
   }
}

使用 Lambda 表达式需要注意以下两点:

  • Lambda 表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。在上面例子中,我们使用各种类型的Lambda表达式来定义MathOperation接口的方法。然后我们定义了sayMessage的执行。
  • 使用lambda表达式实现接口仅适用于该接口有且只有一个抽象方法
  • Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。

 

变量作用域

lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

举个🌰:

public class Java8Tester {
    public static void main(String args[]) {
        int num = 1;
        Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
        s.convert(2);  // 输出结果为 3
        //接下来如果改变num的值会报错,因为num传入lambda表达式即其隐性的具有final语义
        //num = 2;
    }
 
    public interface Converter<T1, T2> {
        void convert(int i);
    }
}

 

再举个java8前后使用lambda语法差异的🌰

public class Test {
 
    public static void main(String[] args) {
 
        // Java8之前:
        new Thread(new Runnable() {
            public void run() {
                System.out.println("hello world");
            }
        }).start();
 
        // Java8方式:
        new Thread(() -> System.out.println("hello world")).start();
    }
}

 

 

常用例子

//list转set
List<Tags> list = new ArrayList<>(); Set<Integer> tagIdSet = list.stream().map(Tags::getTagId).collect(Collectors.toSet());

//list转map
List<Tags> crowdHitList = new ArrayList<>();
Map<String,Long> resultMap = crowdHitList.stream().collect(Collectors.toMap(Tags::getCrowdId, tag-> {
if (tag.getTotal() == null) {
return 0L;
} else {
return tag.getTotal();
}
}));

 

参考地址:https://www.runoob.com/java/java8-lambda-expressions.html

http://swiftlet.net/archives/3331

posted on 2019-07-31 14:41  殁舞  阅读(1038)  评论(0编辑  收藏  举报