
Reading this article will take approximately 16 minutes.
From: blog.csdn.net/mu_wind/article/details/91464351
1 Basic Features
1.1 Characteristics of Streams
-
stream
does not store data but computes it according to specific rules, typically producing a result; -
stream
does not modify the data source; it usually produces a new collection; -
stream
has lazy execution characteristics, where intermediate operations are only executed when terminal operations are called. -
Operations on
stream
can be categorized into terminal operations and intermediate operations. Terminal operations consume the stream and produce a result. Once a stream has been consumed, it cannot be reused. Intermediate operations produce another stream, allowing for the creation of a pipeline of actions. A critical point to note is that intermediate operations do not occur immediately. Instead, the operations specified by intermediate operations only occur after terminal operations are executed on the newly created stream. Thus, intermediate operations are delayed, which allows the Stream API to execute more efficiently. -
stream
cannot be reused; calling on a stream that has already undergone terminal operations will throw an exception.
1.2 Creating Streams
public static void main(String[] args) { //1. Creating via Arrays.stream //1.1 Primitive types int[] arr = new int[]{1,2,34,5}; IntStream intStream = Arrays.stream(arr); //1.2 Reference types Student[] studentArr = new Student[]{new Student("s1",29),new Student("s2",27)}; Stream<Student> studentStream = Arrays.stream(studentArr); //2. Creating via Stream.of Stream<Integer> stream1 = Stream.of(1,2,34,5,65); // Note that this generates a stream of int[] Stream<int[]> stream2 = Stream.of(arr,arr); stream2.forEach(System.out::println); }
public static void main(String[] args) { List<String> strs = Arrays.asList("11212","dfd","2323","dfhgf"); // Create a regular stream Stream<String> stream = strs.stream(); // Create a parallel stream Stream<String> stream1 = strs.parallelStream(); }
2 Detailed Stream API
2.1 BaseStream Details
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(); }

2.2 Stream Details
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); IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper); LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper); DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> 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 factories public static<T> Builder<T> builder() { return new Streams.StreamBuilderImpl<>(); } public static<T> Stream<T> empty() { return StreamSupport.stream(Spliterators.<T>emptySpliterator(), false); } public static<T> Stream<T> of(T t) { return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false); } @SafeVarargs @SuppressWarnings("varargs") // Creating a stream from an array is safe public static<T> Stream<T> of(T... values) { return Arrays.stream(values); } public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) { Objects.requireNonNull(f); final Iterator<T> iterator = new Iterator<T>() { @SuppressWarnings("unchecked") T t = (T) Streams.NONE; @Override public boolean hasNext() { return true; } @Override public T next() { return t = (t == Streams.NONE) ? seed : f.apply(t); } }; return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED | Spliterator.IMMUTABLE), false); } public static<T> Stream<T> generate(Supplier<T> s) { Objects.requireNonNull(s); return StreamSupport.stream(new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false); } public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) { Objects.requireNonNull(a); Objects.requireNonNull(b); @SuppressWarnings("unchecked") Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>((Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator()); Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel()); return stream.onClose(Streams.composedClose(a, b)); } }

