Java8新特性全面介绍

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

一、介绍

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

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

1. Lambda 表达式:Lambda表达式是Java 8中最重要的特性之一。它提供了一种简洁而灵活的方式来编写匿名函数。Lambda表达式可以作为参数传递给方法或存储在变量中,并可以替代使用匿名内部类的方式。
2. 函数式接口:函数式接口是指只包含一个抽象方法的接口。Java 8引入了一些新的函数式接口,例如Predicate、Consumer、Supplier、Function等,这些接口可以用Lambda表达式来实现。
3. 方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码
4. 默认方法:Java 8允许在接口中定义默认方法,即具有默认实现的方法。这样可以使得接口的修改更加灵活,不会破坏已有的实现。
5. Stream API:Stream API提供了一种功能强大的处理集合数据的方式。它可以通过一系列的中间操作和终端操作来对集合进行过滤、映射、排序、聚合等操作,使得代码更加简洁、可读性更强。
6. Optional 类:Optional类是一种容器对象,可以用来表示一个值存在或不存在。它可以避免空指针异常,并提供了一些便捷的方法来处理可能为空的值。
7. Date Time API:Java 8引入了java.time包,提供了一套全新的日期和时间API。它提供了更好的可读性和易用性,并且支持更多的操作,例如日期的解析格式化、时区处理、日期计算等。
8. Nashorn, JavaScript 引擎:Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用

除了上述主要特性外,Java 8还包含了其他一些改进,例如重复注解、类型注解、改进的类型推断、新的IO和NIO API等。这些新特性使得Java 8成为了一个更现代化、更强大的编程语言。

话不多说,直接上代码!

Java8

二. 常用功能

(一). Lambda 表达式

Lambda表达式是Java 8引入的一种新的语法特性,它提供了一种简洁而灵活的方式来编写匿名函数。

1. 基础介绍

Lambda表达式的语法形式如下:

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

其中,parameters指定了Lambda表达式的参数列表,可以包含零个或多个参数。参数列表可以省略类型,编译器会根据上下文进行类型推断。

->是Lambda运算符,将参数列表与Lambda表达式的主体分隔开来。

expression是单个表达式,可以是一个返回值的计算或一个方法调用。如果Lambda表达式只有一条表达式,可以省略花括号{}和return关键字。

{ statements; }是一系列语句的块,可以包含多条语句,并可以有返回值。

Lambda表达式可以用于函数式接口的实现,函数式接口是指只包含一个抽象方法的接口。Lambda表达式可以与函数式接口相匹配,用于提供该接口的实现。

例如,下面是一个使用Lambda表达式的例子:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用Lambda表达式对集合进行遍历和打印
names.forEach(name -> System.out.println(name));
// 使用Lambda表达式对集合进行过滤
List<String> filteredNames = names.stream()
                                  .filter(name -> name.length() > 4)
                                  .collect(Collectors.toList());

Lambda表达式可以简化代码,使代码更加紧凑和可读。它提供了一种简单而强大的方式来处理函数式编程的需求,例如在集合处理、事件处理、多线程等方面的应用广泛。

2. Lambda编程风格分类
2.1 可选类型声明

不需要声明参数类型,编译器可以统一识别参数值

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

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

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

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
3. Lambda编程使用分类

遍历和过滤:Lambda表达式可以用于集合的遍历和过滤操作,使用函数式接口如Consumer、Predicate等。这种风格的Lambda表达式常见于使用Stream API进行集合操作。

映射和转换:Lambda表达式可以用于集合的映射和转换操作,使用函数式接口如Function、UnaryOperator等。这种风格的Lambda表达式常见于使用Stream API进行数据转换和处理。

排序和比较:Lambda表达式可以用于集合的排序和比较操作,使用函数式接口如Comparator等。这种风格的Lambda表达式常见于使用Collections.sort()等排序方法或使用Stream API进行排序操作。

链式调用和组合:Lambda表达式可以通过链式调用和组合实现复杂的操作流程,例如使用Stream API的filter()、map()、reduce()等方法,以及使用函数式接口的andThen()、compose()等方法。

并行处理:Lambda表达式可以通过Stream API的并行处理特性实现并行计算,提高程序的性能。这种风格的Lambda表达式常见于对大数据集或耗时操作进行并行处理。

总体而言,Lambda编程风格强调使用简洁、灵活的Lambda表达式来实现函数式编程的各种操作。它能够减少样板代码、提高代码可读性,并且使得代码更加模块化和易于维护。Lambda表达式的引入使得Java的编程范式更加多样化,并且使得函数式编程成为Java开发中的一种重要编程风格。

