Reputation: 3
I'm fairly new to Java and trying to learn how to use streams for easier code writing. If I can code like this:
Map<String, SomeConfig> temp = new HashMap<>();
resultStorage.forEach((key, value) -> key.getUsers().forEach(user -> {
if (!temp.containsKey(user.getMeta())) {
SomeConfig emailConfiguration = key
.withCheck1(masterAccountId)
.withCheck2(getClientTimezone())
.withCheck3(user.getMeta());
temp.put(user.getMeta(), emailConfiguration);
}
temp.get(user. getMeta()).getStreams().add(value);
}));
return new ArrayList<>(temp.values());
resultStorage
declaration:
private Map< SomeConfig, byte[]> resultStorage = new ConcurrentHashMap<>();
getStreams
is a getter on SomeConfig
that returns a List<byte[]>
as here:
private List<byte[]> attachmentStreams = new ArrayList<>();
public List<byte[]> getAttachmentStreams() {
return attachmentStreams;
}
My first attempt was something similar to this:
resultStorage.entrySet().stream()
.forEach(entry -> entry.getKey().getUsers().forEach(user -> {
}));
Are we able to use a forEach within one of the streams terminating operation, forEach? How would a stream benefit in this case as I saw documentation that it can significantly improve readability and performance of older pre-Java8 code?
Edit:
resultStorage
holds a ConcurrentHashMap. It will contain Map<SomeConfig, byte[]>
for email and attachments. Using another HashMap temp
that is initially empty - we analyze resultStorage
, see if temp
contains a specific email key, and then put
or add
based on the existence of a user's email
Upvotes: 0
Views: 465
Reputation: 20914
Notes after the code.
Map<String, SomeConfig> temp = resultStorage.keySet()
.stream()
.flatMap(key -> key.getUsers()
.stream()
.map(user -> new AbstractMap.SimpleEntry(user, key)))
.collect(Collectors.toMap(e -> e.getKey().getMeta(),
e -> e.getValue()
.withCheck1(masterAccountId)
.withCheck2(getClientTimezone())
.withCheck3(e.getKey().getMeta())
resultStorage.keySet()
This returns Set<SomeConfig>
.
stream()
This returns a stream where every element in the stream is an instance of SomeConfig
.
.flatMap(key -> key.getUsers()
.stream()
.map(user -> new AbstractMap.SimpleEntry(user, key)))
Method flatMap()
must return a Stream
. The above code returns a Stream
where every element is an instance of AbstractMap.SimpleEntry. The "entry" key is the user and the entry value is the key from resultStorage
.
Finally I create a Map<String, SomeConfig>
via [static] method toMap
of class Collectors.
The first argument to method toMap
is the key mapper, i.e. a method that extracts the [map] key from the AbstractMap.SimpleEntry
. In your case this is the value returned by method getMeta()
of the user – which is the key from AbstractMap.SimpleEntry
, i.e. e.getKey()
returns a user object.
The second argument to toMap
is the value mapper. e.getValue()
returns a SomeConfig
object and the rest is your code, i.e. the withCheck
s.
There is no way I can test the above code because not only did you not post a minimal, reproducible example, you also did not post any sample data. Hence the above may be way off what you actually require.
Also note that the above code simply creates your Map<String, SomeConfig> temp
. I could not understand the code in your question that processes that Map
so I did not try to implement that part at all.
Upvotes: 0
Reputation: 298233
The terminal operation of entrySet().stream().forEach(…)
is entirely unrelated to the getUsers().forEach(…)
call within the Consumer
. So there’s no problem of “multiple terminal operations” here.
However, replacing the Map
operation forEach((key, value) -> …
with an entrySet() .stream() .forEach(entry -> …)
rarely adds a benefit. So far, you’re not only made the code longer, you introduced the necessity to deal with a Map.Entry
instead of just using key
and value
.
But you can simplify your operation by using a single computeIfAbsent
instead of containsKey
, put
, and get
:
resultStorage.forEach((key, value) -> key.getUsers().forEach(user ->
temp.computeIfAbsent(user.getMeta(), meta ->
key.withCheck1(masterAccountId).withCheck2(getClientTimezone()).withCheck3(meta))
.getStreams().add(value)));
Upvotes: 2