Using Stream.of
to create generic streams is very convenient, but what if I want to create a Stream<String[]>
of only one element?
Let’s say I have:
String[] tropicalFruits = new String[] {"pineapple", "banana", "mango"};
String[] fruits = new String[] {"melon", "peach", "apple"};
Then Stream.of(tropicalFruits, fruits)
produces a Stream<String[]>
of two elements. How can I achieve the same for a stream of a single element? If I try:
Stream<String[]> fruittyStream = Stream.of(tropicalFruits);
I get:
Error: incompatible types: inference variable T
has incompatible
bounds
equality constraints: java.lang.String[]
lower bounds: java.lang.String
Stream<String[]> fruittyStream = Stream.of(fruits);
^---------------^
I’ve googled for this and searched in SO but I got nothing. It seems to me that it’s not a very unusual or esoeteric problem, so it’s kind of surprising I didn’t get any answers (or I’m not searching with the right keywords).
Solution
Stream<String[]> stream = Stream.<String[]>of(tropicalFruits);
or
Stream<String[]> stream = Stream.of(new String[][]{tropicalFruits});
Explanation
To produce a Stream<T>
, Stream.of
takes either T
or T...
.
A T[]
parameter perfectly applies to the second signature.
Therefore, passing a String[]
invokes the Stream.of(String...)
version.
To change this behaviour, we need to provide some extra information about T
(1) or define it more clearly (=unambiguously) (2).
There are two ideas came to my mind:
- To specify a type argument of the method explicitly to use the first signature.
Stream.<String[]>of(new String[]{})
will produce a Stream<String[]>
.
- To wrap a
T[]
value in a T[][]
array to use the second signature.
Stream.of(new String[][]{})
will produce a Stream<String[]>
.
This Stream<String[]> fruittyStream = Stream.of(tropicalFruits);
calls the var-arg method of Stream.of
.
I can think of this workaround:
List<String> list = Arrays.asList("one");
Stream.of(list)
.map(x -> x.toArray(new String[1]));
Or you can call the var-args method a bit differently:
Stream.of(tropicalFruits, null)
.filter(Objects::nonNull)
.forEach(x -> System.out.println(Arrays.toString(x)));
By calling Stream#of
with a single T[]
, Java defaults to the vararg factory method, creating a Stream<T>
rather than a Stream<T[]>
. To create a Stream<T[]>
with a single element, you can either create a Stream<T[]>
with multiple elements and call limit(1)
, or use a dummy array for the second element:
Stream<String[]> stream = Stream.of(tropicalFruits, fruits).limit(1);
Stream<String[]> stream = Stream.of(tropicalFruits, new String[] {});