(二). 函数式接口

Java 8提供了java.util.function包,其中定义了一些常用的函数式接口,用于支持函数式编程的需求。

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

以下是一些常用的函数式接口:

Supplier<T>:无参数,返回一个结果。对应的方法是T get()。
Consumer<T>:接受一个参数,无返回值。对应的方法是void accept(T t)。
Predicate<T>:接受一个参数,返回一个布尔值。对应的方法是boolean test(T t)。
Function<T, R>:接受一个参数,返回一个结果。对应的方法是R apply(T t)。
UnaryOperator<T>:接受一个参数,返回与参数类型相同的结果。对应的方法是T apply(T t)。
BinaryOperator<T>:接受两个参数,返回一个结果,且参数和结果类型相同。对应的方法是T apply(T t1, T t2)。

除了以上几个常用的函数式接口,还有一些其他的函数式接口,如BiFunction、BiConsumer、BiPredicate等,用于支持多个参数的场景。

函数式接口可以使用Lambda表达式或方法引用来创建实例。例如:

// 使用Lambda表达式创建Supplier接口的实例
Supplier<String> supplier = () -> "Hello";

// 使用方法引用创建Consumer接口的实例
Consumer<String> consumer = System.out::println;

// 使用Lambda表达式创建Predicate接口的实例
Predicate<Integer> predicate = n -> n > 0;

// 使用Lambda表达式创建Function接口的实例
Function<Integer, String> function = n -> Integer.toString(n);

// 使用Lambda表达式创建UnaryOperator接口的实例
UnaryOperator<Integer> operator = n -> n * 2;

// 使用Lambda表达式创建BinaryOperator接口的实例
BinaryOperator<Integer> binaryOperator = (a, b) -> a + b;

函数式接口在函数式编程和Lambda表达式的使用中发挥重要作用。它们提供了一种简洁而灵活的方式来实现函数的传递和组合,使得代码更加简洁和可读。

(三). 方法引用

Java 8引入了方法引用(Method References)的概念,它允许直接通过方法的名称来引用现有的方法。方法引用提供了一种更简洁和易读的方式来传递方法作为参数或在函数式接口中使用。

方法引用可以看作是Lambda表达式的一种简化形式,它可以替代Lambda表达式的情况,即当Lambda表达式仅仅是调用一个已经存在的方法时。

在Java 8中,方法引用可以分为以下几种形式:

1. 静态方法引用

引用静态方法,语法为类名::静态方法名。例如,Math::max表示引用Math类的max方法。

// 静态方法引用
Function<Integer, Double> sqrt = Math::sqrt;
System.out.println(sqrt.apply(16)); // 输出:4.0
2. 实例方法引用

引用某个对象的实例方法,语法为对象::方法名。例如,list::size表示引用list对象的size方法。

// 实例方法引用
List<String> list = Arrays.asList("Java", "Python", "C++");
Consumer<String> print = System.out::println;
list.forEach(print); // 输出:Java Python C++
3. 类名方法引用

引用特定类的任意对象的实例方法,语法为类名::方法名。例如,String::length表示引用String类的length方法。

// 类名方法引用
Function<String, Integer> length = String::length;
System.out.println(length.apply("Hello")); // 输出:5
4. 构造方法引用

引用构造方法来创建新对象,语法为类名::new。例如,ArrayList::new表示引用ArrayList的无参构造方法。

// 构造方法引用
Supplier<List<String>> listSupplier = ArrayList::new;
List<String> newList = listSupplier.get();

使用方法引用可以简化代码并提高可读性,特别是在函数式接口中传递方法时。它允许直接引用已经存在的方法,而无需编写冗长的Lambda表达式或匿名内部类。

方法引用是Java 8中一个强大且实用的特性,可以使代码更简洁、易读,并提高开发效率。它是函数式编程在Java中的重要组成部分,与Lambda表达式一起为Java引入了更加灵活和优雅的编程方式。

(四). 默认方法

Java 8引入了默认方法(Default Methods),也称为扩展方法(Extension Methods),它们是接口中具有默认实现的方法。

默认方法允许在接口中定义具有方法体的方法,而不需要实现类必须提供方法的具体实现。默认方法为接口提供了一种向后兼容的方式,在向现有接口添加新方法时,不会破坏已有的实现类。

默认方法在接口中使用default关键字进行定义,具有方法体。接口中的默认方法可以直接在接口中调用,也可以被实现该接口的类重写。

