Java 教程

Java 控制语句

面向对象编程

Java 内置类

Java 文件处理

Java 错误和异常

Java 多线程

Java 同步

Java 网络编程

Java 集合

Java 接口

Java 数据结构

Java 集合算法

高级 Java

Java 杂项

Java API 和框架

Java 类引用

Java 有用资源

Java 8 新特性



JAVA 8 是 JAVA 编程语言 开发的一个主要功能版本。其初始版本于 2014 年 3 月 18 日发布。随着 Java 8 的发布,Java 提供了对函数式编程、新的 JavaScript 引擎、新的日期时间操作 API、新的流 API 等的支持。

以下是 Java 8 支持的新特性列表:

Lambda 表达式

Lambda 表达式 是 Java 中引入的最重要的特性之一。Lambda 表达式促进了 Java 中的函数式编程。Lambda 表达式基于函数式接口的原理。函数式接口是一个只有一个方法要实现的接口。Lambda 表达式提供函数式接口方法的实现。

Lambda 表达式极大地简化了函数式编程,并使代码更易读,无需任何样板代码。Lambda 表达式可以推断使用的参数类型,并且可以在没有 return 关键字的情况下返回值。对于简单的单语句方法,甚至可以省略大括号。

示例 - 使用 Lambda 表达式

以下示例展示了 Lambda 表达式的用法。Lambda 表达式最适合与函数式接口一起使用,函数式接口只有一个抽象方法。我们定义了一个只有一个方法 operate 的接口 Calculator,它可以接受两个参数并返回一个值。在 main 方法中,我们首先使用匿名函数实现了 Calculator 接口,然后使用 Lambda 表达式。operate() 方法在两种情况下都被调用以打印结果,并且结果都被打印出来。

package com.tutorialspoint;

public class Tester {

   public static void main(String[] args) {
      // Interface implementation using anonymous class
      Calculator sum = new Calculator() {
         @Override
         public int operate(int a, int b) {
            return a + b;
         }
      };
      int result = sum.operate(2,3);
      System.out.println(result);	   

      // Interface implementation using lambda expression
      Calculator sum1 = (a,b) -> a + b;
      result = sum1.operate(2,3);
      System.out.println(result);
   }  

