Talk about a collection of .Stream Api

1. What is a stream API

Java8 provided stream API allows programmers to the same set of operations as the operation of the database. Stream API Java programmers can greatly improve the productivity of programmers to write efficient, clean, simple code. At the same time it provides both serial and parallel modes aggregation operation, concurrency model can take advantage of multi-core processors, using fork / join and split task in parallel to accelerate the process. Usually write parallel code is difficult and error-prone, but using Stream API without writing a single line of multi-threaded code, you can easily write high-performance concurrent programs. The stream API used are as follows;

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

Briefly, Stream API is a very efficient data processing framework.

2. stream of several features

  • Element is a particular type of object, a queue is formed. In Java Stream and does not store elements, but on-demand computing.
  • Source data sources. It may be a set, arrays, I / O channel, generator and generator and the like IntStream
  • Similar polymerization operation as the operation of the SQL statements, such as filter, map, reduce, find, match, sorted and the like.

3. Stream API use Liezi

3.1 Stream Category

It can create a stream of data from different sources. java collection package Collections, Lists, Sets of these new classes stream () and parallelStream () method, for creating a sequential stream (sequential streams) or a concurrent stream (Parallel streams) by these methods. Concurrent stream (Parallel streams) is more suitable for use in a multithreaded herein describes the sequence of the first stream (sequential streams) at the end will be described with concurrent stream (Parallel streams),

Arrays.asList("a1", "a2", "a3")
    .stream()
    .findFirst()
    .ifPresent(System.out::println);  // a1
1234

Call stream () method of the List object can return a regular stream of objects. In the following example, we do not need to create a collection object can also use the stream:

Stream.of("a1", "a2", "a3")
    .findFirst()
    .ifPresent(System.out::println);  // a1
123

Directly Stream.of () method will be able to create a stream object from a set of objects,

In addition to regular stream of objects, JAVA IntStream in 8, LongStream, DoubleStream these streams can be processed, such as basic data types: int, long, double. For example: IntStream use range () method can replace the traditional for loop

IntStream.range(1, 4)
    .forEach(System.out::println);
12

Basic types stream (primitive streams) use the general object stream type (regular object streams) largely the same, but the basic types stream (primitive streams) could use some special lambda expression, such as: instead of using IntFunction Function, instead of using IntPredicate the predicateA, at the same time 基本类型流(primitive streams)中可以支持一些聚合方法, such as: sum (), average () and the like.

Arrays.stream(new int[] {1, 2, 3})
    .map(n -> 2 * n + 1)
    .average()
    .ifPresent(System.out::println);  // 5.0
1234

mapToInt (), mapToLong (), mapToDouble () routine may flow through the object (regular object stream) of, mapToObj base stream type object (primitive streams) in () to complete the like between the general object of stream and the elementary stream type相互转换

IntStream.range(1, 4)
    .mapToObj(i -> "a" + i)
    .forEach(System.out::println);
123

The following example doubles stream is first mapped to int stream, and then is mapped to a String object stream:

Stream.of(1.0, 2.0, 3.0)
    .mapToInt(Double::intValue)
    .mapToObj(i -> "a" + i)
    .forEach(System.out::println);

// a1
// a2
// a

3.2 Stream API processing procedure of

We use the following Liezi to introduce a processing sequence of Stream:

  Stream.of("d2", "a2", "b1", "b3", "c")
                .filter(s -> {
                    System.out.println("filter: " + s);
                    return true;
                });

Imagine, the above Liezi will output the following:

filter: d2
filter: a2
filter: b1
filter: b3
filter: c

But when we execute this code, the console does not output anything. The reason for this phenomenon in terms of the following will occur next. Before speaking this reason we first introduce two related concepts Stream, can help us better understand the Stream API:

Final operation and intermediate operation

containing stream 中间(intermediate operations)and 最终(terminal operation)two forms of operation. 中间操作(intermediate operations)的返回值还是一个stream, It is possible to operate the intermediate (intermediate operations) in series by the chain calls. 最终操作(terminal operation)只能返回void或者一个非stream的结果。In the above example: filter, map, sorted intermediate operation, and is a final operation forEach. More operations are available on the stream can view java doc. The above example is also referred to chain calls the operating pipeline flow.