3 Common Methods
3.1 Data Used for Demonstration
public class Person { private String name; private int salary; // Constructor public Person(String name, int salary) { this.name = name; this.salary = salary; } // Omitted getter and setter methods } public class MyTest { public static void main(String[] args) { List<Person> personList= new ArrayList<Person>(); persons.add(new Person("Tom", 8900)); persons.add(new Person("Jack", 7000)); persons.add(new Person("Lily", 9000)); } }
3.2 Filtering and Matching
public static void main(String[] args) { 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); // Expected result: [8,9] }
public static void main(String[] args) { List<Person> collect = personList.stream().filter(x -> x.getSalary() > 8000).collect(Collectors.toList()); // Expected result: A collection of entities that meet the criteria }
public static void main(String[] args) { List<Integer> list = Arrays.asList(7,6,9,3,8,2,1); // Match the first Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst(); // Match any (suitable for parallel streams) Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny(); // Check if any match boolean anyMatch = list.stream().anyMatch(x -> x < 6); System.out.println(findFirst); System.out.println(findAny); System.out.println(anyMatch); } // Expected results: // 1. Optional[7] // 2. Result uncertain for parallel stream // 3. true
3.3 Aggregation
3.3.1 max, min, and count
public static void main(String[] args) { List<String> list = Arrays.asList("adnm","admmt","pot"); Optional<String> max = list.stream().max(Comparator.comparing(String::length)); System.out.println(max); // Expected result: Optional[admmt] }
public static void main(String[] args) { List<Integer> list = Arrays.asList(7,6,9); Optional<Integer> reduce = list.stream().max(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }); System.out.println(reduce); // Output result: Optional[9] }
public static void main(String[] args) { list.add(new Person("a", 4)); list.add(new Person("b", 4)); list.add(new Person("c", 6)); Optional<Person> max = list.stream().max(Comparator.comparingInt(Person::getSalary)); System.out.println(max.get().getSalary()); // Output result: 6; change max to min for minimum value. }
public static void main(String[] args) { List<Integer> list = Arrays.asList(7,6,9); long count = list.stream().filter(x -> x > 6).count(); System.out.println(count); // Expected result: 2 }
3.3.2 Reduction (reduce)
public interface Stream<T> extends BaseStream<T, Stream<T>> { // Method 1 T reduce(T identity, BinaryOperator<T> accumulator); // Method 2 Optional<T> reduce(BinaryOperator<T> accumulator); // Method 3 <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner); }
public static void main(String[] args) throws Exception { List<Integer> list = Arrays.asList(1, 3, 2); // Sum Integer sum = list.stream().reduce(1, (x, y) -> x + y); // Result is 7, which is the sum of list elements plus 1 System.out.println(sum); // Alternative writing Integer sum2 = list.stream().reduce(1, Integer::sum); System.out.println(sum2); // Result: 7 // Finding maximum Integer max = list.stream().reduce(6, (x, y) -> x > y ? x : y); System.out.println(max); // Result: 6 // Alternative writing Integer max2 = list.stream().reduce(1, Integer::max); System.out.println(max2); // Result: 3 }
public class MyTest { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900)); personList.add(new Person("Jack", 7000)); personList.add(new Person("Lily", 9000)); // Sum // Expected result: Optional[24900] System.out.println(personList.stream().map(Person::getSalary).reduce(Integer::sum)); // Finding maximum - Method 1 Person person = personList.stream().reduce((p1, p2) -> p1.getSalary() > p2.getSalary() ? p1 : p2).get(); // Expected result: Lily:9000 System.out.println(person.getName() + ":" + person.getSalary()); // Finding maximum - Method 2 // Expected result: Optional[9000] System.out.println(personList.stream().map(Person::getSalary).reduce(Integer::max)); // Finding maximum - Method 3: System.out.println(personList.stream().max(Comparator.comparingInt(Person::getSalary)).get().getSalary()); } }
3.3.3 Collecting (collect)
public interface Stream<T> extends BaseStream<T, Stream<T>> { <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); }
1. Averaging Series
public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900)); personList.add(new Person("Jack", 7000)); personList.add(new Person("Lily", 9000)); Double averageSalary = personList.stream().collect(Collectors.averagingDouble(Person::getSalary)); System.out.println(averageSalary); // Result: 8300 }
2. Summarizing Series
public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900)); personList.add(new Person("Jack", 7000)); personList.add(new Person("Lily", 9000)); DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary)); System.out.println(collect); // Output result: // DoubleSummaryStatistics{count=3, sum=24900.000000, min=7000.000000, average=8300.000000, max=9000.000000} }
3. Joining
public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900)); personList.add(new Person("Jack", 7000)); personList.add(new Person("Lily", 9000)); String names = personList.stream().map(p -> p.getName()).collect(Collectors.joining(",")); System.out.println(names); }
4. Reduce
public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900)); personList.add(new Person("Jack", 7000)); personList.add(new Person("Lily", 9000)); Integer sumSalary = personList.stream().collect(Collectors.reducing(0, Person::getSalary, (i, j) -> i + j)); System.out.println(sumSalary); // Result: 24900 // Optional<Integer> sumSalary2 = list.stream().map(Person::getSalary).reduce(Integer::sum); System.out.println(sumSalary2); // Optional[24900] }
5. Grouping By
public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900)); personList.add(new Person("Jack", 7000)); personList.add(new Person("Lily", 9000)); // Single-level grouping Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getName)); System.out.println(group); // Output result: {Tom=[mutest.Person@7cca494b], // Jack=[mutest.Person@7ba4f24f],Lily=[mutest.Person@3b9a45b3]} // Multi-level grouping: first group by name, then by salary: Map<String, Map<Integer, List<Person>>> group2 = personList.stream() .collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getSalary))); System.out.println(group2); // Output result: {Tom={8900=[mutest.Person@7cca494b]},Jack={7000=[mutest.Person@7ba4f24f]},Lily={9000=[mutest.Person@3b9a45b3]}} }
6. toList, toSet, toMap
public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900)); personList.add(new Person("Jack", 7000)); personList.add(new Person("Lily", 9000)); personList.add(new Person("Lily", 5000)); // toList List<String> names = personList.stream().map(Person::getName).collect(Collectors.toList()); System.out.println(names); // toSet Set<String> names2 = personList.stream().map(Person::getName).collect(Collectors.toSet()); System.out.println(names2); // toMap Map<String, Person> personMap = personList.stream().collect(Collectors.toMap(Person::getName, p -> p)); System.out.println(personMap); }
3.4 Mapping (map)
1. Data>>Data
public static void main(String[] args) { String[] strArr = { "abcd", "bcdd", "defde", "ftr" }; Arrays.stream(strArr).map(x -> x.toUpperCase()).forEach(System.out::println); // Expected result: ABCD BCDD DEFDE FTR }
2. Object Collection>>Data
public static void main(String[] args) { // To save space, personList reuses the demonstration data's personList personList.stream().map(person -> person.getSalary()).forEach(System.out::println); // Expected result: ABCD BCDD DEFDE FTR }
3. Object Collection>>Object Collection
public static void main(String[] args) { // To save space, personList reuses the demonstration data's personList List<Person> collect = personList.stream().map(person -> { person.setName(person.getName()); person.setSalary(person.getSalary() + 10000); return person; }).collect(Collectors.toList()); System.out.println(collect.get(0).getSalary()); System.out.println(personList.get(0).getSalary()); List<Person> collect2 = personList.stream().map(person -> { Person personNew = new Person(null, 0); personNew.setName(person.getName()); personNew.setSalary(person.getSalary() + 10000); return personNew; }).collect(Collectors.toList()); System.out.println(collect2.get(0).getSalary()); System.out.println(personList.get(0).getSalary()); // Expected result: // 1. 18900 18900, indicating this approach altered the original personList. // 2. 18900 8900, indicating this approach did not alter the original personList. }
3.5 Sorting (sorted)
public static void main(String[] args) { String[] strArr = { "abc", "m", "M", "bcd" }; System.out.println(Arrays.stream(strArr).sorted().collect(Collectors.toList())); // Expected result: [M, abc, bcd, m] }
public static void main(String[] args) { String[] strArr = { "ab", "bcdd", "defde", "ftr" }; // 1. Sort by length naturally, i.e., from shortest to longest Arrays.stream(strArr).sorted(Comparator.comparing(String::length)).forEach(System.out::println); // 2. Sort by length in reverse order, i.e., from longest to shortest Arrays.stream(strArr).sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println); // 3. Sort by first letter in reverse order Arrays.stream(strArr).sorted(Comparator.reverseOrder()).forEach(System.out::println); // 4. Sort by first letter naturally Arrays.stream(strArr).sorted(Comparator.naturalOrder()).forEach(System.out::println); // /** * thenComparing * First sort by first letter * Then by string length */ @Test public void testSorted3_(){ Arrays.stream(arr1).sorted(Comparator.comparing(this::com1).thenComparing(String::length)).forEach(System.out::println); } public char com1(String x){ return x.charAt(0); } // Expected results: // 1. ftr bcdd defde // 2. defde bcdd ftr ab // 3. ftr defde bcdd ab // 4. ab bcdd defde ftr }
3.6 Extracting Streams and Combining Streams
public static void main(String[] args) { String[] arr1 = {"a","b","c","d"}; String[] arr2 = {"d","e","f","g"}; String[] arr3 = {"i","j","k","l"}; /** * Streams can be combined into one stream (the combined stream type must be the same), only two can be combined at a time * Expected result: a b c d e (to save space, space replaces newline) */ Stream<String> stream1 = Stream.of(arr1); Stream<String> stream2 = Stream.of(arr2); Stream.concat(stream1,stream2).distinct().forEach(System.out::println); /** * limit, limits the number of data obtained from the stream to the first n * Expected result: 1 3 5 7 9 11 13 15 17 19 */ Stream.iterate(1,x->x+2).limit(10).forEach(System.out::println); /** * skip, skips the first n data * Expected result: 3 5 7 9 11 */ Stream.iterate(1,x->x+2).skip(1).limit(5).forEach(System.out::println); }
Recommended Reading:
【195期】Are You Familiar with the Conditional Judgment Functions CASE WHEN, IF, IFNULL in MySQL?
【194期】Redis—How Do We Execute Commands Not Wrapped in Third-Party Jars?
【193期】How to Use the Decorator Pattern to Extend Functionality Without Changing the Original Object?
Scan the QR code to follow my public account
I have read