Java9
新增takeWhile()和dropWhile()方法
takeWhile(Predicate)
从流的起始位置开始,逐个提取满足条件的元素,直到遇到第一个不满足条件的元素时停止,得到的是满足条件的列表。
代码示例如下:
java
@Test
public void takeWhileTest() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 1, 6, 7);
// 取出所有小于 5 的元素,遇到 5 就停止
List<Integer> taken = numbers.stream()
.takeWhile(n -> n < 5)
.collect(Collectors.toList());
// 输出结果为:[1, 2, 3, 4]
System.out.println(taken);
}
dropWhile(Predicate)
与 takeWhile 相反,它从流的起始位置开始,逐个丢弃满足条件的元素,直到遇到第一个不满足条件的元素,然后返回包含剩余所有元素的新流。
代码示例如下:
java
@Test
public void dropWhileTest() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 1, 6, 7);
// 丢弃所有小于5的元素,从5开始保留
List<Integer> taken = numbers.stream()
.dropWhile(n -> n < 5)
.collect(Collectors.toList());
// 输出结果为:[5, 1, 6, 7]
System.out.println(taken);
}
新增ofNullable()方法
如果传入的元素非 `null`,则返回一个包含该元素的单元素流。 如果传入的元素为 `null`,则返回一个空流。
示例代码如下:
过滤集合中null元素
java
@Test
public void ofNullableTest() {
List<String> listWithNulls = Arrays.asList("a", null, "b", null, "c");
List<String> resultList = listWithNulls.stream()
.flatMap(Stream::ofNullable)
.collect(Collectors.toList());
// 输出结果为:resultList: [a, b, c]
System.out.printf("resultList: %s\n", resultList);
}
改进 iterate() 方法
Java 8 中的 Stream.iterate() 方法会生成一个无限流,通常需要配合 limit() 来限制大小。
Java 9 为其增加了一个重载方法,允许直接指定一个终止条件(Predicate),从而更方便地生成有限序列。
- Java 8 :
Stream.iterate(seed, nextFunction) - Java 9 :
Stream.iterate(seed, hasNextPredicate, nextFunction)
对比示例代码如下:
java
@Test
public void iterateTest() {
// Java 8 写法,需要 limit(5) 来限制数量
Stream.iterate(0, n -> n + 2)
.limit(5)
.forEach(System.out::print); // 输出: 0, 2, 4, 6, 8
System.out.println("\n---------------------------");
// Java 9 写法,直接在 iterate 中指定终止条件
Stream.iterate(0, n -> n < 10, n -> n + 2)
.forEach(System.out::print); // 输出: 0, 2, 4, 6, 8
System.out.println("\n");
}
新增Optional.stream()方法
可以将一个 Optional 实例转换为一个 Stream。如果 Optional 有值,则返回包含该值的单元素流;如果为空,则返回空流。
示例代码如下:
可以用来过滤Optional 集合中空元素数据
java
@Test
public void optionalTest() {
List<Optional<String>> optionalList = Arrays.asList(
Optional.of("A"),
Optional.empty(),
Optional.of("B")
);
// 使用 Java 9 的 Optional.stream() 扁平化并过滤空值
List<String> result = optionalList.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
// 结果: [A, B]
System.out.println(result);
}
新增集合工厂方法
| 集合类型 | 工厂方法 | 说明 |
|---|---|---|
List |
List.of(E... elements) |
创建不可变列表 |
Set |
Set.of(E... elements) |
创建不可变集合,元素唯一 |
Map |
Map.of(K k1, V v1, ...) |
创建不可变映射(最多10个键值对) |
Map |
Map.ofEntries(Map.Entry... entries) |
创建任意数量键值对的不可变映射 |
示例代码:
java
@Test
public void collectionTest() {
// 创建不可变 List
List<String> names = List.of("Alice", "Bob", "Charlie");
System.out.println(names.stream().collect(Collectors.joining(", ")));
// 创建不可变 Set
Set<Integer> numbers = Set.of(1, 2, 3);
System.out.println(numbers.stream().collect(Collectors.toSet()));
// 创建不可变 Map (最多10个键值对)
Map<String, Integer> scores = Map.of("Alice", 95, "Bob", 88);
System.out.println(scores);
// 创建超过10个键值对的不可变 Map
Map<String, Integer> largeMap = Map.ofEntries(
Map.entry("Java", 1),
Map.entry("Python", 2),
Map.entry("Go", 3)
// ... 可以有更多
);
System.out.println(largeMap);
}
工厂创建的集合特性
- 真正不可变 (Immutable)
集合一旦创建,其内容和结构就不可更改。任何尝试调用add、remove、clear等修改方法的操作,都会在运行时抛出UnsupportedOperationException。这与 Java 8 中使用Collections.unmodifiableList()等方式创建的"伪不可变"集合不同,后者在编译期无法提供类型安全检查。 - 空值安全 (Null-Safe)
工厂方法在创建集合时会严格检查,不允许任何null元素(对于List和Set)或null键/值(对于Map)。如果传入null,会立即抛出NullPointerException,这有助于在开发早期就发现潜在问题。 - 元素唯一性 (针对 Set 和 Map)
对于Set.of(),如果传入重复元素,会抛出IllegalArgumentException。同样,对于Map.of(),如果传入重复的键,也会抛出异常。
多版本JAR文件
Java 9 引入的多版本JAR文件 (Multi-Release JAR Files,简称 MR-JAR)是一项非常重要的特性,旨在解决 Java 平台演进过程中的兼容性痛点。
简单来说,它允许你在同一个 JAR 包中打包针对不同 Java 版本编译的类文件。这样,你的库既可以兼容旧版 Java(如 Java 8),又能在运行于新版 Java(如 Java 9、11、17 等)时自动利用新版本的 API 特性。
使用示例
1、添加maven依赖
java
<properties>
<!-- 定义项目使用的 Maven 和 JDK 版本 -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.release>8</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- 1. 配置编译器插件,用于编译不同版本的代码 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
<!-- 执行1: 编译基准版本 (Java 8) -->
<execution>
<id>default-compile</id>
<configuration>
<release>8</release>
</configuration>
</execution>
<!-- 执行2: 编译 Java 17+ 版本的代码 -->
<execution>
<id>java17-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>17</release>
<!-- 指定 Java 17 源码的目录 -->
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/resources-jdk17</compileSourceRoot>
</compileSourceRoots>
<!-- 指定 Java 17 编译后的输出目录 -->
<outputDirectory>${project.build.outputDirectory}/META-INF/versions/17</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- 2. 配置 JAR 插件,启用多版本打包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<!-- 关键配置:在 MANIFEST.MF 中添加 Multi-Release: true -->
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
2、项目结构
IDEA的项目结构
html
mrjar
├── src/main/java/com/example/mrjar/Utils.java <-- 默认版本 (兼容 Java 8)
├── src/main/resources-jdk17/com/example/mrjar/Utils.java <-- Java 17 专用版本
编译后的项目结构
html
mrjar-0.0.1-SNAPSHOT.jar
├── com/example/mrjar/Utils.class <-- 默认版本 (兼容 Java 8)
├── META-INF/
│ ├── MANIFEST.MF <-- 必须包含 "Multi-Release: true"
│ └── versions/
│ ├── 17/
│ │ └── com/example/mrjar/Utils.class <-- Java 17 专用版本
3、Utils代码示例
Java8
java
public static List<String> getList() {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
return list;
}
Java17
java
public static List<String> getList() {
return List.of("6", "7", "8", "9","10");
}
4、执行
使用如下命令分别在Java8和Java17程序包执行,输出不一样:
bash
java -cp mrjar-0.0.1-SNAPSHOT.jar com.example.mrjar.MrJarMain