Most stream operation in some form of lambda expressions as parameters, by operation of the method specifies a specific behavior of the interface, the interface behavior of these methods are substantially non-interfering (non-interfering) and stateless (stateless). The method defined in interference-free (non-interfering) are: The method does not change the underlying data source stream, such as the above example: lambda expression is not add or delete elements in myList. No defined state (Stateless) method: performing the operations are independent, such as the above example, the lambda expression is not dependent on changes in external variables or states that may occur during execution.

The above summary of simple superficial those remarks: The return value is the type of operation or the middle Stream operation, the return value is a final operation or non-void Stream type operation. Stream API that does not alter the original data.

Stream The following is an interface, we return value can clearly determine which is the intermediate operation which is the final operation. We usually used as the operating filter, map, distinct, sort, and the like are intermediate operating limit.

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));
    }
    public interface Builder<T> extends Consumer<T> {
        @Override
        void accept(T t);
        default Builder<T> add(T t) {
            accept(t);
            return this;
        }
        Stream<T> build();
    }
}

With the above operations center and base the final operation, we look at the above operation Liezi Liezi will find in the middle of the operation and not only the final operation. Here you may already know the answer: Stream in operation will only be triggered to execute the final action.

Here's a look at the effect of adding a final operation:

Stream.of("d2", "a2", "b1", "b3", "c")
    .filter(s -> {
        System.out.println("filter: " + s);
        return true;
    })
    .forEach(s -> System.out.println("forEach: " + s));

The above code output following results:

filter:  d2
forEach: d2
filter:  a2
forEach: a2
filter:  b1
forEach: b1
filter:  b3
forEach: b3
filter:  c
forEach: c

We will find the filter operation after a filtration element will immediately enter the next step execution, rather than waiting for the completion of the entire collection and then filtering operation. (Map operation is also similar behavior)

3.3 and the relationship between the efficiency of order execution chain steream

Stream.of("d2", "a2", "b1", "b3", "c")
    .map(s -> {
        System.out.println("map: " + s);
        return s.toUpperCase();
    })
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.startsWith("A");
    })
    .forEach(s -> System.out.println("forEach: " + s));

Filter map and sequence of the above adjustments can significantly reduce the number of executions of the map, to enhance the efficiency;

Stream.of("d2", "a2", "b1", "b3", "c")
    .sorted((s1, s2) -> {
        System.out.printf("sort: %s; %s\n", s1, s2);
        return s1.compareTo(s2);
    })
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.startsWith("a");
    })
    .map(s -> {
        System.out.println("map: " + s);
        return s.toUpperCase();
    })
    .forEach(s -> System.out.println("forEach: " + s));

Sorting is a special intermediate operations (intermediate operation), in the collection of elements required for the sorting process to save the state of the element, thus Sorting is a stateful operation (stateful operation).

First, the sort operation (i.e., the first level of the set of operations) on the entire input set, since there are many combinations between input elements of the collection, thus sorted example above operation is performed eight times.

Can be performed by means of chain reordering, improve the efficiency of the stream. After modifying the chain performing sequential filter since the filter operation, cause the input operation of only one set of sorted elements, can greatly improve the efficiency in the case where a large amount of data.

3.4 Stream Multiplexing

Stream has a characteristic, that is, when you执行完任何一个最终操作(terminal operation)的时候流就被关闭了

Stream<String> stream =
    Stream.of("d2", "a2", "b1", "b3", "c")
        .filter(s -> s.startsWith("a"));        

stream.anyMatch(s -> true);    // ok
stream.noneMatch(s -> true);   // exception

In the same stream in executing the anyMatch after the implementation of noneMatch will throw the following exception:

java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
    at java.util.stream.ReferencePipeline.noneMatch(ReferencePipeline.java:459)
    at com.winterbe.java8.Streams5.test7(Streams5.java:38)
    at com.winterbe.java8.Streams5.main(Streams5.java:28)
