Appearance
JDK 8 特性详解
JDK 8 是Java语言发展的一个重要里程碑,引入了许多革命性的特性,特别是函数式编程相关的功能。本文将详细介绍JDK 8的主要特性,并通过示例代码来说明其用法。
1. Lambda表达式
Lambda表达式是JDK 8最显著的特性之一,它允许我们以更简洁的方式表示匿名函数。
语法
java
(参数列表) -> 表达式
// 或
(参数列表) -> { 语句块 }示例
java
// 传统方式
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello, World!");
}
};
// 使用Lambda表达式
Runnable runnableLambda = () -> System.out.println("Hello, World!");
// 带参数的Lambda表达式
Function<Integer, Integer> square = (x) -> x * x;
System.out.println(square.apply(5)); // 输出: 25
// 多参数Lambda表达式
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(3, 4)); // 输出: 72. 函数式接口
函数式接口是只包含一个抽象方法的接口,可以使用@FunctionalInterface注解来标记。
内置函数式接口
| 接口名称 | 参数 | 返回值 | 描述 |
|---|---|---|---|
Consumer<T> | T | void | 接收一个参数,无返回值 |
Supplier<T> | 无 | T | 无参数,返回一个值 |
Function<T, R> | T | R | 接收一个参数,返回一个值 |
Predicate<T> | T | boolean | 接收一个参数,返回布尔值 |
BiFunction<T, U, R> | T, U | R | 接收两个参数,返回一个值 |
示例
java
// 使用Consumer
Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello, Consumer!");
// 使用Supplier
Supplier<Double> random = () -> Math.random();
System.out.println(random.get());
// 使用Predicate
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // 输出: true3. 方法引用
方法引用是一种更简洁的Lambda表达式写法,用于引用已存在的方法。
语法
java
对象::实例方法
类::静态方法
类::实例方法示例
java
// 引用静态方法
Function<String, Integer> parseInt = Integer::parseInt;
System.out.println(parseInt.apply("123")); // 输出: 123
// 引用实例方法
String str = "Hello";
Supplier<Integer> length = str::length;
System.out.println(length.get()); // 输出: 5
// 引用构造方法
Supplier<List<String>> listSupplier = ArrayList::new;
List<String> list = listSupplier.get();4. Stream API
Stream API 是JDK 8引入的一个强大的处理集合的工具,它支持函数式风格的操作。
基本操作
- 创建流:
stream(),parallelStream() - 中间操作:
filter(),map(),sorted(),distinct(),limit(),skip() - 终端操作:
forEach(),collect(),reduce(),count(),anyMatch(),allMatch(),noneMatch()
示例
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// 过滤并收集
List<String> filteredNames = names.stream()
.filter(name -> name.length() > 3)
.collect(Collectors.toList());
System.out.println(filteredNames); // 输出: [Alice, Charlie, David]
// 映射并计算
int totalLength = names.stream()
.mapToInt(String::length)
.sum();
System.out.println(totalLength); // 输出: 19
// 并行流
long count = names.parallelStream()
.filter(name -> name.startsWith("A"))
.count();
System.out.println(count); // 输出: 15. Optional类
Optional类是一个容器对象,用于处理可能为null的值,避免NullPointerException。
主要方法
of(): 创建一个非空的Optional对象ofNullable(): 创建一个可能为空的Optional对象empty(): 创建一个空的Optional对象isPresent(): 检查值是否存在ifPresent(): 如果值存在则执行操作orElse(): 如果值不存在则返回默认值orElseGet(): 如果值不存在则通过Supplier获取默认值orElseThrow(): 如果值不存在则抛出异常
示例
java
// 创建Optional对象
Optional<String> optional1 = Optional.of("Hello");
Optional<String> optional2 = Optional.ofNullable(null);
Optional<String> optional3 = Optional.empty();
// 检查值是否存在
System.out.println(optional1.isPresent()); // 输出: true
System.out.println(optional2.isPresent()); // 输出: false
// 获取值
String value1 = optional1.orElse("Default");
String value2 = optional2.orElse("Default");
System.out.println(value1); // 输出: Hello
System.out.println(value2); // 输出: Default
// 函数式风格
optional1.ifPresent(System.out::println); // 输出: Hello
// 链式操作
String result = optional1
.map(s -> s.toUpperCase())
.orElse("DEFAULT");
System.out.println(result); // 输出: HELLO6. 日期时间API
JDK 8引入了新的日期时间API,位于java.time包中,解决了旧API的许多问题。
主要类
LocalDate: 表示日期(年、月、日)LocalTime: 表示时间(时、分、秒)LocalDateTime: 表示日期和时间ZonedDateTime: 表示带时区的日期和时间Duration: 表示时间间隔Period: 表示日期间隔DateTimeFormatter: 日期时间格式化
示例
java
// 获取当前日期
LocalDate today = LocalDate.now();
System.out.println(today); // 输出: 2023-10-05
// 创建指定日期
LocalDate date = LocalDate.of(2023, 12, 25);
System.out.println(date); // 输出: 2023-12-25
// 日期计算
LocalDate nextWeek = today.plusWeeks(1);
System.out.println(nextWeek); // 输出: 2023-10-12
// 日期比较
boolean isAfter = nextWeek.isAfter(today);
System.out.println(isAfter); // 输出: true
// 格式化日期
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formattedDate = today.format(formatter);
System.out.println(formattedDate); // 输出: 2023-10-05
// 解析日期
LocalDate parsedDate = LocalDate.parse("2023-10-05", formatter);
System.out.println(parsedDate); // 输出: 2023-10-057. 默认方法
默认方法是接口中可以有实现的方法,使用default关键字修饰。
示例
java
interface MyInterface {
void abstractMethod();
default void defaultMethod() {
System.out.println("Default method implementation");
}
}
class MyClass implements MyInterface {
@Override
public void abstractMethod() {
System.out.println("Abstract method implementation");
}
}
// 使用
MyClass myClass = new MyClass();
myClass.abstractMethod(); // 输出: Abstract method implementation
myClass.defaultMethod(); // 输出: Default method implementation8. 静态方法在接口中
JDK 8允许在接口中定义静态方法。
示例
java
interface MyInterface {
static void staticMethod() {
System.out.println("Static method in interface");
}
}
// 直接调用
MyInterface.staticMethod(); // 输出: Static method in interface9. Nashorn JavaScript引擎
JDK 8引入了新的JavaScript引擎Nashorn,替代了旧的Rhino引擎。
示例
java
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class NashornExample {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
// 执行JavaScript代码
engine.eval("print('Hello from Nashorn!')");
// 调用JavaScript函数
engine.eval("function add(a, b) { return a + b; }");
Object result = engine.eval("add(2, 3)");
System.out.println("2 + 3 = " + result); // 输出: 2 + 3 = 5
}
}10. 类型注解
JDK 8扩展了注解的使用范围,允许在更多地方使用注解,如类型参数、类型转换等。
示例
java
// 类型参数注解
public class TypeAnnotationExample {
public <@MyAnnotation T> void method(T t) {}
// 类型转换注解
public void castExample(Object obj) {
String str = (@MyAnnotation String) obj;
}
// 数组注解
public void arrayExample(@MyAnnotation String[] array) {}
}
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@interface MyAnnotation {}11. 收集器(Collectors)
Collectors类提供了许多用于Stream API的收集操作。
示例
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// 收集到List
List<String> nameList = names.stream()
.collect(Collectors.toList());
// 收集到Set
Set<String> nameSet = names.stream()
.collect(Collectors.toSet());
// 收集到Map
Map<String, Integer> nameLengthMap = names.stream()
.collect(Collectors.toMap(name -> name, String::length));
// 分组
Map<Integer, List<String>> lengthGroups = names.stream()
.collect(Collectors.groupingBy(String::length));
// 分区
Map<Boolean, List<String>> partitioned = names.stream()
.collect(Collectors.partitioningBy(name -> name.length() > 3));
// 连接字符串
String joined = names.stream()
.collect(Collectors.joining(", "));
System.out.println(joined); // 输出: Alice, Bob, Charlie, David, Eve12. 并行数组操作
JDK 8在Arrays类中添加了一些并行操作方法。
示例
java
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 并行排序
Arrays.parallelSort(numbers);
System.out.println(Arrays.toString(numbers)); // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 并行前缀
int[] prefix = new int[numbers.length];
Arrays.parallelPrefix(numbers, (a, b) -> a + b);
System.out.println(Arrays.toString(numbers)); // 输出: [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
// 并行设置
Arrays.parallelSetAll(prefix, i -> i * 2);
System.out.println(Arrays.toString(prefix)); // 输出: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]总结
JDK 8引入了许多强大的特性,特别是函数式编程相关的功能,如Lambda表达式、Stream API等。这些特性使得Java代码更加简洁、易读,同时提高了开发效率。通过本文的示例,你应该对JDK 8的主要特性有了更深入的了解。