问题来源于一段写自Java 8的代码
JSONArray paramJsonArray = cmdJson.getJSONArray("paramArray");
paramArray = paramJsonArray.stream()
.map(Object::toString).collect(Collectors.toList());
这段代码升级到Java 17之后出现了编译错误

一、对于Collect操作的变化
-
Collectors.toUnmodifiableList()
支持了不可变的搜集器 -
Stream.toList()
支持了转List的操作符
二、实际的使用
用法 | 可变性 | 容null性 |
---|---|---|
Collectors.toList() | 可变 | 可null |
Collectors.toUnmodifiableList() | 不可变 | 不可null |
Stream.toList() | 不可变 | 可null |
demo:
@ExtendWith(MockitoExtension.class)
class DemoTest {
/**
* 正常情况
*/
@Test
void test1() {
var source = new ArrayList<String>();
source.add("1");
source.add("2");
source.add(null);
// 正常数据 可修改,可处理空数据
List<String> list1 = source.stream().collect(Collectors.toList());
list1.add("4");
// UnmodifiableList 引用了java.util.ImmutableCollections,不支持null
assertThatThrownBy(() -> {
source.stream().collect(Collectors.toUnmodifiableList());
}).isInstanceOf(NullPointerException.class);
List<String> list2 = source.stream().filter(Objects::nonNull).collect(Collectors.toUnmodifiableList());
assertThatThrownBy(() -> {
list2.add("4");
}).isInstanceOf(UnsupportedOperationException.class);
// toList操作符 不支持修改,不能存null
List<String> list3 = source.stream().toList();
assertThatThrownBy(() -> {
list3.add("4");
}).isInstanceOf(UnsupportedOperationException.class);
}
}
三、范型遇到的问题
在Java8中对于Raw type的容器对象,为了方便序列化的读写操作会将其转换成String或者二进制数据,所以经常会有下面的操作
List rawList = new ArrayList();
rawList.add("1");
rawList.add("2");
List<String> ret = rawList.stream().map(Object::toString).collect(Collectors.toList());
这样拿到ret之后可以再进行整体的读写操作,其实rawList.stream()这块的linq操作执行的结果是产生了一个Stream<Object>的数据流,交给map变换成Stream<String>
但是同一段代码在Java17中会直接得到一个类型转换错误
List<String> ret = Stream.of("null",123)
.map(Object::toString).collect(Collectors.toList());
其实整件事情的重点在于对范型的理解和java 11引入的var
关键字
- java确实存在范型擦出,在编译之后处理的都是Object,但是无论从字节码的角度看,还是从语义的角度看List和List<Object>是有区别的
- java11由于引入了var,实际上对于List和List<Object>的stream操作的语义推断返回值是不同的,前者返回的Stream,后者返回的是Stream<Object>
明确了上述两点,再来看下下面的代码
List tt = new ArrayList();
tt.add("111");
tt.add("222");
// Java8下编译错误,两者都是编译错误,因为collect(Collectors.toList())返回的是Object
List<String> e1 = tt.stream().map(param -> param.toString()).collect(Collectors.toList());
List e2 = tt.stream().map(param -> param.toString()).collect(Collectors.toList());
// Java8下正确编译
Stream<Object> s8 = tt.stream();
List<String> ret8 = s8.map(Object::toString).collect(Collectors.toList());
// Java11下正确编译,但是提示raw type
Stream<Object> s11 = paramJsonArray.stream();
List<String> ret11 = s11.map(Object::toString).collect(Collectors.toList());
网友评论