12345

The above problem can be solved reuse by creating a new way for each stream chain final operation (terminal operation), Stream api have been provided in a stream supplierclass basis to build the intermediate operation stream already exists (intermediate operations) on a new stream.

Supplier<Stream<String>> streamSupplier =
    () -> Stream.of("d2", "a2", "b1", "b3", "c")
            .filter(s -> s.startsWith("a"));

streamSupplier.get().anyMatch(s -> true);   // ok
streamSupplier.get().noneMatch(s -> true);  // ok
streamSupplier的每个get()方法会构造一个新的stream,我们可以在这个stream上执行期望的最终操作(terminal operation)。

Some 3.5 Advanced Operations

3.5.1 Collect (collection) operation

The Collect (collection) is a final operation is useful, it can convert the elements stream into another form, such as; list, set, map. Collector Collect used as a parameter, comprising four different operating Collector: supplier (initial constructor), accumulator (accumulator), combiner (combiner), finisher (Terminator). It sounds complicated, but the good news is that java 8 built by Collectors like to collect a variety of complex operations, so for the most common operations, you do not need to go to achieve collector class.

Use Collectors can easily generate List, Set, and Map objects.

List<Person> filtered =
    persons
        .stream()
        .filter(p -> p.name.startsWith("P"))
        .collect(Collectors.toList());

As can be seen from the above demo, the stream is converted into List is very simple, if you want to convert Set, then simply use Collectors.toSet () on it.

3.5.2 FlatMap operation

We already know: You can convert one stream of objects into another object through the map method. However, there are a method using map scene limited only mapping one another specific object existing object. Whether an object can be mapped to a variety of objects, or mapped into an object that does not exist yet. This is the purpose flatMap method appears.

FlatMap method converts each element of the stream object to another object in another element in the stream, it is possible to transform each object in the stream to zero, one or more. flatMap operation returns the object after the stream contains the transformation. '

A Liezi given below:

 String[] words = new String[]{"Hello","World"};
        List<String> a = Arrays.stream(words)
                .map(word -> word.split(""))
                .flatMap(Arrays::stream)
                .distinct()
                .collect(toList());
        a.forEach(System.out::print);

The method of receiving a flatMap Stream type parameter, can be seen from its name, the role of this method is to merge into a plurality Stream Stream (not our granted then generates a Map).

3.5.3 Reduce operation

reduce操作可以将stream中所有元素组合起来得到一个元素, JAVA8 reduce support the three different methods.

  1. Be reduce by a comparison rules
persons
    .stream()
    .reduce((p1, p2) -> p1.age > p2.age ? p1 : p2)
    .ifPresent(System.out::println);
  1. Reduce a second operation identification value received and a binary operator ACC as parameters, this method can reduce the stream of all the user's name and age are summarized to give a new user.
Person result =
persons
.stream()
.reduce(new Person("", 0), (p1, p2) -> {
p1.age += p2.age;
p1.name += p2.name;
return p1;
});

System.out.format("name=%s; age=%s", result.name, result.age);
// name=MaxPeterPamelaDavid; age=76
1234567891011
  1. Reduce the third method, three parameters: a designated value (identity value), a binary operator accumulator (BiFunction accumulator), a binary combination of methods. Since the identifier parameter is not strictly limited to the type of person, so we can use this method to get reduce the overall age of the user.
   Integer ageSum = persons
       .stream()
       .reduce(0, (sum, p) -> sum += p.age, (sum1, sum2) -> sum1 + sum2);

   System.out.println(ageSum);  // 76
   12345

The result of the calculation is 76, by adding debug output, we can understand in detail what is happening execution engine.

   Integer ageSum = persons
       .stream()
       .reduce(0,
           (sum, p) -> {
               System.out.format("accumulator: sum=%s; person=%s\n", sum, p);
               return sum += p.age;
           },
           (sum1, sum2) -> {
               System.out.format("combiner: sum1=%s; sum2=%s\n", sum1, sum2);
               return sum1 + sum2;
           });

   // accumulator: sum=0; person=Max
   // accumulator: sum=18; person=Peter
   // accumulator: sum=41; person=Pamela
   // accumulator: sum=64; person=David
   12345678910111213141516

