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

还有两个,以后再说。

posted @ 2019-05-15 17:30  不抛弃,不放弃  阅读(339)  评论(0编辑  收藏  举报