以下是一个示例,演示了默认方法的使用:

interface Vehicle {
    void start();

    default void honk() {
        System.out.println("Honking the horn");
    }
}

对上述示例接口的两个实现类

class Car implements Vehicle {
    @Override
    public void start() {
        System.out.println("Starting the car");
    }
}
class Bike implements Vehicle {
    @Override
    public void start() {
        System.out.println("Starting the bike");
    }

    @Override
    public void honk() {
        System.out.println("Bike honking the horn");
    }
}

对实现类的使用

public class Main {
    public static void main(String[] args) {
        Vehicle car = new Car();
        car.start(); // 输出:Starting the car
        car.honk();  // 输出:Honking the horn

        Vehicle bike = new Bike();
        bike.start(); // 输出:Starting the bike
        bike.honk();  // 输出:Bike honking the horn
    }
}

在上述示例中,Vehicle接口定义了两个方法:start()和默认方法honk()。Car类和Bike类实现了Vehicle接口,并分别提供了自己的实现。Car类使用了默认方法的默认实现,而Bike类重写了默认方法。

默认方法的引入使得接口能够具有一些通用的行为,而不会破坏已有的实现类。它为接口的演化提供了更大的灵活性,使得在接口上添加新的功能变得更加容易。

(五). Stream API

Java 8引入了Stream API,它是一种用于处理集合数据的新的抽象层。Stream API允许开发人员以声明性的方式操作数据集合,实现更简洁、更可读的代码。

1.介绍

Stream是一个来自数据源的元素队列,并支持各种操作,比如过滤、映射、排序、聚合等。使用Stream API,可以在集合上执行复杂的数据操作,而无需编写繁琐的循环和条件语句。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

+--------------------+       +------+   +------+   +---+   +-------+ 
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect| 
+--------------------+       +------+   +------+   +---+   +-------+ 

以上的流程转换为 Java 代码,实例如下:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); 
// 获取集合中大于2、并且经过排序、平方去重的有序集合 
List<Integer> squaresList = numbers 
        .stream() 
        .filter(x -> x > 2) 
        .sorted((x,y) -> x.compareTo(y)) 
        .map( i -> i*i).distinct().collect(Collectors.toList()); 

在 Java 8 中,集合接口有两个方法来生成流:

stream():为集合创建串行流
parallelStream():为集合创建并行流

当然,流的来源可以是集合,数组,I/O channel, 产生器generator 等!

2. Stream API的常用操作:
2.1创建Stream

可以通过集合、数组、I/O通道等方式创建Stream。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream();
2.2过滤filter

使用filter()方法过滤Stream中的元素。

List<Integer> evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .collect(Collectors.toList());
2.3映射map

使用map()方法将Stream中的元素映射到另一个值。

List<String> words = Arrays.asList("Java", "Stream", "API");
List<Integer> wordLengths = words.stream()
                                 .map(String::length)
                                 .collect(Collectors.toList());
2.4排序sorted

使用sorted()方法对Stream中的元素进行排序。

List<Integer> sortedNumbers = numbers.stream()
                                     .sorted()
                                     .collect(Collectors.toList());
2.5聚合操作reduce

使用reduce()方法对Stream中的元素进行聚合操作,如求和、求最大值、求最小值等。

int sum = numbers.stream()
                 .reduce(0, Integer::sum);
2.6收集结果collect

使用collect()方法将Stream中的元素收集到一个集合或Map中。

List<Integer> collectedNumbers = numbers.stream()
                                        .collect(Collectors.toList());

Map<String, Integer> nameLengthMap = names.stream()
                                          .collect(Collectors.toMap(Function.identity(), String::length));

Stream API还提供了许多其他操作,如限制元素数量、跳过元素、查找元素、判断是否满足条件等。

使用Stream API可以编写更简洁、更可读的代码,它提供了一种更直观的方式来处理集合数据,同时还能够发挥并行计算的潜力,提高程序的性能。

(六). Optional类

Java 8引入了Optional类,它是用来解决空指针异常(NullPointerException)的常见问题的一种方式。Optional类是一个容器对象,可以包含一个非空的值或者表示值不存在。使用Optional类可以避免显式地进行空值检查,从而简化了代码,并提高了代码的可读性和健壮性。

1. 创建Optional对象:

使用静态方法of()创建包含非空值的Optional对象。

Optional<String> optional = Optional.of("Hello");

使用静态方法empty()创建一个空的Optional对象。

Optional<String> emptyOptional = Optional.empty();

