英文:
Populating an existing Set<String> via Java 8 streams
问题
I am new to Java streams and functional programming and I wonder if my question will ever even have a valid use case or it is just not meaningful.
我对Java流和函数式编程很陌生,我想知道我的问题是否有有效的用例,还是根本没有意义。
I have the following code that gives me a Set<String> from an array
我有以下的代码,它从一个数组中给我一个Set<String>。
This gives me an empty dict. If I do it the way I have in second last line, it works. Is there a way to mutate already instantiated dict
that was instantiated outside stream that it gets populated in the map
function?
这会给我一个空的字典。如果我按照倒数第二行的方式做,它会工作。有没有一种方法可以修改已经在流外实例化的dict
,以使其在map
函数中得到填充?
英文:
I am new to Java streams and functional programming and I wonder if my question will ever even have a valid use case or it is just not meaningful.
I have the following code that gives me a Set<String> from an array
public static void main(String[] args) {
String []arr = {"a","abc","b","cd"};
Set<String> dict = new HashSet<>();
Arrays.stream(arr).map(item->{
System.out.println(item);
dict.add(item);
return dict;
});
// dict = Arrays.stream(arr).collect(Collectors.toSet());
System.out.println(dict);
}
This gives me an empty dict. If I do it the way I have in second last line, it works. Is there a way to mutate already instantiated dict
that was instantiated outside stream that it gets populated in the map
function?
答案1
得分: 5
Stream.map()
是一个中间操作,意味着它只是流水线中的一个步骤,但当你调用它时并不会执行任何操作。你需要一个终端操作来让流开始工作。在你的情况下,你可以使用 forEachOrdered()
:
Arrays.stream(arr)
.peek(System.out::println)
.forEachOrdered(dict::add);
注意:我假设你需要修改现有的集合而不是生成一个新的集合。否则,可以像其他答案中建议的那样使用 collect()
。
英文:
Stream.map()
is an intermediate operation, meaning it only stages a step of the pipeline, but it doesn't do anything when you call it. You need a terminal operation to put the stream to work. In your case, you can use forEachOrdered()
:
Arrays.stream(arr)
.peek(System.out::println)
.forEachOrdered(dict::add);
Note: I'm assuming there's a reason you need to modify an existing set rather than produce a new one. Otherwise, just use collect()
as suggested in the other answer.
答案2
得分: 3
- 在问题被编辑之前,已注释部分无法编译,因为
dict
必须是 final 或者 effectively final。有关更多信息,请参见此答案。 - 使用 Stream API 的少数规则之一是避免副作用。
java.util.stream
包的 JavaDoc 用示例很好地描述了这一点:
> 通常不鼓励在流操作的行为参数中使用副作用,因为这往往会导致无意中违反无状态要求,以及其他线程安全风险。 - 每个 Stream 的要点是通过诸如过滤、映射、归约或高级收集等操作返回新的集合/值。它从未旨在修改现有集合。将数组
arr
转换为集合的正确方式是:Set<String> dict = Arrays.stream(arr) .peek(item -> System.out.println(item)) // 用于调试的可选项 .collect(Collectors.toSet());
英文:
- Before the question got edited, the commented part didn't compile because
dict
must be either final or effectively final. See this answer for more information. - One of the few rules of using Stream API is to avoid side effects. The JavaDoc for
java.util.stream
package describes it well with examples:
> Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement, as well as other thread-safety hazards. - The gist of each Stream is to return a new collection/value through operations such as filtering, mapping, reducing, or advanced collecting. It was never meant to modify an existing one. The correct way how to transform the array
arr
into a set is:Set<String> dict = Arrays.stream(arr) .peek(item -> System.out.println(item)) // optional for debugging .collect(Collectors.toSet());
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论