java8有哪些新特性
1、Lambda表达式;2、方法引用;3、接口中有默认方法和静态方法;4、新编译工具;5、Stream API;6、Date Time API;7、Optional;8、Nashorn javascript引擎。
1、Lambda表达式
lambda 表达式的语法格式如下:
(parameters) -> expression或(parameters) ->{statements; }
以下是lambda表达式的重要特征:
1.可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
2.可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
3.可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
4.可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指明表达式返回了一个数值。
2、方法引用
方法引用说简单点,就是代替比较简单的Lambda表达式,让代码看起来比较简洁易懂。
方法引用使用一对冒号(::)来表示对方法的简洁引用。
在java中方法引用有四种:
1. 构造器引用:它的语法是Class::new,或者更一般的Class< T >::new
2. 静态方法引用:它的语法是Class::static_method
3. 特定类的任意对象的方法引用:它的语法是Class::method
4. 特定对象的方法引用:它的语法是instance::method
类::实例方法(Class::method)如何理解?
这种模式并不是要直接调用类的实例方法,这样显然连编译都过不去。
这种模式实际上是 对象::实例方法模式的一种变形,当一个对象调用方法时,方法的某个参数是函数式接口,而且函数式接口的方法参数列表的第一个参数就是调用者对象所属的类时,如果调用者类中定义了这样一个方法,该方法的参数列表与函数式接口的方法参数列表除去第一个参数外都一样,那么可以用类::实例方法这种形式来调用该方法。例如:
先定义一个函数式接口,注意方法的参数列表:
package com.statics.proxy.methodReference;
@FunctionalInterface
public interface MyFunInterface<T> {
String myConcat(T t, String a, String b);
}
定义测试类:
package com.statics.proxy.methodReference;
public class MethodRefTest {
/**
* 函数式接口MyFunInterface的myConcat(T t, String a, String b)方法参数,
* 除了第一个参数是泛型T,后面两个参数与concatStr方法的参数相同,如果泛型T
* 是MethodRefTest类型,则可以使用MethodRefTest::concatStr来调用方法。
*/
public String concatStr(String a, String b){
return a + "_" + b;
}
public String concat(MyFunInterface<MethodRefTest> f, String a, String b){
return f.myConcat(this, a, b);
}
public static void main(String[] args) {
String s1 = "abc";
String s2 = "123";
MethodRefTest mrt = new MethodRefTest();
//第一种写法,匿名内部类,容易理解
String result1 = mrt.concat(new MyFunInterface<MethodRefTest>() {
@Override
public String myConcat(MethodRefTest methodRefTest, String a, String b) {
return methodRefTest.concatStr(a, b);
}
}, s1, s2);
//第二种写法,使用lambda表达式简化
String result2 = mrt.concat((methodRefTest, a, b) -> methodRefTest.concatStr(a, b), s1, s2);
//第三种写法,使用方法引用代替lambda表达式,进一步简化
String result3 = mrt.concat(MethodRefTest::concatStr, s1, s2);
System.out.println("result1======" + result1);
System.out.println("result2======" + result2);
System.out.println("result3======" + result3);
}
}
输出结果:
现在参照代码再回过头来看这句话:
当一个对象调用方法时(mrt.concat),方法的某个参数是函数式接口(concat方法的第一个参数是MyFunInterface<MethodRefTest> f),而且函数式接口的方法参数列表的第一个参数就是调用者对象所属的类(函数式接口方法参数的第一个参数是MethodRefTest),如果调用者类中定义了这样一个方法(concatStr方法),该方法的参数列表与函数式接口的方法参数列表除去第一个参数外都一样,那么可以用类::实例方法(MethodRefTest::concatStr)这种形式来调用该方法。
3、默认方法
Java 8 新增了接口的默认方法。默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法,只需在方法名前面加个default关键字即可实现默认方法。
为什么要有这个特性?
首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的java 8之前的集合框架没有foreach方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现,所以引进的默认方法,他们的目的是为了解决接口的修改与现有的实现不兼容的问题。
比如List接口继承Collection接口,Collection接口继承Iterable接口。在jdk1.8版本中给Iterable接口添加了foreach方法,为了不在Collection接口及其子接口中也定义foreach方法,在Iterable接口中将foreach方法定义为默认方法。