You can see from the debug output, accumulator did all the work, it first gets the value indicated a value of 0 and a user Max, in the next three-step continuous sum value due to the cumulative increase in size in the last step summary age increased to 76.

Note that the above is not the debug output combiner are performed by the same stream above parallel.

   Integer ageSum = persons
       .parallelStream()
       .reduce(0,
           (sum, p) -> {
               System.out.format("accumulator: sum=%s; person=%s\n", sum, p);
               return sum += p.age;
           },
           (sum1, sum2) -> {
               System.out.format("combiner: sum1=%s; sum2=%s\n", sum1, sum2);
               return sum1 + sum2;
           });

   // accumulator: sum=0; person=Pamela
   // accumulator: sum=0; person=David
   // accumulator: sum=0; person=Max
   // accumulator: sum=0; person=Peter
   // combiner: sum1=18; sum2=23
   // combiner: sum1=23; sum2=12
   // combiner: sum1=41; sum2=35
   12345678910111213141516171819

The above operation executed by the parallel manner stream, is further obtained a completely different action is performed. combiner method is called in a parallel stream in. This is because the accumulator is invoked in parallel, and therefore the need for the combiner summing operation from accumulating.

4. Parallel Stream

In order to improve the efficiency when a large number of inputs, stream may be performed in parallel using release. 并行流(Parallel Streams)通过ForkJoinPool.commonPool() 方法获取一个可用的ForkJoinPool。这个ForkJoinPool使用5个线程(实际上是由底层可用的物理cpu核数决定的).

ForkJoinPool commonPool = ForkJoinPool.commonPool();
System.out.println(commonPool.getParallelism());    // 3
On my machine the common pool is initialized with a parallelism of 3 per default. This value can be decreased or increased by setting the following JVM parameter:
123

On my machine for each default initialization public pool 3 parallel, this value can be modified by adjusting the jvm parameters:

-Djava.util.concurrent.ForkJoinPool.common.parallelism=5
1

Collections中包含parallelStream()方法,通过这个方法能够为Collections中的元素创建并行流。另外也可以调用stream的parallel()方法将一个顺序流转变为一个并行流的拷贝。

In order to understand the operation of the implementation of parallel streams, the following example will print information for the current thread of execution.

Arrays.asList("a1", "a2", "b1", "c2", "c1")
    .parallelStream()
    .filter(s -> {
        System.out.format("filter: %s [%s]\n",
            s, Thread.currentThread().getName());
        return true;
    })
    .map(s -> {
        System.out.format("map: %s [%s]\n",
            s, Thread.currentThread().getName());
        return s.toUpperCase();
    })
    .forEach(s -> System.out.format("forEach: %s [%s]\n",
        s, Thread.currentThread().getName()));
1234567891011121314

Implementation of the results are as follows:

filter:  b1 [main]
filter:  a2 [ForkJoinPool.commonPool-worker-1]
map:     a2 [ForkJoinPool.commonPool-worker-1]
filter:  c2 [ForkJoinPool.commonPool-worker-3]
map:     c2 [ForkJoinPool.commonPool-worker-3]
filter:  c1 [ForkJoinPool.commonPool-worker-2]
map:     c1 [ForkJoinPool.commonPool-worker-2]
forEach: C2 [ForkJoinPool.commonPool-worker-3]
forEach: A2 [ForkJoinPool.commonPool-worker-1]
map:     b1 [main]
forEach: B1 [main]
filter:  a1 [ForkJoinPool.commonPool-worker-3]
map:     a1 [ForkJoinPool.commonPool-worker-3]
forEach: A1 [ForkJoinPool.commonPool-worker-3]
forEach: C1 [ForkJoinPool.commonPool-worker-2]
123456789101112131415