使用静态方法ofNullable()创建一个Optional对象,可以接受空值。

Optional<String> optional = Optional.ofNullable(null);
2. 检查值的存在:

使用isPresent()方法检查Optional对象是否包含值。

Optional<String> optional = Optional.of("Hello");
if (optional.isPresent()) {
    System.out.println("Value is present: " + optional.get());
} else {
    System.out.println("Value is absent");
}
3. 获取值:

使用get()方法获取Optional对象中的值(前提是已经通过isPresent()方法检查了值的存在性)。

Optional<String> optional = Optional.of("Hello");
String value = optional.get();
4. 避免空值:

使用orElse()方法获取Optional对象中的值,如果值不存在则返回指定的默认值。

Optional<String> optional = Optional.ofNullable(null);
String value = optional.orElse("Default Value");

使用orElseGet()方法获取Optional对象中的值,如果值不存在则通过Supplier接口提供一个默认值。

Optional<String> optional = Optional.ofNullable(null);
String value = optional.orElseGet(() -> generateDefaultValue());
5. 处理值:

使用ifPresent()方法对Optional对象中的值进行处理,如果值存在则执行指定的操作。

Optional<String> optional = Optional.of("Hello");
optional.ifPresent(value -> System.out.println("Value is present: " + value));
6. 链式调用:

可以通过链式调用一系列Optional对象的方法来处理值的存在与否。

Optional<String> optional = Optional.of("Hello");
optional.map(String::toUpperCase)
        .ifPresent(value -> System.out.println("Modified value: " + value));

Optional类提供了一种优雅地处理空值的方式,它可以避免繁琐的空值检查,使代码更加简洁和可读。使用Optional类可以提高代码的健壮性,并减少空指针异常的发生。

(七). Date Time API

Java 8引入了新的日期和时间API,以解决旧的Date和Calendar类在设计上的一些问题。新的日期和时间API位于java.time包中,提供了更简洁、易用和线程安全的日期和时间处理方式。

1. 使用原因

设计更合理:旧的Date和Calendar类在设计上存在一些问题,比如可变性、线程安全性和易用性等方面。新的Date Time API通过不可变性、线程安全性和清晰的设计,避免了这些问题,并提供了更一致、更可靠的日期和时间操作。

更加易用:新的Date Time API提供了一组简洁而直观的类和方法,使得日期和时间的操作更加易用和直观。它提供了更多的方法来处理日期和时间,如日期加减、格式化、解析、比较等操作,减少了编写复杂代码的工作量。

更好的类型安全性:新的Date Time API引入了一些新的类型,如LocalDate、LocalTime、LocalDateTime等,用于表示日期和时间。这些类型提供了更严格的类型检查和更准确的操作,减少了错误和异常的发生。

更好的时区支持:新的Date Time API提供了更好的时区支持,可以轻松地处理不同时区的日期和时间。它引入了ZoneId和ZonedDateTime等类,用于表示带有时区的日期和时间,提供了丰富的时区操作和转换方法。

与其他API的集成:新的Date Time API与其他Java 8的特性和API更好地集成,如Lambda表达式、Stream API等。它可以与函数式编程结合使用,使得处理日期和时间的代码更加简洁和灵活。

2. 主要组件和用法
2.1 LocalDate

表示日期,不包含时间和时区信息。

创建当前日期:

LocalDate today = LocalDate.now();

创建指定日期:

LocalDate date = LocalDate.of(2023, 5, 18);

获取日期的年、月、日等信息:

int year = date.getYear();
Month month = date.getMonth();
int day = date.getDayOfMonth();
DayOfWeek dayOfWeek = date.getDayOfWeek();
2.2 LocalTime

表示时间,不包含日期和时区信息。

创建当前时间:

LocalTime time = LocalTime.now();

创建指定时间:

LocalTime time = LocalTime.of(10, 30, 0);

获取时间的小时、分钟、秒等信息:

int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();
2.3 LocalDateTime

表示日期和时间,不包含时区信息。

创建当前日期和时间:

LocalDateTime dateTime = LocalDateTime.now();

创建指定日期和时间:

LocalDateTime dateTime = LocalDateTime.of(2023, 5, 18, 10, 30, 0);

获取日期和时间的各个组成部分:

int year = dateTime.getYear();
Month month = dateTime.getMonth();
int day = dateTime.getDayOfMonth();
int hour = dateTime.getHour();
int minute = dateTime.getMinute();
int second = dateTime.getSecond();
2.4 ZonedDateTime

表示带有时区的日期和时间。

