I have a Set<String>
of "hostname:port"
pairs and from that I'd like to create a Set<InetSocketAddress>
. I tried it like:
Set<InetSocketAddress> ISAAddresses = StrAddresses
.stream().map(addr -> new InetSocketAddress(
addr.split(":")[0],
Integer.parseInt(addr.split(":")[1])));
But this produces the following error in IntelliJ:
Incompatible types. Required
Set<InetSocketAddress>
but 'map' was inferred toStream<R>
: no instance(s) of type variable(s) R exist so thatStream<R>
conforms toSet<InetSocketAddress>
Something must be wrong with how I'm using the map and the lambda.
The Stream#map
function does not return a Map
. It transforms (maps) the current elements of your stream to other elements. So it generates from a Stream<X>
a Stream<Y>
using the given transformation function which takes X
and outputs Y
.
StrAddresses.stream() // String
.map(addr -> new InetSocketAddress(
addr.split(":")[0],
Integer.parseInt(addr.split(":")[1]))); // InetSocketAddress
You start with a Stream<String>
and end up with a Stream<InetSocketAddress>
.
To quote from its documentation:
Returns a stream consisting of the results of applying the given function to the elements of this stream.
If you want to transform that stream into a Set
you need to use the Stream#collect
method like so:
StrAddresses.stream()
.map(addr -> new InetSocketAddress(
addr.split(":")[0],
Integer.parseInt(addr.split(":")[1])))
.collect(Collectors.toSet());
The utility method Collectors.toSet()
returns a collector for a well optimized Set
. If you for example explicitly want a HashSet
you can use this instead:
.collect(Collectors.toCollection(HashSet::new));
From its documentation:
Performs a mutable reduction operation on the elements of this stream. A mutable reduction is one in which the reduced value is a mutable result container, such as an
ArrayList
[...]
As a small note, you currently split the same element twice each time:
addr.split(":")[0], // First
Integer.parseInt(addr.split(":")[1]))) // Second
You could save that additional split
procedure by memorizing the value before. In this case this can be done elegantly by using a second Stream#map
call. First we transform from Stream<String>
to Stream<String[]>
and then to Stream<InetSocketAddress>
:
StrAddresses.stream() // String
.map(addr -> addr.split(":")) // String[]
.map(addrData -> new InetSocketAddress(
addrData[0], Integer.parseInt(addrData[1]))) // InetSocketAddress
.collect(Collectors.toSet());
Note that Stream#map
is a lazy operation. This means that Java will not transform the whole Stream
from A
to B
once you call the method. It will wait until a non-lazy (finalizing) operation like Stream#collect
comes, then traverse the Stream
and apply each lazy operation element-wise. So you can add as many Stream#map
calls as you like without producing extra loops over the whole Stream
.