By analyzing debug output, we can better understand what a thread executes what stream operations. From the above output, we can see parallel stream uses all available threads ForkJoinPool provided to perform various operations flow. Since not determine which thread which performs operations in parallel flow, so the above code is repeatedly executed, the result of printing will be different.

Expansion above example, added sort operation

Arrays.asList("a1", "a2", "b1", "c2", "c1")
    .parallelStream()
    .filter(s -> {
        System.out.format("filter: %s [%s]\n",
            s, Thread.currentThread().getName());
        return true;
    })
    .map(s -> {
        System.out.format("map: %s [%s]\n",
            s, Thread.currentThread().getName());
        return s.toUpperCase();
    })
    .sorted((s1, s2) -> {
        System.out.format("sort: %s <> %s [%s]\n",
            s1, s2, Thread.currentThread().getName());
        return s1.compareTo(s2);
    })
    .forEach(s -> System.out.format("forEach: %s [%s]\n",
        s, Thread.currentThread().getName()));
12345678910111213141516171819

Execution results are as follows:

filter:  c2 [ForkJoinPool.commonPool-worker-3]
filter:  c1 [ForkJoinPool.commonPool-worker-2]
map:     c1 [ForkJoinPool.commonPool-worker-2]
filter:  a2 [ForkJoinPool.commonPool-worker-1]
map:     a2 [ForkJoinPool.commonPool-worker-1]
filter:  b1 [main]
map:     b1 [main]
filter:  a1 [ForkJoinPool.commonPool-worker-2]
map:     a1 [ForkJoinPool.commonPool-worker-2]
map:     c2 [ForkJoinPool.commonPool-worker-3]
sort:    A2 <> A1 [main]
sort:    B1 <> A2 [main]
sort:    C2 <> B1 [main]
sort:    C1 <> C2 [main]
sort:    C1 <> B1 [main]
sort:    C1 <> C2 [main]
forEach: A1 [ForkJoinPool.commonPool-worker-1]
forEach: C2 [ForkJoinPool.commonPool-worker-3]
forEach: B1 [main]
forEach: A2 [ForkJoinPool.commonPool-worker-2]
forEach: C1 [ForkJoinPool.commonPool-worker-1]
123456789101112131415161718192021

The results of the implementation looks rather strange looks sort operation just performed sequentially in the main thread. Indeed, sort operation in parallel stream using a new method of JAVA 8: Arrays.parallelSort (). JAVA doc is described in Arrays.parallelSort (): the length of the array to be sorted to determine the sort operation is performed sequentially or in parallel. java doc described as follows:

If the length of the specified array is less than the minimum granularity, then it is sorted using the appropriate Arrays.sort method.
1

Back to the example of the previous chapter, we already know combiner method can only be invoked in parallel streams, let us look at those threads is actually invoked:

List<Person> persons = Arrays.asList(
    new Person("Max", 18),
    new Person("Peter", 23),
    new Person("Pamela", 23),
    new Person("David", 12));

persons
    .parallelStream()
    .reduce(0,
        (sum, p) -> {
            System.out.format("accumulator: sum=%s; person=%s [%s]\n",
                sum, p, Thread.currentThread().getName());
            return sum += p.age;
        },
        (sum1, sum2) -> {
            System.out.format("combiner: sum1=%s; sum2=%s [%s]\n",
                sum1, sum2, Thread.currentThread().getName());
            return sum1 + sum2;
        });
12345678910111213141516171819

Execution results are as follows:

accumulator: sum=0; person=Pamela; [main]
accumulator: sum=0; person=Max;    [ForkJoinPool.commonPool-worker-3]
accumulator: sum=0; person=David;  [ForkJoinPool.commonPool-worker-2]
accumulator: sum=0; person=Peter;  [ForkJoinPool.commonPool-worker-1]
combiner:    sum1=18; sum2=23;     [ForkJoinPool.commonPool-worker-1]
combiner:    sum1=23; sum2=12;     [ForkJoinPool.commonPool-worker-2]
combiner:    sum1=41; sum2=35;     [ForkJoinPool.commonPool-worker-2]
1234567

