英文:
Why are Java 8 stream elements not being accessed sequentially?
问题
我创建了一段代码,它读取一个字符串并创建出频率映射。我是在Java 8中提出的这个想法。
```java
final Map<Character, Integer> frequencyMap = new HashMap<>(26);
myString.chars()
.forEach(ch -> frequencyMap.put((char)ch, frequencyMap.getOrDefault(ch, 0) + 1));
然而,我的输出结果如下 -
[1, 1, 1, 1, 1, 1, 1, 1]
我理解Lambda函数只能访问它作用域外部的final/实际上的final变量,但在这里我似乎也没有违反这个规则。
我尝试通过显式地使流变成顺序流来解决这个问题,但仍然不起作用。
str.chars()
.sequential().forEach(ch -> frequencyMap.put((char)ch, frequencyMap.getOrDefault(ch, 0) + 1));
为了确保我在使用Map函数时没有问题,我尝试了相同的Map函数与数组,它可以工作 -
final Map<Character, Integer> frequencyMap = new HashMap<>(26);
for (char ch: str.toCharArray()) {
frequencyMap.put((char)ch, frequencyMap.getOrDefault(ch, 0) + 1);
}
这里的输出结果 -
[1, 1, 1, 1, 1, 2, 3, 4]
我知道存在许多不同的解决方案来执行这个操作,但我对于我漏掉了哪个概念很感兴趣。
<details>
<summary>英文:</summary>
I created a piece of code which reads a String & creates a frequency map out of it. I came up with this in Java 8.
final Map<Character, Integer> frequencyMap = new HashMap<>(26);
myString.chars()
.forEach(ch -> frequencyMap.put((char)ch, frequencyMap.getOrDefault(ch, 0) + 1));
However my output is as follows -
[1, 1, 1, 1, 1, 1, 1, 1]
I understand that the lambda functions can access only final/effectively final variables outside it's scope but here I don't seem to violate that rule as well.
I tried making the stream sequential explicitly by doing this but it still doesn't work
str.chars()
.sequential().forEach(ch -> frequencyMap.put((char)ch, frequencyMap.getOrDefault(ch, 0) + 1));
To be sure that there isn't a problem with the way I'm using Map functions I tried the same map functions with array & it works -
final Map<Character, Integer> frequencyMap = new HashMap<>(26);
for (char ch: str.toCharArray()) {
frequencyMap.put((char)ch, frequencyMap.getOrDefault(ch, 0) + 1);
}
Output here -
[1, 1, 1, 1, 1, 2, 3, 4]
I'm aware of the many different solutions that exist to do this but I'm interested in knowing what concept I'm missing here?
</details>
# 答案1
**得分**: 2
你的想法是正确的。如果你还将`ch`转换为`char`,你的初始代码就能够工作:
```java
final Map<Character, Integer> frequencyMap = new HashMap<>(26);
myString.chars()
.forEach(ch -> frequencyMap.put((char)ch, frequencyMap.getOrDefault((char)ch, 0) + 1));
如果你省略这个步骤,映射的键会是java.lang.Character
类型。搜索键是java.lang.Integer
类型,因此它们不相等。这会导致计数始终保持为1。
英文:
You had the right idea. Your initial code works if you also cast ch
to char:
final Map<Character, Integer> frequencyMap = new HashMap<>(26);
myString.chars()
.forEach(ch -> frequencyMap.put((char)ch, frequencyMap.getOrDefault((char)ch, 0) + 1));
If you omit this, the map key is a java.lang.Character
. The search key is a java.lang.Integer
and therefore they are not equal. This causes the count to stay 1 always.
答案2
得分: 0
试试这个。
Map<Character, Integer> frequencyMap = new HashMap<>(26);
myString.chars()
.forEach(ch -> frequencyMap.compute((char)ch, (k, v) -> v == null ? 1 : v + 1));
或者
Map<Character, Integer> frequencyMap = myString.chars()
.mapToObj(i -> (char)i)
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(e -> 1)));
或者
Map<Character, Long> frequencyMap = myString.chars()
.mapToObj(i -> (char)i)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
英文:
Try this.
Map<Character, Integer> frequencyMap = new HashMap<>(26);
myString.chars()
.forEach(ch -> frequencyMap.compute((char)ch, (k, v) -> v == null ? 1 : v + 1));
Or
Map<Character, Integer> frequencyMap = myString.chars()
.mapToObj(i -> (char)i)
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(e -> 1)));
Or
Map<Character, Long> frequencyMap = myString.chars()
.mapToObj(i -> (char)i)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论