Java Stream API Overview and Practical Usage Examples
This article provides a comprehensive guide to Java 8 Stream API, covering its core characteristics, creation methods, essential interfaces, and common operations such as filtering, mapping, reducing, collecting, grouping, and sorting, with clear code examples for each concept.
1. Basic Characteristics
Java 8 introduced the Stream API, which treats collections or arrays as a flow of elements that can be filtered, sorted, and processed without storing intermediate results.
1.1 Stream Features
streamdoes not store data; it computes results on demand. stream does not modify the source; it typically produces a new collection. stream operations are lazy and execute only when a terminal operation is invoked.
Streams are single‑use; invoking a terminal operation on a consumed stream throws an exception.
1.2 Creating Streams
From arrays:
public static void main(String[] args) {
// 1. Arrays.stream for primitive types
int[] arr = new int[]{1,2,34,5};
IntStream intStream = Arrays.stream(arr);
// 2. Arrays.stream for reference types
Student[] studentArr = new Student[]{new Student("s1",29), new Student("s2",27)};
Stream<Student> studentStream = Arrays.stream(studentArr);
// 3. Stream.of for var‑args
Stream<Integer> stream1 = Stream.of(1,2,34,5,65);
// 4. Stream.of for array streams (produces Stream<int[]>)
Stream<int[]> stream2 = Stream.of(arr, arr);
stream2.forEach(System.out::println);
}From collections:
public static void main(String[] args) {
List<String> strs = Arrays.asList("11212","dfd","2323","dfhgf");
// ordinary stream
Stream<String> stream = strs.stream();
// parallel stream
Stream<String> stream1 = strs.parallelStream();
}2. Stream API Details
The BaseStream interface defines the fundamental operations for all streams.
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {
Iterator<T> iterator();
Spliterator<T> spliterator();
boolean isParallel();
S sequential();
S parallel();
S unordered();
S onClose(Runnable closeHandler);
@Override void close();
}The Stream interface extends BaseStream and adds a rich set of intermediate and terminal operations.
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> predicate);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Stream<T> distinct();
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
Stream<T> peek(Consumer<? super T> action);
Stream<T> limit(long maxSize);
Stream<T> skip(long n);
void forEach(Consumer<? super T> action);
void forEachOrdered(Consumer<? super T> action);
Object[] toArray();
<A> A[] toArray(IntFunction<A[]> generator);
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
<R, A> R collect(Collector<? super T, A, R> collector);
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
long count();
boolean anyMatch(Predicate<? super T> predicate);
boolean allMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);
Optional<T> findFirst();
Optional<T> findAny();
static <T> Builder<T> builder() { return new Streams.StreamBuilderImpl<>(); }
static <T> Stream<T> empty() { return StreamSupport.stream(Spliterators.emptySpliterator(), false); }
static <T> Stream<T> of(T t) { return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false); }
@SafeVarargs static <T> Stream<T> of(T... values) { return Arrays.stream(values); }
static <T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) { /* implementation omitted */ }
static <T> Stream<T> generate(Supplier<T> s) { /* implementation omitted */ }
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) { /* implementation omitted */ }
}2.1 Common Operations
Filtering and Matching
List<Integer> intList = Arrays.asList(6,7,3,8,1,2,9);
List<Integer> collect = intList.stream().filter(x -> x > 7).collect(Collectors.toList());
System.out.println(collect); // [8,9]
List<Person> collect2 = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toList());
Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
boolean anyMatch = list.stream().anyMatch(x -> x < 6);Aggregation (max, min, count)
Optional<String> max = list.stream().max(Comparator.comparing(String::length));
Optional<Integer> maxInt = list.stream().max(Comparator.naturalOrder());
Optional<Person> maxPerson = list.stream().max(Comparator.comparingInt(Person::getSalary));
long count = list.stream().filter(x -> x > 6).count();Reduction (reduce)
Integer sum = list.stream().reduce(1, (x, y) -> x + y);
Optional<Integer> maxOpt = list.stream().reduce(Integer::max);
Integer sumSalary = personList.stream().reduce(0, (sum, p) -> sum + p.getSalary(), Integer::sum);Collecting (collect)
Double avgSalary = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
DoubleSummaryStatistics stats = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
String names = personList.stream().map(Person::getName).collect(Collectors.joining(","));
List<String> nameList = personList.stream().map(Person::getName).collect(Collectors.toList());
Set<String> nameSet = personList.stream().map(Person::getName).collect(Collectors.toSet());
Map<String, Person> personMap = personList.stream().collect(Collectors.toMap(Person::getName, p -> p));
Map<String, List<Person>> groupByName = personList.stream().collect(Collectors.groupingBy(Person::getName));
Map<String, Map<Integer, List<Person>>> multiGroup = personList.stream().collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getSalary)));Mapping (map)
String[] arr = {"abcd","bcdd","defde","ftr"};
Arrays.stream(arr).map(String::toUpperCase).forEach(System.out::println);
personList.stream().map(Person::getSalary).forEach(System.out::println);
List<Person> increased = personList.stream().map(p -> { p.setSalary(p.getSalary()+10000); return p; }).collect(Collectors.toList());Sorting (sorted)
String[] strs = {"abc","m","M","bcd"};
System.out.println(Arrays.stream(strs).sorted().collect(Collectors.toList())); // [M, abc, bcd, m]
Arrays.stream(strs).sorted(Comparator.comparing(String::length)).forEach(System.out::println);Stream Extraction and Combination
Stream<String> s1 = Stream.of(arr1);
Stream<String> s2 = Stream.of(arr2);
Stream.concat(s1, s2).distinct().forEach(System.out::println);
Stream.iterate(1, x -> x + 2).limit(10).forEach(System.out::println);
Stream.iterate(1, x -> x + 2).skip(1).limit(5).forEach(System.out::println);The article concludes with a list of additional interview‑question resources and a call‑to‑action for readers to follow the associated public account for more Java interview material.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
