Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One-to-one map with Java streams

Having a little trouble using the Stream API to get a one to one mapping. Basically, say you've got a class.

public class Item {
    private final String uuid;

    private Item(String uuid) {
        this.uuid = uuid;
    }

    /**
    * @return universally unique identifier
    */
    public String getUuid() {
        return uuid;
    }
}

I'd like a Map<String, Item> for easy look up. But given a Stream<Item> there doesn't seem a simple way to arrive at that Map<String, Item>.

Obviously, Map<String, List<Item>> ain't no thing:

public static Map<String, List<Item>> streamToOneToMany(Stream<Item> itemStream) {
    return itemStream.collect(groupingBy(Item::getUuid));
}

That's the safer more general case, but we do know in this situation that there will only ever be one-to-one. I can't find anything that compiles though -- I've specifically been trying to muck with the downstream parameter to Collectors.groupingBy. Something like:

// DOESN'T COMPILE
public static Map<String, Item> streamToOneToOne(Stream<Item> itemStream) {
    return itemStream.collect(groupingBy(Item::getUuid, Function.identity()));
}

What am I missing?

like image 849
jwilner Avatar asked Jul 26 '15 18:07

jwilner


People also ask

Can we get a map from a stream in Java?

Method 1: Using Collectors.toMap() Function The Collectors. toMap() method takes two parameters as the input: KeyMapper: This function is used for extracting keys of the Map from stream value. ValueMapper: This function used for extracting the values of the map for the given key.

How does map work in Java stream?

Stream map() in Java with examples Stream map(Function mapper) returns a stream consisting of the results of applying the given function to the elements of this stream. Stream map(Function mapper) is an intermediate operation. These operations are always lazy.

How do I combine two streams in Java?

concat() in Java. Stream. concat() method creates a concatenated stream in which the elements are all the elements of the first stream followed by all the elements of the second stream. The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel.


2 Answers

Use the Collectors#toMap(Function, Function), generating the key from each Item's uuid and the Item as the value itself.

public static Map<String, Item> streamToOneToOne(Stream<Item> itemStream) {
    return itemStream.collect(Collectors.toMap(Item::getUuid, Function.identity()));
}

Note from the javadoc

If the mapped keys contains duplicates (according to Object.equals(Object)), an IllegalStateExceptionis thrown when the collection operation is performed. If the mapped keys may have duplicates, use toMap(Function, Function, BinaryOperator) instead.

like image 188
Sotirios Delimanolis Avatar answered Nov 15 '22 20:11

Sotirios Delimanolis


groupingBy() collects items (plural, as a List) by a key.

You want toMap():

public static Map<String, Item> streamToOneToOne(Stream<Item> itemStream) {
    return itemStream.collect(toMap(Item::getUuid, Function.identity()));
}
like image 33
Bohemian Avatar answered Nov 15 '22 20:11

Bohemian