   interface Calculator {
      int operate(int a, int b);
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

5
5

方法引用

方法引用 是一种简短而简洁的调用方法、静态方法甚至构造函数的方式,无需冗长的语法。方法引用有助于通过名称指向方法,即使不指定参数也是如此。参数由 Lambda 表达式传递。方法引用使用 "::" 符号描述。

可以使用以下语法引用静态方法:

<<class-name>>::methodName

可以使用以下语法引用实例方法:

<<object-name>>::methodName

可以使用以下语法调用构造函数:

<<class-name>>::new

示例 - 使用方法引用

在这个例子中,我们使用了静态方法 compare 和实例方法 compareTo 来排序两个整数的 ArrayList。我们使用方法引用来表示静态方法和实例方法。

package com.tutorialspoint;

import java.util.Arrays;
import java.util.List;

public class Tester {
   public static void main(String args[]) {
      List<Integer> numbers = Arrays.asList(1,2,4,9,8,7,3);
      System.out.println("Sorted using static method reference");
      // Use static method compare
      numbers = numbers.stream().sorted(Integer::compare).toList();
      System.out.println(numbers);

      numbers = Arrays.asList(1,2,4,9,8,7,3);
      System.out.println("Sorted using instance method reference" );
      // Use instance method compareTo
      numbers = numbers.stream().sorted(Integer::compareTo).toList();

      System.out.println(numbers);		
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

Sorted using static method reference
[1, 2, 3, 4, 7, 8, 9]
Sorted using instance method reference
[1, 2, 3, 4, 7, 8, 9]

默认方法

在 Java 8 之前,接口只能包含抽象方法。随着 Java 8 的发布,引入了 Lambda 表达式。现在为了向后兼容性,添加了 默认方法 功能,以便旧的 接口 可以利用 Lambda 表达式而无需修改其实现。

例如,ListCollection 接口 没有 'forEach' 方法声明。因此,添加此方法只会破坏集合框架的实现。Java 8 引入了默认方法,以便 List/Collection 接口可以具有 forEach 方法的默认实现,而实现这些接口的类无需实现相同的方法。

语法

以下是 Java 中接口中默认方法的语法:

public interface vehicle {
   default void message() {
      System.out.println("I am a vehicle!");
   }
}

示例 - 使用默认方法

在这个例子中,我们创建了一个包含默认方法的接口。在实现类中,此消息未实现,用于打印消息。

package com.tutorialspoint;

interface vehicle {
   // default method must have an implementation
   default void message() {
      System.out.println("I am a vehicle!");
   }
}

// implementing class need not to implement the default method
// of an interface.
public class Tester implements vehicle {
   public static void main(String args[]) {
      Tester tester = new Tester();
      // implementing class can access the default method as its own method
      tester.message(); 
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

I am a vehicle!

Stream API

Stream API 是 Java 8 中引入的一个新的抽象层,用于以声明式方式处理数据。流表示一系列元素。流以顺序方式提供特定类型的元素集合。流按需获取/计算元素。它永远不会存储元素。

Stream 支持聚合操作,例如 filter、map、limit、reduce、find、match 等,并且可以在内部对提供的源元素进行迭代,这与需要显式迭代的集合形成对比。

语法

以下是使用流的通用语法

<<collection-instance>>.stream().<<non-terminal-operation()>>.<<non-terminal-operation()>>.<<terminal-operation()>>

示例 - 使用 Stream

在这个例子中,我们创建了一个字符串列表,其中一些条目为空。现在使用 Stream API,我们过滤空字符串并计算它们的数量。

package com.tutorialspoint;

import java.util.Arrays;
import java.util.List;

public class Tester {
   public static void main(String args[]) {
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

      // get stream from list using stream() method
      // then apply filter
      // lastly count the result of filter
      long count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("Empty Strings: " + count);
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

Empty Strings: 2

Optional 类

Optional 类 功能是在 Java 8 中引入的,用于以编程方式处理空指针异常场景,使程序更简洁、更不易出错。当使用空对象引用获取其值或调用其方法时,就会发生空指针异常。随着程序规模的增加,处理所有可能发生空指针异常的情况变得非常繁琐。

Optional 类实例为对象提供了一个包装器,其中包含许多实用程序方法,例如在底层值为 null 时获取备用值,检查对象引用是否为 null 等。

示例 - 使用 Optional 类

在这个例子中,我们使用 oofNullable() 方法创建了两个 Optional 类实例,该方法允许将底层对象作为 null 传递,然后使用 orElse() 方法检索值,如果底层对象为 null,则返回默认值。

package com.tutorialspoint;

import java.util.Optional;

public class Tester {
   public static void main(String args[]) {
      // case 1: Optional is having null as underlying value
      Optional<Integer> valueOptional = Optional.ofNullable(null);

      // case 2:  Optional is having not null as underlying value
      Optional<Integer> valueOptional1 = Optional.ofNullable(Integer.valueOf(10));

      // orElse will return -1 being default value
      Integer value = valueOptional.orElse(Integer.valueOf(-1));

      System.out.println(value);

      //  orElse will return the underlying value
      Integer value1 = valueOptional1.orElse(Integer.valueOf(-1));

      System.out.println(value1);
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

-1
10

新的日期时间 API

Java 8 引入了一个新的日期时间 API,它是线程安全的,支持时区,并具有多个直接处理日期操作的方法。早期的日期时间 API 不是线程安全的,在并发问题中,在使用日期时可能会出现问题。新的日期时间 API 使用不可变结构,没有 setter 方法,因此使 API 更安全。新的 API 在设计时考虑了时区和特定领域的需要。

Java 8 在 java.time 包下引入了一个新的日期时间 API。以下是 java.time 包中引入的一些重要类。

  • Local − 简化的日期时间 API,没有时区处理的复杂性。

  • Zoned − 用于处理各种时区的专用日期时间 API。

示例 - 使用日期时间 API

在这个例子中,我们使用 oofNullable() 方法创建了两个 Optional 类实例,该方法允许将底层对象作为 null 传递,然后使用 orElse() 方法检索值,如果底层对象为 null,则返回默认值。

package com.tutorialspoint;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZonedDateTime;

public class Tester {
   public static void main(String args[]) {
      // Get the current date and time
      LocalDateTime currentTime = LocalDateTime.now();
      System.out.println("Current DateTime: " + currentTime);

      LocalDate date1 = currentTime.toLocalDate();
      System.out.println("date1: " + date1);

      Month month = currentTime.getMonth();
      int day = currentTime.getDayOfMonth();
      int seconds = currentTime.getSecond();

      System.out.println("Month: " + month +", day: " + day +", seconds: " + seconds);

      ZonedDateTime date2 = ZonedDateTime.parse("2007-12-03T10:15:30+05:30[Asia/Karachi]");
      System.out.println("date2: " + date2);
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

Current DateTime: 2024-03-07T10:29:15.650806
date1: 2024-03-07
Month: MARCH, day: 7, seconds: 15
date2: 2007-12-03T09:45:30+05:00[Asia/Karachi]

Nashorn JavaScript 引擎

Nashorn 是一个非常强大且高效的 Javascript 引擎,它作为现有 javascript 引擎 Rhino 的替代品而引入。Nashorn 引擎号称速度是 Rhino 的 2 到 10 倍,因为它可以直接将 JavaScript 代码编译为字节码。Nashorn 引擎允许在 Java 文件中运行执行 JavaScript 代码,我们甚至可以在 JavaScript 代码片段中执行 Java 代码。使用 Nashorn 引擎,引入了命令行工具 jjs 来在命令行工具中运行 javascript。

直接在命令提示符中执行 JavaScript

打开控制台,键入 jjs 并按 Enter 键。jjs 工具将打开一个交互式会话。jjs 会话打开后,我们可以执行 javascript 代码。完成后,键入quit() 并按 Enter 键退出 jjs 交互式会话并返回到命令提示符。

示例

C:\JAVA>jjs
jjs> print("Hello, World!")
Hello, World!
jjs> quit()
>>
C:\JAVA>

示例 - 在 Java 代码中使用 Javascript 代码

自 Java 6 以来,Java 就有一个 ScriptEngineManager 类,本例中使用它将 javascript 引擎加载为 ScriptEngine 实例。一旦引擎加载到 java 代码中,我们就可以调用eval() 方法来评估 Java 中的 JavaScript 代码。我们甚至可以在 javascript 代码片段中使用Java 变量

package com.tutorialspoint;

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

public class Tester {

   public static void main(String args[]) {
      // create the script engine manager   
      ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
      // load the Nashorn javascript engine
      ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");
		
      String message = "This is a message";
      String expression = "10 + 2";
      Integer result = null;
      
      try {
         // call the javascript function, pass a java variable	  
         nashorn.eval("print('" + message + "')");
         // call the javascript function and get the result back in java
         result = (Integer) nashorn.eval(expression);
         
      } catch(ScriptException e) {
         System.out.println("Error executing script: "+ e.getMessage());
      }
      System.out.println(result.toString());
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

This is a message
12

Nashorn 引擎在 Java 11 中已弃用,在 Java 15 中已删除,并由 GraalVM javascript 引擎取代。

广告