创建当前日期和时间,并指定时区:

ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

创建指定日期和时间,并指定时区:

ZonedDateTime zonedDateTime = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("Asia/Tokyo"));
2.5 Duration

表示一段时间间隔。

计算两个时间点之间的间隔:

LocalDateTime start = LocalDateTime.of(2023, 5, 18, 10, 0, 0);
LocalDateTime end = LocalDateTime.of(2023, 5, 18, 11, 30, 0);
Duration duration = Duration.between(start, end);
long minutes = duration.toMinutes();
2.6 Period

表示日期之间的间隔。

计算两个日期之间的间隔:

LocalDate startDate = LocalDate.of(2023, 5, 18);
LocalDate endDate = LocalDate.of(2023, 6, 18);
Period period = Period.between(startDate, endDate);
int months = period.getMonths();
int days = period.getDays();

Java 8 Date Time API提供了丰富的类和方法,可以更方便地进行日期和时间的处理。它的设计更加符合实际需求,并且提供了很多便利的操作方法,使得日期和时间的计算、格式化和解析等操作变得简单而直观。

(八). Nashorn, JavaScript 引擎

Java 8引入了Nashorn作为新的JavaScript引擎,它是基于JVM的高性能JavaScript运行时环境。Nashorn的目标是提供一个与传统的Rhino引擎相比更快速、更现代化的JavaScript解释器。

以下是Nashorn的一些主要特点和优势:

高性能:Nashorn引擎使用了JIT(即时编译)技术,能够将JavaScript代码编译成高效的字节码,从而实现更快的执行速度。相比传统的Rhino引擎,Nashorn在性能上有显著的提升。

与Java的无缝集成:Nashorn可以直接访问Java类和API,能够在Java和JavaScript之间进行无缝的交互。JavaScript代码可以调用Java类的方法、访问Java对象的属性,反之亦然。这种集成性使得在Java应用程序中嵌入JavaScript代码变得更加方便。

支持ES6标准:Nashorn对ES6(ECMAScript 2015)标准提供了广泛的支持,包括箭头函数、模板字符串、解构赋值、类和模块等特性。这使得开发者能够使用最新的JavaScript语言特性,提高代码的可读性和开发效率。

轻量级和易于部署:Nashorn是一个轻量级的JavaScript引擎,作为JDK的一部分,无需单独安装,可以直接在Java应用程序中使用。这使得部署和管理变得更加简单。

脚本执行和嵌入式应用:Nashorn可以作为脚本引擎使用,可以从命令行或脚本文件中执行JavaScript代码。同时,它也可以作为嵌入式引擎在Java应用程序中使用,通过API调用执行JavaScript代码。

当使用Nashorn JavaScript引擎时,可以在Java中嵌入JavaScript代码并进行互操作。以下是一个简单的示例,展示了如何在Java中执行JavaScript代码和在JavaScript中调用Java方法

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class NashornExample {
    public static void main(String[] args) {
        // 创建Nashorn引擎
        ScriptEngineManager engineManager = new ScriptEngineManager();
        ScriptEngine engine = engineManager.getEngineByName("nashorn");

        try {
            // 在Java中执行JavaScript代码
            engine.eval("print('Hello from JavaScript!');");

            // 在JavaScript中调用Java方法
            engine.eval("var result = java.lang.Math.sqrt(16);");
            Object result = engine.get("result");
            System.out.println("Square root of 16 is: " + result);
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }
}

上述示例中,首先创建了一个Nashorn引擎。然后使用eval方法执行了一段JavaScript代码,在控制台输出了"Hello from JavaScript!"。接着,在JavaScript中调用了Java的Math.sqrt方法来计算16的平方根,然后通过engine.get方法获取了计算结果,并在Java中打印出来。

这个示例展示了Nashorn在Java和JavaScript之间的互操作能力。你可以根据具体的需求,编写更复杂的代码来实现更多的交互操作。

总的来说,Nashorn提供了一个高性能、与Java无缝集成的JavaScript运行时环境。它使得在Java应用程序中使用JavaScript变得更加便捷,同时也提供了现代化的语言特性和更好的性能。不过需要注意的是,自Java 11开始,Nashorn被标记为已弃用,并在未来的版本中可能会被移除,建议使用其他现代化的JavaScript引擎,如GraalVM。

版权声明: 闲者 发表于 2023-09-11
转载请注明: Java8新特性全面介绍 | Java8新特性全面介绍 - 无界文档,Java8新特性全面介绍

评论区

暂无评论...