Can be seen from the console output combiner accumulator and operations are executed in parallel threads are available.

To sum up: When a large amount of data input, parallel streams can bring large performance gains. It should be remembered, however, a number of parallel operations, such as: reduce, collect additional computation required (combined operation), but in the order of the stream, the combination of these operations is not required.

In addition, we know that 所有的parallel stream操作共享一个jvm范围内的ForkJoinPool, so you should be taken to avoid blocking the implementation of a slow stream operations on parallel stream, since these operations may lead to other parts of your applications rely on parallel streams will be slow response operations.

5. Detailed Liezi

package com.csx.demo.spring.boot.lambda;

import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.*;

public class LambdaStreamDemo {

    public static void main(String[] args) {

        List<Person> javaProgrammers = new ArrayList<Person>() {
            {
                add(new Person("Elsdon", "Jaycob", "Java programmer", "male", 43, 2000));
                add(new Person("Tamsen", "Brittany", "Java programmer", "female", 23, 1500));
                add(new Person("Floyd", "Donny", "Java programmer", "male", 33, 1800));
                add(new Person("Sindy", "Jonie", "Java programmer", "female", 32, 1600));
                add(new Person("Vere", "Hervey", "Java programmer", "male", 22, 1200));
                add(new Person("Maude", "Jaimie", "Java programmer", "female", 27, 1900));
                add(new Person("Shawn", "Randall", "Java programmer", "male", 30, 2300));
                add(new Person("Jayden", "Corrina", "Java programmer", "female", 35, 1700));
                add(new Person("Palmer", "Dene", "Java programmer", "male", 33, 2000));
                add(new Person("Addison", "Pam", "Java programmer", "female", 34, 1300));
            }
        };

        List<Person> phpProgrammers = new ArrayList<Person>() {
            {
                add(new Person("Jarrod", "Pace", "PHP programmer", "male", 34, 1550));
                add(new Person("Clarette", "Cicely", "PHP programmer", "female", 23, 1200));
                add(new Person("Victor", "Channing", "PHP programmer", "male", 32, 1600));
                add(new Person("Tori", "Sheryl", "PHP programmer", "female", 21, 1000));
                add(new Person("Osborne", "Shad", "PHP programmer", "male", 32, 1100));
                add(new Person("Rosalind", "Layla", "PHP programmer", "female", 25, 1300));
                add(new Person("Fraser", "Hewie", "PHP programmer", "male", 36, 1100));
                add(new Person("Quinn", "Tamara", "PHP programmer", "female", 21, 1000));
                add(new Person("Alvin", "Lance", "PHP programmer", "male", 38, 1600));
                add(new Person("Evonne", "Shari", "PHP programmer", "female", 40, 1800));
            }
        };

        //----------------------forEach使用----------------------
        //所有程序员的姓名
        //forEach方法接收一个Consumer参数,来遍历处理每个对象
        System.out.println("---------------------forEach使用--------------------------");
        System.out.println("java programmer:");
        javaProgrammers.forEach((person) -> {
            System.out.println(person.getFirstName() + "." + person.getLastName());
        });
        System.out.println("php programmer:");
        phpProgrammers.forEach((person) -> {
            System.out.println(person.getFirstName() + "." + person.getLastName());
        });
        //给所有程序员的薪水上涨5%
        System.out.println("给程序员加薪 5% :");
        Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary());
        javaProgrammers.forEach(giveRaise);
        phpProgrammers.forEach(giveRaise);

