Java 8: iterating across all elements of a Map

我的未来我决定 提交于 2019-12-24 17:09:36

问题


I'm having a validate method that return a boolean.

I'm using invoking this method (Java 7) as follow:

    boolean isValid = true;
    for (String key: aMap.keySet()) {
        isValid &= validate(key, aMap.get(key));
    }

I would like to rewrite this code in Java 8.

Java 8 allows iterating across a Map using:

aMap.forEach((k,v) -> validate(k, v));

But this won't work:

aMap.forEach((k,v) -> isValid &= validate(k, v)); 

Question

How can I rewrite the the Java 7 code into Java 8 to achieve the same result?

Note:

I asked a similar question here . The difference in this post is that I want to iterate this time across all the items of the Map (for the validate method to build a validation report). isValid must return true if no validation error occurred, or false if at least one occurred.


回答1:


You can use

boolean isValid = aMap.entrySet().stream()
    .map(e -> validate(e.getKey(), e.getValue()))
    .reduce(true, Boolean::logicalAnd);

as, unlike anyMatch, allMatch, etc, Reduction knows no short-circuiting. However, your requirement of executing all validate method calls suggests that there are side-effects within that method. It’s important to understand that these side effects must be non-interfering, i.e. it should not matter in which order these method calls are made and even concurrent evaluation of multiple elements should not break it.

Even when these requirements are met, it is rather discouraged to have such side-effects in a functional operation. E.g., the next developer looking at your code may say, “hey that looks like we should use allMatch here”…

So I’d stay with the loop. But when processing the associations of a Map, you should not loop over the entrySet(), to perform a lookup for every key, but rather use

boolean isValid = true;
for(Map.Entry<String, ValueType> e: aMap.entrySet())
    isValid &= validate(e.getKey(), e.getValue());

Starting with Java 10, you may use

boolean isValid = true;
for(var e: aMap.entrySet()) isValid &= validate(e.getKey(), e.getValue());

eliminating the most annoying syntactical element of that loop.




回答2:


The issue with aMap.forEach((k,v) -> isValid &= validate(k, v)); is that the variable captured in a lambda expression should be final or effectively final. This is the same for anonymous inner classesin Java.

So, to answer your query, you can convert isValid to a final one element array, like this:

final boolean[] isValid = {true}; and then
aMap.forEach((k,v) -> isValid[0] &= validate(k, v));

You can also probably make it atomic, but that would require more code changes. This solution is much simpler.



来源:https://stackoverflow.com/questions/51426673/java-8-iterating-across-all-elements-of-a-map

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!