Java 8 的一些新特性
Java 8 —— 下面主要讲 8 个特性:
一、Lambda 表达式(也可以称为“闭包”):
(paramList) -> expression;
或者
(paramList) -> {statments;}
特征:
- 参数类型声明可选:编译器可识别参数值
- 只有一个表达式,那么表达式的值作为 Lambda 的返回值;用大括号 {} 括起来的,多个表达式,需要使用 return 关键字指明返回值
- Lambda 中不能声明和任何局部变量同名的,参数或者局部变量。引用的局部变量必须是 final 修饰的,否则会编译错误。可以不用显式声明 final,但是必须在 lambda 引用之前,赋值
演示用例:
public interface MathOperation { int operation(int a, int b); }
public class Tester { public static void main(String[] args) { MathOperation add = (int a, int b) -> a + b; //参数列表、表达式返回值相同即可;方法实现甚至可以没有:Lambda表达式相当于一个方法类,作为接口的实现 System.out.println(add.operation(1, 2)); } }
二、方法引用(方法实现,Lambda 的简写):
示例类 Car:
import java.util.function.Supplier; public class Car { public static Car create(final Supplier<Car> supplier) { return supplier.get(); } public static void collide(final Car car) { System.out.println("Collided " + car.toString()); } public void repair() { System.out.println("Repaired " + this.toString()); } public void follow(final Car another) { System.out.println("Following the " + another.toString()); } }
有四种引用方法:
//构造器引用 Class::new Car car = Car.create(Car::new); List<Car> cars = Collections.singletonList(car); //静态方法引用 Class::static_method cars.forEach(Car::collide); //类引用非静态方法 Class::method cars.forEach(Car::repair); //对象引用非静态方法 instance::method cars.forEach(car::follow);
运行结果:
Collided com.jackie.sms.biz.Car@81ad775
Repaired com.jackie.sms.biz.Car@81ad775
Following the com.jackie.sms.biz.Car@81ad775
三、函数式接口:
函数式接口(Functional Interface)仅有一个抽象方法,可以有多个非抽象方法(默认方法、静态方法)的接口。
如下为其定义:
@FunctionalInterface public interface Car { void go(Integer speed); }
Lambda 表达式就是表示该接口抽象方法的一种实现:
Car car = System.out::println;
car.go(120);
Java 8 新增的函数式接口在下面的包中:
java.util.function
其中 Predicate<T> 接口是较为常用的一个函数式接口:它接受一个参数 T,返回一个布尔值结果。
四、接口默认方法(即接口的缺省实现方法):
其语法格式如下:
public interface Vehicle { // default 关键字只是interface使用 default void print() { System.out.println("我是一辆汽车"); } }
(1)多个接口具有同名的默认方法:
//Vehicle.java public interface Vehicle { // default 关键字只是interface使用 default void print() { System.out.println("我是一辆汽车"); } } // FourWheeler.java public interface FourWheeler { default void print() { System.out.println("我是一辆四轮车"); } }
那么同一个类,实现这样的接口,会出现如下情况:
对此,可以有两种方案:
一是,类自己直接重载接口的实现方法,来覆盖这些接口的同名默认方法:
public class Car implements Vehicle, FourWheeler { @Override public void print() { System.out.println("我是一辆四轮汽车"); } }
二是,在重载方法中,使用 super 关键字,调用指定接口的默认方法(所以除了调用接口的方法,还可以有其他代码):
public class Car implements Vehicle, FourWheeler { @Override public void print() { Vehicle.super.print(); FourWheeler.super.print(); System.out.println("其他"); } }
(2)静态默认方法(除了默认实现,也可以提供静态实现):
public interface Vehicle { static void horn() { System.out.println("按喇叭"); } }
可以像类一样,直接调用:
Vehicle.horn();
五、Optional 类:
Optional 类是包含一个对象的一种容器,其容纳的对象可以是 null。如果值存在,则其 isPresent() 方法返回 true,调用 get() 方法返回该对象。
使用简例:
Integer num1 = null; Integer num2 = 10; // 此时Optional.ofNullable(num1) == Optional.empty() Optional<Integer> a = Optional.empty(); Optional<Integer> b = Optional.of(num2); Integer c = a.orElse(0); Integer d = b.orElse(100); System.out.println(a.isPresent()); System.out.println(b.get()); System.out.println(c); System.out.println(d);
六、Nashorn —— Java 嵌入式的 JavaScript 引擎:
Java 8 开始,Nashorn 取代 Rhino(Java 6、7),成为 Java 的 JS 引擎,性能提升了 2 到 10倍。Nashorn 完全支持ECMAScipt 5.1 规范以及一些扩展。
(1)jjs:
jjs 是基于 Nashorn 的命令行工具。它接受一些 JavaScript 源码作为参数,并执行。
例如,可以创建编写 JS 文件:
// test.js print('hello')
然后 jjs 执行此文件:
D:\>jjs test.js
hello
a)交互式编程:
D:\>jjs jjs> print('hello') hello jjs> quit function quit() { [native code] } jjs> quit() D:\>
交互式编程 —— 传递参数(-- 没有空格):
D:\>jjs -- a b c jjs> print(arguments.join(', ')) a, b, c jjs>
(2)Java 中调用 JavaScript:
ScriptEngineManager engineManager = new ScriptEngineManager(); ScriptEngine nashorn = engineManager.getEngineByName("nashorn"); String name = "jackie"; Integer result = null; try { nashorn.eval("print('" + name + "')"); // alert不得行。。。 result = (Integer) nashorn.eval("10 + 2"); System.out.println(result); } catch (ScriptException e) { e.printStackTrace(); }
(3)JavaScript 中调用 Java 类(使用 jjs 执行):
// test.js var BigDecimal = Java.type('java.math.BigDecimal') var num1 = new BigDecimal(10) var num2 = new BigDecimal(20) var result = num1.multiply(num2) .divide(new BigDecimal(100), BigDecimal.ROUND_HALF_EVEN) print(result.toPlainString()) // 执行 D:\>jjs test.js 2
还有两个,以后再说。