        //-----------------------filter使用---------------------
        //过滤器的使用
        //显示月薪超所1400美元的php程序员
        System.out.println("---------------------filter使用--------------------------");
        System.out.println("显示月薪超过1400的php程序员:");
        phpProgrammers.stream()
                .filter(p -> p.getSalary() > 1400)
                .forEach(person -> System.out.println(person.getFirstName() + "." + person.getLastName()));
        //定义filters,这些定义的Filter可以重用
        Predicate<Person> ageFilter = (p) -> (p.getAge() > 25);
        Predicate<Person> salaryFilter = (p) -> (p.getSalary() > 1400);
        Predicate<Person> genderFilter = (p) -> ("female".equals(p.getGender()));
        System.out.println("下面是年龄大于24岁且月薪在$1,400以上的女PHP程序员:");
        phpProgrammers.stream()
                .filter(ageFilter)
                .filter(salaryFilter)
                .filter(genderFilter)
                .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
        //重用filters
        System.out.println("下面是年龄大于24岁的女性 Java programmers:");
        javaProgrammers.stream()
                .filter(ageFilter)
                .filter(genderFilter)
                .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
        //-----------------------------map的使用---------------------------------
        System.out.println("---------------------map的使用--------------------------");
        System.out.println("将 PHP programmers 的 first name 拼接成字符串:");
        String phpDevelopers = phpProgrammers
                .stream()
                .map(Person::getFirstName)
                .collect(joining(" ; "));

        System.out.println("将 Java programmers 的 first name 存放到 Set:");
        Set<String> javaDevFirstName = javaProgrammers
                .stream()
                .map(Person::getFirstName)
                .collect(toSet());

        System.out.println("将 Java programmers 的 first name 存放到 TreeSet:");
        TreeSet<String> javaDevLastName = javaProgrammers
                .stream()
                .map(Person::getLastName)
                .collect(toCollection(TreeSet::new));
        //------------------------------limit使用--------------------------------------
        System.out.println("---------------------limit使用使用--------------------------");
        System.out.println("最前面的3个Java programmers:");
        javaProgrammers.stream()
                .limit(3)
                .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
        System.out.println("最前面的3个女性 Java programmers:");
        javaProgrammers.stream()
                .filter(genderFilter)
                .limit(3)
                .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
        //------------------------------sort排序使用---------------------------------------
        System.out.println("---------------------sort排序使用--------------------------");
        System.out.println("根据name排序,并显示前5个 Java programmers:");
        List<Person> sortedJavaProgrammers = javaProgrammers
                .stream()
                .sorted(Comparator.comparing(Person::getFirstName))
                .limit(5)
                .collect(toList());
        sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
        //------------------------------max和min方法的使用-------------------------------
        System.out.println("---------------------max和min方法使用--------------------------");
        System.out.println("工资最低的 Java programmer:");
        Person pears = javaProgrammers
                .stream()
                .min(Comparator.comparingInt(Person::getSalary))
                .get();
        System.out.printf("Name: %s %s; Salary: $%,d.", pears.getFirstName(), pears.getLastName(), pears.getSalary());

