4
\$\begingroup\$

Hello dear colleagues.

As an exercise for Java streams, I've written simple program, which scrapes links to references from a news portal. Basically, I wanted to find out, which portals are the most referenced.

Right now, I ended up with the following piece of code:

final Map<String, List<URL>> hostToURLs = Analyzer.mapByHost(ReferencesStore.read());
// E.g. bbc.com -> [ https://www.bbc.com/article1, https://www.bbc.com/article2, etc ]

// The following creates LinkedHashMap sorted by the number of URLs        
final LinkedHashMap<String, List<URL>> sortedHostToURLs = hostToURLs
                .entrySet()
                .stream()
                .sorted(Map.Entry.comparingByValue(Comparator.comparingInt(List::size)))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (m, n) -> { m.addAll(n); return m; }, LinkedHashMap::new));

I'm interested, if the the ugly merge lambda (m,n)-> {m.addAll(n); return m;} in the collect method can be replaced with some method reference from standard library. I wasn't able to find anything useful in the documentation, nor was I able to ask google the right question to find out if such merge function exists. Thank you in advance.

\$\endgroup\$
3
  • \$\begingroup\$ Why convert back to a map? Just print each Map.Entry \$\endgroup\$ Jul 20, 2020 at 11:35
  • 1
    \$\begingroup\$ I'm using the sorted Map in following method calls, where I want the data to be sorted. Thank you for pointing this out. The print statement was there only for initial debugging purposes. I removed it so hopefully my intention with the code is more clear now. \$\endgroup\$ Jul 20, 2020 at 13:53
  • \$\begingroup\$ "How do I join to lists in Java?" (stackoverflow.com/questions/189559/…) suggests that Java does not provide a List concatenation method; the alternatives all suggest converting the lists to streams, concatenating the streams, and converting the output stream to a list. \$\endgroup\$
    – drew
    Jul 21, 2020 at 14:43

1 Answer 1

4
\$\begingroup\$

The thing is that the merge function is never called in your case, because all you are doing is reordering an existing map, so IMO you don't really need to worry about it.

Personally in such cases I just use (m, n) -> m, because it's short and doesn't distract.

Another variant would be to use a function that throws an exception when called. The JDK does this itself when you use the toMap overload that doesn't take a merge function:

private static <T> BinaryOperator<T> throwingMerger() {
  return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}

Another thing you may want to consider it not to use a (Linked)HashMap at all here, but simply collect the Entrys into a list. If you need to lookup an entry by key later, then just keep the original map around.


EDIT: In cases where the merge function is used, your implemention is fine. You may want to just put it in a variable, so that its name can describe its function.

One thing you could consider is using a function that creates a new list instead of "reusing" one of the existing lists. That would reflect the functional style of the code better, where one normally uses immutable data structures.

The basic problem is that Java's List interface isn't intended for functional/immutable situations and doesn't have a simple method to concatinate two lists.

If you are open to additional libraries you'd have more options. For example, Apache's Commons has a union method.

\$\endgroup\$
2
  • \$\begingroup\$ Thank you for your response. I din't realised the merge function is not called. But still, for the sake of my curiosity, would be there a better solution than the mine if the scenario was a bit different and the merge function was called? \$\endgroup\$ Jul 20, 2020 at 14:16
  • \$\begingroup\$ @AnotherNoob See edit. \$\endgroup\$
    – RoToRa
    Jul 20, 2020 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.