Stream.of()
Create a sequential, ordered stream from a few values or an object array, and avoid the primitive-array trap that gives you a stream of one element.
static <T> Stream<T> of(T t)
@SafeVarargs static <T> Stream<T> of(T... values)- Added in Java Java 8
Parameters
| Parameter | Type | Description |
|---|---|---|
$t | T | The single element of the stream (the one-argument overload). It may be null; use Stream.ofNullable to get an empty stream for null instead. |
$values | T... | The elements of the stream (the varargs overload). An object array passed here is spread into its elements; a primitive array is not. |
Return value
Stream<T>A sequential, ordered stream whose elements are the given values, in argument order.
Errors
NullPointerException if the varargs array itself is null. A null element is allowed and becomes a null in the stream.
Stream.of is the quickest way to make a stream from values you already have in your hand. It has two overloads: one takes a single element, the other takes varargs. Both return a sequential, ordered stream, so the elements come out in the order you wrote them.
When to use it
Use it for a fixed, small set of values: the allowed sort fields of an endpoint, a handful of IDs in a test, or several lists you want to process as one. When you already hold a collection, call collection.stream() instead; wrapping the list in Stream.of(list) gives you a stream with exactly one element, the list itself.
Arrays: object versus primitive
An object array such as String[] matches the varargs parameter directly, so Stream.of(tags) is a stream of the strings. A primitive array such as int[] cannot be a T[], because generics need reference types. It is treated as one object, and you get a Stream<int[]> with a single element. This is the most common surprise with Stream.of. For primitives use IntStream.of(...), LongStream.of(...) or Arrays.stream(array), which also avoid boxing.
Nulls and optional values
Stream.of(x) with a null x gives a stream holding one null, which later fails in any mapper that calls a method on it, or in findFirst. Stream.ofNullable(x) (Java 9) gives an empty stream for null and a one-element stream otherwise. Combined with flatMap it drops absent values from a list of optional request headers or lookups.
One use only
A stream is a one-shot pipeline, not a container. Storing a Stream in a field or a variable and running two terminal operations on it throws IllegalStateException with the message stream has already been operated upon or closed. Keep the source (a list, or a Supplier<Stream<T>>) and create a new stream each time.
Joining several sources
Stream.of(a, b, c).flatMap(List::stream) concatenates any number of lists in order. For exactly two streams, Stream.concat(s1, s2) does the same job. Nesting concat calls deeply is discouraged by its documentation, because it builds a deep chain that can overflow the stack; the Stream.of(...).flatMap(...) form has no such limit.
Example
When to use it
- Validate a sort parameter against the fixed set of field names an endpoint allows.
- Merge results from a cache, a database query and a remote call into one stream before mapping them to response objects.
- Collect only the correlation headers a request actually sent by flat-mapping each one through Stream.ofNullable.
Frequently asked questions
What is the difference between Stream.of and Arrays.stream?
For an object array they behave the same, since Stream.of(T...) calls Arrays.stream internally. For a primitive array they differ: Arrays.stream(int[]) returns an IntStream of the numbers, while Stream.of(int[]) returns a Stream<int[]> with the whole array as its only element. Arrays.stream also has an overload that takes a start and end index.
Why do I get 'stream has already been operated upon or closed'?
A stream can run only one terminal operation. If you store a Stream in a variable and call toList() and then count() on it, the second call throws IllegalStateException. Create a new stream from the source each time, for example with a Supplier<Stream<T>>.
How do I make a stream from a value that might be null?
Use Stream.ofNullable(value), added in Java 9. It returns an empty stream for null and a one-element stream otherwise. Stream.of(null value) gives a stream containing null, which tends to fail later in a mapper that calls a method on it, or in findFirst.
More examples
Dropping missing values with Stream.ofNullable
Stream.of keeps the null as an element, so the plain stream still counts 3. flatMap(Stream::ofNullable) turns each null into an empty stream, which is a tidy way to collect only the identifiers a request actually carried.
void main() {
String requestId = "req-42";
String traceId = null;
String sessionId = "s-7";
List<String> present = Stream.of(requestId, traceId, sessionId)
.flatMap(Stream::ofNullable)
.toList();
IO.println(present);
IO.println(Stream.ofNullable(traceId).count());
IO.println(Stream.of(requestId, traceId, sessionId).count());
}
// Output:
// [req-42, s-7]
// 0
// 3A stream can be consumed only once
The second terminal operation on the same stream object fails. A Supplier that builds a new stream on each call is the usual fix when the same values must be processed twice.
void main() {
Stream<String> names = Stream.of("ada", "linus");
IO.println(names.toList());
try {
names.count();
} catch (IllegalStateException e) {
IO.println(e.getMessage());
}
// Keep a way to make a fresh stream instead of the stream itself
Supplier<Stream<String>> source = () -> Stream.of("ada", "linus");
IO.println(source.get().count() + " " + source.get().toList());
}
// Output:
// [ada, linus]
// stream has already been operated upon or closed
// 2 [ada, linus]Processing several lists as one
Stream.of over the lists gives a stream of three lists; flatMap(List::stream) opens each one up in order. This is how you merge users from several sources before filtering or mapping them once.
void main() {
List<String> admins = List.of("ada");
List<String> editors = List.of("bob", "cyd");
List<String> viewers = List.of("dee");
List<String> everyone = Stream.of(admins, editors, viewers)
.flatMap(List::stream)
.toList();
IO.println(everyone);
// Without flatMap the elements are the lists themselves
IO.println(Stream.of(admins, editors, viewers).count());
// For exactly two streams, concat does the same job
IO.println(Stream.concat(admins.stream(), viewers.stream()).toList());
}
// Output:
// [ada, bob, cyd, dee]
// 3
// [ada, dee]
Discussion