        System.out.println("工资最高的 Java programmer:");
        Person person = javaProgrammers
                .stream()
                .max(Comparator.comparingInt(Person::getSalary))
                .get();
        System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary());

        //-------------------------Stream的一些高级用法------------------------
        System.out.println("---------------------Stream的一些高级用法--------------------");
        System.out.println("---------------------Collect的用法--------------------");

        System.out.println("---------------------将Stream转为List--------------------");
        List<Person> list = javaProgrammers.stream()
                .filter(p -> p.getSalary() > 1000)
                .collect(Collectors.toList());

        System.out.println("---------------------将Stream转为Set--------------------");
        Set<Person> set = javaProgrammers.stream()
                .filter(p -> p.getSalary() > 1000)
                .collect(Collectors.toSet());

        System.out.println("---------------------将Stream转为(线程非安全)Map--------------------");
        System.out.println("---------------------将Java程序员按照性别不同分组--------------------");
        Map<String, List<Person>> listMap = javaProgrammers.stream()
                .filter(p -> p.getSalary() > 1000)
                .collect(groupingBy(Person::getGender));
        System.out.println("---------------------将Stream转为(线程安全)Map--------------------");
        System.out.println("---------------------将Java程序员按照性别不同分组--------------------");
        ConcurrentMap<String, List<Person>> listConcurrentMap = javaProgrammers.stream()
                .filter(p -> p.getSalary() > 1000)
                .collect(groupingByConcurrent(Person::getGender));
        //将一个stream转换为map,我们必须指定map的key和value如何映射。要注意的是key的值必须是唯一性的,
        // 否则会抛出IllegalStateException,但是可以通过使用合并函数(可选)绕过这个IllegalStateException异常:

        //将age作为key,firstName作为value,如果遇到age相同,则将两个age相同的Person的FirstName相加作为Value
        Map<Integer, String> integerStringMap = javaProgrammers.stream()
                .collect(toMap(
                        p -> p.getAge(),
                        p -> p.getFirstName(),
                        (value1, value2) -> value1 + value2
                ));

        System.out.println("--------------------计算平均值--------------------");
        Double avAge = javaProgrammers.stream()
                .collect(averagingInt(p -> p.getAge()));
        System.out.println("java程序员平均年龄:"+avAge);

        System.out.println("--------------------获取Java程序员age的统计信息--------------------");
        System.out.println("-------------包括年龄最大值,最小值和平均值等----------------");
        IntSummaryStatistics collect = javaProgrammers.stream()
                .collect(summarizingInt(p -> p.getAge()));

        System.out.println("--------------------获取Java程序员的FirstName进行拼接--------------------");
        String s = javaProgrammers.stream()
                .map(p -> p.getFirstName())
                .collect(joining("and", "preFix", "endFix"));

        //也可以通过Collector.of()方法创建了一个自定义的collector,我们必须给这个collector提供四种功能:
        // supplier, accumulator, combiner,finisher.
        System.out.println("-------------------可以自定义collector--------------------");

        //-------------------flatMap的使用----------------------
        System.out.println("-------------------flatMap的使用----------------------");
        String[] words = new String[]{"Hello","World"};
        List<String> a = Arrays.stream(words)
                .map(word -> word.split(""))
                .flatMap(Arrays::stream)
                .distinct()
                .collect(toList());
        a.forEach(System.out::print);

        //------------------reduce的使用-----------------
        System.out.println("-------------------reduce的使用----------------------");
        javaProgrammers.stream()
                .reduce((p1,p2)->p1.getAge()>p2.getAge()?p1:p2)
                .ifPresent(System.out::println);
        //这个方法直接返回的是Person,将所有Java程序员的年龄相加起来,在set到传进去的Person中
        Person reduce = javaProgrammers.stream()
                .reduce(new Person("", "", "", "", 10, 0), (p1, p2) -> {
                    p1.setAge(p1.getAge() + p2.getAge());
                    p1.setFirstName(p1.getFirstName() + p2.getFirstName());
                    return p1;
                });
        System.out.println(reduce);
        //这个方法返回一个标量值,注意,这种方式中第三个参数是不会被执行的,只有当并行模式下,第三个参数才会被执行
        Integer ageSum = javaProgrammers
                .stream()
                .reduce(0,
                        (sum, p) -> {
                            System.out.format("accumulator: sum=%s; person=%s\n", sum, p.getFirstName());
                            return sum += p.getAge();
                        },
                        (sum1, sum2) -> {
                            System.out.format("combiner: sum1=%s; sum2=%s\n", sum1, sum2);
                            return sum1 + sum2;
                        });
        System.out.println(ageSum);
        //--------------------------------Streams 还可以是并行的(parallel)-------------
        ForkJoinPool commonPool = ForkJoinPool.commonPool();
        System.out.println(commonPool.getParallelism());

    }
}

6. A brief summary

  • Can (List, Set, and Map, etc.) will be the method of stream Stream, Stream can be obtained by methods Stream.of collection object, you can also be obtained by IntStream.range Stream method;
  • Stream operation into the middle of the operation and the final operation, intermediate operation returns a Stream, Stream final operation will be shut down, only to perform the operation will trigger the final intermediate operations; Stream API that does not alter the original data
  • Appropriate adjustments can improve the efficiency of execution order
  • Supplier can be multiplexed Stream.

7. References

  • https://blog.csdn.net/m0_37556444/article/details/84975355

  • https://ifeve.com/stream/

Guess you like

Origin www.cnblogs.com/54chensongxia/p/12449920.html