千万不要滥用Stream.toList(),有坑!
Java后端技术
共 8632字,需浏览 18分钟
·
2024-04-11 16:23
往期热门文章:
1.背景
-
2.Stream toList()和 collect(Collectors.toList())的区别 -
Stream toList() -
Stream collect(Collectors.toList()) -
3.如何使用(不考虑性能)
Stream toList()
返回的是只读List原则上不可修改,collect(Collectors.toList())
默认返回的是ArrayList,可以增删改查
1. 背景
UnsupportedOperationException
报错,想到了不是自己throw的应该就是操作collection不当。
stringList.stream().filter(number -> Long.parseLong(number) > 1).toList() 以stream.toList()
作为返回, 后继续使用了返回值做add操作,导致报错
2. Stream toList()和 collect(Collectors.toList())的区别
-
JDK version: 21 -
IDE: IDEA
stringList.stream().filter(number -> Long.parseLong(number) > 1).collect(Collectors.toList())
。
Stream toList()
/**
* Accumulates the elements of this stream into a {@code List}. The elements in
* the list will be in this stream's encounter order, if one exists. The returned List
* is unmodifiable; calls to any mutator method will always cause
* {@code UnsupportedOperationException} to be thrown. There are no
* guarantees on the implementation type or serializability of the returned List.
*
* <p>The returned instance may be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Callers should make no assumptions about the identity of the returned instances.
* Identity-sensitive operations on these instances (reference equality ({@code ==}),
* identity hash code, and synchronization) are unreliable and should be avoided.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
*
* @apiNote If more control over the returned object is required, use
* {@link Collectors#toCollection(Supplier)}.
*
* @implSpec The implementation in this interface returns a List produced as if by the following:
* <pre>{@code
* Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))
* }</pre>
*
* @implNote Most instances of Stream will override this method and provide an implementation
* that is highly optimized compared to the implementation in this interface.
*
* @return a List containing the stream elements
*
* @since 16
*/
@SuppressWarnings("unchecked")
default List<T> toList() {
return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())));
}
Collections.unmodifiableList
而在unmodifiableList(List<? extends T> list)
实现中,都会返回一个不可修改的List,所以不能使用set/add/remove等改变list数组的方法。
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
List<String> stringList = List.of("1", "2", "3");
List<String> largeNumberList = stringList.stream().filter(number -> Long.parseLong(number) > 1).toList();
List<String> largeNumberList2 = stringList.stream().filter(number -> Long.parseLong(number) > 1).collect(Collectors.toList());
largeNumberList.add("4"); // java.lang.UnsupportedOperationException
largeNumberList2.add("4"); //success
// modify custom object attribute
User userZhang = new User("ZhangSan");
User userLi = new User("LiSi");
List<User> userList = List.of(userZhang, userLi);
List<User> filterList = userList.stream().filter(user -> "LiSi".equals(user.name)).toList();
User first = filterList.getFirst();//java 21
first.name = "WangWu";
filterList.forEach(u -> System.out.println(u.name));
//List.of返回的也是不能修改的List
userList.forEach(u -> System.out.print(u.name));
WangWu
ZhangSanWangWu
Stream collect(Collectors.toList())
toList()
方法入参中传入指定Supplier的话, 可以做ArrayList的任何操作
/**
* Returns a {@code Collector} that accumulates the input elements into a
* new {@code List}. There are no guarantees on the type, mutability,
* serializability, or thread-safety of the {@code List} returned; if more
* control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
*
* @param <T> the type of the input elements
* @return a {@code Collector} which collects all the input elements into a
* {@code List}, in encounter order
*/
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>(ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
Unmodifiable Lists
说明
-
它们是不可修改的。元素不能被添加、删除或替换。调用List上的任何mutator方法将始终导致引发 UnsupportedOperationException
。但是,如果包含的元素本身是可变的,这可能会导致List的内容看起来发生变化。 -
它们不允许空元素。尝试使用空元素创建它们会导致 NullPointerException
。 -
如果所有元素都是可序列化的,那么它们就是可序列化的。 -
列表中元素的顺序与提供的参数或提供的数组中元素的顺序相同。列表及其子List视图实现了 RandomAccess
接口。 -
它们以价值为基础。应将相等的实例视为可互换的,不应将它们用于同步,否则可能会发生不可预知的行为。如,在将来的版本中,同步可能会失败。呼叫端不应假设传回执行个体的识别。工厂可以自由地创建新的实例或重用现有的实例。 -
它们将按照“序列化窗体”页上的指定进行序列化。 -
该接口是Java集合框架的成员。
3.如何使用(不考虑性能)
collect(Collectors.toList())
,sonar或idea自带以及第三方的一些code checker会爆warning,以本人经验,可以使用collect(Collectors.toCollection(ArrayList::new))
来代替
来源:juejin.cn/post/7325717778597904420
往期热门文章:
1、中国程序员独立开发9年、最受欢迎的开源Redis客户端,被Redis公司收购了! 2、我在代码里面故意留个漏洞,违法吗? 3、一个现代化轻量级的跨平台 Redis 桌面客户端,支持 Mac、Windows 和 Linux 4、能用到“退休”的 600条 Linux 命令,可以解决日常99%的问题~ 5、工作六年,看到这样的代码,内心五味杂陈... 6、拒绝写重复代码,试试这套开源的 SpringBoot 组件 7、一次生产事故,来来回回搞了一个月,人麻了! 8、面试官:Git 如何撤回已 Push 的代码?问倒一大片。。。 9、SpringBoot 如何快速过滤出一次请求的所有日志? 10、千万不要把 Request 传递到异步线程里面!有坑! 10、别再用 offset 和 limit 分页了,性能太差!
评论