【终极版】Java8 新特性全面介绍,强烈建议收藏(一)

简介: Java 8 已经发布很久了,很多报道表明 Java 8 是一次重大的版本升级,虽然我们的 JDK 环境也升级到1.8,但是在日常的开发过程中,使用最多的编程风格还是停留在 JDK1.7。

一、介绍

Java 8 已经发布很久了,很多报道表明 Java 8 是一次重大的版本升级,虽然我们的 JDK 环境也升级到1.8,但是在日常的开发过程中,使用最多的编程风格还是停留在 JDK1.7。

Java8 新增了非常多的特性,主要有以下几个:

  • Lambda 表达式:Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)
  • 函数式接口:指的是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,这样的接口可以隐式转换为 Lambda 表达式
  • 方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码
  • 默认方法:默认方法就是一个在接口里面有了一个实现的方法
  • Stream API:新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
  • Optional 类:Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
  • Date Time API:加强对日期与时间的处理。
  • Nashorn, JavaScript 引擎:Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用

有很多人认为,Java 8 的一些新特性另 Java 开发人员十分满意,在本篇文章中,我们将详细介绍 Java 8 的这些新特性!

话不多说,直接上代码

二、Lambda 表达式

Lambda 表达式,也称为闭包,是 Java 8 中最大和最令人期待的语言改变。它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理,函数式开发者非常熟悉这些概念。

很多JVM平台上的语言(Groovy、Scala等)从诞生之日就支持 Lambda 表达式,但是 Java 开发者没有选择,只能使用匿名内部类代替Lambda表达式。

//匿名内部类方式排序
List<String> names = Arrays.asList( "a", "b", "d" );
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});

Lambda 的设计可谓耗费了很多时间和很大的社区力量,最终找到一种折中的实现方案,可以实现简洁而紧凑的语言结构。

Lambda 表达式的语法格式:

(parameters) -> expression
(parameters) ->{ statements; }

Lambda 编程风格,可以总结为四类:

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

2.1、可选类型声明

在使用过程中,我们可以不用显示声明参数类型,编译器可以统一识别参数类型,例如:

Collections.sort(names, (s1, s2) -> s1.compareTo(s2));

上面代码中的参数s1s2的类型是由编译器推理得出的,你也可以显式指定该参数的类型,例如:

Collections.sort(names, (String s1, String s2) -> s1.compareTo(s2));

运行之后,两者结果一致!

2.2、可选的参数圆括号

当方法那只有一个参数时,无需定义圆括号,例如:

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

但多个参数时,需要定义圆括号,例如:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );

2.3、可选的大括号

当主体只包含了一行时,无需使用大括号,例如:

Arrays.asList( "a", "b", "c" ).forEach( e -> System.out.println( e ) );

当主体包含多行时,需要使用大括号,例如:

Arrays.asList( "a", "b", "c" ).forEach( e -> {
    System.out.println( e );
    System.out.println( e );
} );

2.4、可选的返回关键字

如果表达式中的语句块只有一行,则可以不用使用return语句,返回值的类型也由编译器推理得出,例如:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );

如果语句块有多行,可以在大括号中指明表达式返回值,例如:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
    int result = e1.compareTo( e2 );
    return result;
} );

2.5、变量作用域

还有一点需要了解的是,Lambda 表达式可以引用类成员和局部变量,但是会将这些变量隐式得转换成final,例如:

String separator = ",";
Arrays.asList( "a", "b", "c" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );

final String separator = ",";
Arrays.asList( "a", "b", "c" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );

两者等价!

同时,Lambda 表达式的局部变量可以不用声明为final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义),例如:

int num = 1;
Arrays.asList(1,2,3,4).forEach(e -> System.out.println(num + e));
num =2;
//报错信息:Local variable num defined in an enclosing scope must be final or effectively final

在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量,例如:

int num = 1;
Arrays.asList(1,2,3,4).forEach(num -> System.out.println(num));
//报错信息:Variable 'num' is already defined in the scope

三、函数式接口

Lambda 的设计者们为了让现有的功能与 Lambda 表达式良好兼容,考虑了很多方法,于是产生了函数接口这个概念。

函数接口指的是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,这样的接口可以隐式转换为 Lambda 表达式。

但是在实践中,函数式接口非常脆弱,只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface,举个简单的函数式接口的定义:

@FunctionalInterface
public interface GreetingService {
    void sayMessage(String message);
}

Java7 只能通过匿名内部类进行编程,例如:

GreetingService greetService = new GreetingService() {
    @Override
    public void sayMessage(String message) {
        System.out.println("Hello " + message);
    }
};
greetService.sayMessage("world");

Java8 可以采用 Lambda 表达方进行编程,例如:

GreetingService greetService = message -> System.out.println("Hello " + message);
greetService.sayMessage("world");

目前 Java 库中的所有相关接口都已经带有这个注解了,实践上java.lang.Runnablejava.util.concurrent.Callable是函数式接口的最佳例子!

相关文章
|
2天前
|
Java API 开发者
Java 8的新特性简单分享(后续有系列篇~敬请期待)
Java 8的新特性简单分享(后续有系列篇~敬请期待)
7 1
|
3天前
|
JavaScript 前端开发 Java
Java11 新特性深度解析
Java11 新特性深度解析
|
2天前
|
Java API 开发者
高效利用Java中的函数式编程特性
高效利用Java中的函数式编程特性
|
3天前
|
SQL 运维 Java
深度解析Java 9核心新特性
深度解析Java 9核心新特性
|
3天前
|
Java 编译器 API
技术经验分享:JAVA8十大新特性详解
技术经验分享:JAVA8十大新特性详解
|
4天前
|
安全 Java C++
深入探究Java中的TransferQueue:机制、特性与应用场景
深入探究Java中的TransferQueue:机制、特性与应用场景
|
4天前
|
安全 Java API
JDK 11 vs JDK 8:探索Java的新特性和改进
JDK 11 vs JDK 8:探索Java的新特性和改进
|
4天前
|
并行计算 JavaScript 前端开发
Java 8新特性全面解读
Java 8新特性全面解读
|
5天前
|
安全 Java 容器
Java 1.8新特性使用记录
Java 1.8新特性使用记录 有些方法一段时间不使用会忘记,这里要记录一下,方便以后使用
14 0
|
6天前
|
Java
java的lambda延时执行特性案例
java的lambda延时执行特性案例
8 0