introduce
JDK 8 not only added Lambda expressions, but also Stream streams, which programmers use to simplify handling of data. The essence of this is calculation.
A stream is a data channel that manipulates a sequence of elements generated by a data source.
Let’s get familiar with the Stream:
public class StringSorting {
public static void main(String[] args) {
Stream.of("Java"."Python"."C++"."C"."Shell"."Ruby"."Scala"."Groovy"."Kotlin"."Clojure"."Jython"."C#"."JavaScript"."SQL")
.sorted() // Natural sort
.forEach(s -> System.out.printf("%s ", s)); // Print the output}}Copy the code
Output result:
C C# C++ Clojure Groovy Java JavaScript Jython Kotlin Python Ruby SQL Scala Shell
Copy the code
From the above example, we can see the steps to use Stream:
- Create a flow. Like the one above
Stream.of()
- Intermediate operation of convection. Like the one above
sorted()
To sort the data in the stream. - Final operation. Like the one above
forEach()
, will be circulated through the method for printing.
Flow to create
Streams can be created in the following ways:
There are several ways to create a Stream:
Arrays
Provided by the array utility classstream()
Static method.Stream
In the classof()
,generate()
,iterate()
andempty()
Static method.Stream
In the classbuilder()
Methods.Collection
Pool-providedstream()
The methods andparallelStream()
Methods.
There are other ways of generating streams that are not listed. Here’s how to create a Stream above
Arrays.stream() static method
Here are the stream() and overload methods of Arrays:
public class Arrays {... Omit...public static <T> Stream<T> stream(T[] array) {... }public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {... }public static IntStream stream(int[] array) {... }public static IntStream stream(int[] array, int startInclusive, int endExclusive) {... }public static LongStream stream(long[] array) {... }public static LongStream stream(long[] array, int startInclusive, int endExclusive) {... }public static DoubleStream stream(double[] array) {... }public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {... }... Omit... }Copy the code
As we can see from the above method, by overloading the form, we can convert an array of primitive types and generics we call into a Stream.
Here’s an example of using arrays.stream () to convert an array to a stream:
public class ArraysStream {
public static void main(String[] args) {
Arrays.stream(new double[] {3.1415926.9.8.3.3333}) .forEach(System.out::println); }}Copy the code
Static method of Stream
A Stream has three static methods: of(), generate(), and iterate().
We’ll look at the source of the stream.of () static method:
public interface Stream<T> extends BaseStream<T.Stream<T>> {... Omit...@SafeVarargs
@SuppressWarnings("varargs") // Creating a stream from an array is safe
public static<T> Stream<T> of(T... values) {
returnArrays.stream(values); }... Omit... }Copy the code
Using the stream.of () static method converts mutable elements to the Stream () static method of the Array.stream () utility class.
Let’s look at an example of using stream.of () to convert an array of mutable arguments to a Stream:
public class StreamOf {
public static void main(String[] args) {
// Convert a set of numbers to a stream
Stream.of(9.8.3.1415926.3.33333) .forEach(System.out::println); }}Copy the code
The source code and examples for the stream.of () static method are described above. ,
Stream also has a static method for generating streams that generate infinite elements: generate() static method: generate()
public interface Stream<T> extends BaseStream<T.Stream<T>> {... Omit...public static<T> Stream<T> generate(Supplier<? extends T> s) {... }... Omit... }Copy the code
The stream created using the generate() method is infinite in length and takes the Supplier function interface as an argument.
public class StreamGenerate {
public static void main(String[] args) {
Stream.generate(Math::random)
.limit(10)
.forEach(i -> System.out.printf("%f ", i)); }}Copy the code
Output result:
0.792192 0.625073 0.983115 0.372405 0.294238 0.790635 0.688823 0.238186 0.096708 0.434963
Copy the code
We’re looking at another static method for creating an infinite Stream, stream.iterate () :
public interface Stream<T> extends BaseStream<T.Stream<T>> {... Omit...public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {... }public static<T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) {}... Omit... }Copy the code
Both of the above static methods are used to create an infinite Stream, as opposed to the generate method, which produces an infinitely continuous and ordered Stream by iterating over a specified seed through the function f.
public class StreamIterate {
int x = 1;
Stream<Integer> numbers(a) {
return Stream.iterate(0, i -> {
int result = x + i;
x = i;
return result;
});
}
public static void main(String[] args) {
new StreamIterate().numbers()
.skip(20) // Filter the first 20
.limit(10) // Then take 10
.forEach(i -> System.out.printf("%d ", i)); }}Copy the code
Output result:
6765 10946 17711 28657 46368 75025 121393 196418 317811 514229
Copy the code
There is also a Stream class that creates a Stream without any elements:
public interface Stream<T> extends BaseStream<T.Stream<T>> {... Omit...public static<T> Stream<T> empty(a) {... }... Omit... }Copy the code
An example of creating an empty stream is as follows:
public class StreamEmpty {
public static void main(String[] args) { Stream<Object> empty = Stream.empty(); }}Copy the code
Constructor pattern for Stream
The Stream class can also create streams using the builder Builder () method.
public class StreamBuilder {
public static void main(String[] args) {
Stream.builder()
.add("Jan").add("Feb").add("Mar")
.add("Apr").add("May").add("Jun")
.build()
.forEach(s -> System.out.printf("%s ", s)); }}Copy the code
Output result:
Jan Feb Mar Apr May Jun
Copy the code
The Collection series
In Java 8, we extended the Collection interface to add two default methods to create streams:
public interface Collection<E> extends 可迭代<E> {... Omit...default Stream<E> stream(a) {... }default Stream<E> parallelStream(a) {...}
}
Copy the code
The two default methods above, stream(), are converted to a sequential stream and paralletlStream() to a parallel stream.
Let’s look at two examples of default methods in use:
public class ListStream {
public static void main(String[] args) {
String[] months = {"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"."Jun"."Jun"."Feb"."Jan"};
// Set creation
List<String> list = Arrays.asList(months);
list.stream().forEach(s -> System.out.format("%s ", s)); }}Copy the code
Output result:
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Copy the code
But after converting the stream() method of the List object to parallelStream(),
Output result:
Aug Jul Jun Feb Dec Oct Nov Apr Mar May Jan Sep
Copy the code
ParallelStream () = parallelStream() = parallelStream()
Stream () is converted to a sequential stream, which uses the main thread and is single-threaded; ParallelStream () is converted to parallel streams, which are run by multiple threads at the same time. Thus, stream() outputs sequentially, while parallelStream() does not.
So how do we convert a Map relational mapping table into a stream?
Look at the following example:
public class MapStream {
public static void main(String[] args) {
Map<String, Integer> users = new HashMap<>();
users.put("Xiao zhao.".18);
users.put("Money".29);
users.put("Note".20);
users.put("Xiao li".29);
users.entrySet().stream().forEach(entry -> System.out.format("%s ", entry));
System.out.println();
users.keySet().stream().forEach(key -> System.out.format("%s ", key));
System.out.println();
users.values().stream().forEach(value -> System.out.format("%d ", value)); }}Copy the code
Output result:
Sun =20 Li =29 Qian =29 Zhao =18 Sun =29 Li xiao Qian zhao 20 29 29 18Copy the code
As can be seen from the above example, we get the Entity set, Key set and Value set of Map and convert them into streams for processing.
In the middle of operation
The intermediate operation is to process the stream created above and return the stream again for the convenience of other operations.
Let’s take a look at the intermediate operations: peek(), sorted(), unordered(), distinct(), filter(), map(), flatMap(), limit(), skip(), etc. Let’s go through these operations in detail.
peek
Peek operates as follows:
Stream<T> peek(Consumer<? super T> action);
Copy the code
The main purpose is to receive logic provided by a Consumer function to operate on elements in the flow.
The peek() operation is intended to aid debugging. It allows you to view elements in a stream without modification. Code examples:
public class Peeking {
public static void main(String[] args) {
Stream.of("Hello"."Hello World!"."I'm hello") .peek(System.out::println) .collect(Collectors.toList()); }}Copy the code
Output result:
Hello
Hello World!
I'm hello
Copy the code
Let’s look at another example:
public class Peeking {
public static void main(String[] args) {
List<String> list = Stream.of("Hello"."Hello World!"."I'm hello")
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(list);
list = Stream.of("Hello"."Hello World!"."I'm hello") .peek(String::toUpperCase) .collect(Collectors.toList()); System.out.println(list); }}Copy the code
Output result:
[HELLO, HELLO WORLD!, I'M HELLO]
[Hello, Hello World!, I'm hello]
Copy the code
You can see that the map() operation transforms the element, but peek() does not.
Thus, peek() is generally used when you don’t want to change the type of the element itself in the flow or when you just want to manipulate the internal state of the element; Map (), on the other hand, is used to change the type of the element itself in the stream, that is, to derive another type from the element.
Peek () is suitable for batching certain properties of generics in Stream
.
sorted
The sorted operation is as follows:
Stream<T> sorted(a);
/ / or
Stream<T> sorted(Comparator<? super T> comparator);
Copy the code
Sorted () can either use a no-argument method or pass in the Comparator argument. Code examples:
public class SortedComparator {
public static void main(String[] args) throws Exception {
FileToWords.stream("Cheese.dat")
.skip(10)
.limit(10)
.sorted(Comparator.reverseOrder())
.map(w -> w + "") .forEach(System.out::print); }}Copy the code
Output result:
you what to the that sir leads in district And
Copy the code
Sorted () presets some default comparators. Here we use reverse “natural ordering”. Of course you can also pass a Lambda function to sorted() as an argument.
distinct
Distinct methods are as follows:
Stream<T> distinct(a);
Copy the code
Its main function is to reduce weight:
public class DistinctOperator {
public static void main(String[] args) {
Stream.of(45.31.21.98.31.55.982.45.54)
.distinct().forEach(n -> System.out.format("%d ", n)); }}Copy the code
Output result:
45 31 21 98 55 982 54
Copy the code
filter
The method of filter is as follows:
Stream<T> filter(Predicate<? super T> predicate);
Copy the code
This method is a filtering operation that filters out the unwanted data and keeps the desired data. The data that does not meet the requirements of the Predicate function is filtered out, leaving the data that does meet the requirements of the Predicate function.
Let’s look at the following example to familiarize ourselves with the filter() method:
class Month {
private String name;
private int id;
public Month(String name, int id) { this.name = name;this.id = id; }
public String getName(a) { return name; }
public void setName(String name) { this.name = name; }
public int getId(a) { return id; }
public void setId(int id) { this.id = id; }
@Override
public String toString(a) {
return "Month{" + "name='" + name + '\' ' + ", id=" + id + '} '; }}public class FilterOperator {
public static void main(String[] args) {
String[] strings = new String[]{"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"};
Month[] months = new Month[strings.length];
for (int i = 0; i < strings.length; i++) {
months[i] = new Month(strings[i], i+1);
}
Stream.of(months)
.filter(s -> "J".equals(s.getName().substring(0.1))) .forEach(System.out::println); }}Copy the code
Output result:
Month{name='Jan', id=1}
Month{name='Jun', id=6}
Month{name='Jul', id=7}
Copy the code
As you can see from the result, all objects with an initial equal to J are printed out.
map
The map method is as follows:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
Copy the code
It receives a Function Function that converts an object of one type to an object of another type.
Let’s write an example to see how it works:
class Student {
private String name;
private int age;
public Student(String name, int age) { this.name = name;this.age = age; }
public String getName(a) { return name; }
public void setName(String name) { this.name = name; }
public int getAge(a) { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString(a) {
return "Student{" + "name='" + name + '\' ' + ", age=" + age + '} '; }}public class MapOperator {
public static void main(String[] args) {
String[] strings = new String[]{"Xiao zhao."."Money"."Note"."Xiao li"."Chou"."Xiao wu"."Zheng"."Wang"};
int[] ints = new int[] {20 , 18.31.28.20.25.31.20};
Student[] students = new Student[strings.length];
for (int i = 0; i < strings.length; i++) {
students[i] = new Student(strings[i], ints[i]);
}
Stream.of(students).map(Student::getName).forEach(s -> System.out.printf("%s ", s));
System.out.println();
Stream.of(students).mapToInt(Student::getAge).forEach(i -> System.out.printf("%d ", i)); System.out.println(); }}Copy the code
Output result:
Xiao Zhao, Xiao Qian, Xiao Sun, Xiao Li, Xiao Zhou, Xiao Wu, Xiao Zheng, Xiao Wang 20 18 31 28 20 25 31 20Copy the code
As you can see from the above example, the first output is to get the names of all the students from the Student object array and print them, and the second output is to print the ages.
MapToInt (IntStream, IntStream); mapToInt (IntStream, IntStream);
// According to 'ToIntFunction' function, get 'IntStream'
IntStream mapToInt(ToIntFunction<? super T> mapper);
// Get the 'LongStream' stream according to the 'ToLongFunction' function
LongStream mapToLong(ToLongFunction<? super T> mapper);
// According to 'ToDoubleFunction', get 'DoubleStream'
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
Copy the code
flatMap
The method of flatMap is as follows:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Copy the code
This method takes a Function Function as an argument, converts each value in the stream to another stream, and then concatenates all streams into a single stream, a flattening operation.
Example:
class Employee {
private int id;
private String name;
private double salary;
public Employee(int id, String name, double salary) { this.id = id;this.name = name;this.salary = salary; }
public int getId(a) { return id; }
public void setId(int id) { this.id = id; }
public String getName(a) { return name; }
public void setName(String name) { this.name = name; }
public double getSalary(a) { return salary; }
public void setSalary(double salary) { this.salary = salary; }
@Override
public String toString(a) {
return "Employee{" + "id=" + id + ", name='" + name + '\' ' + ", salary=" + salary + '} '; }}public class FlatMapOperator {
public static void main(String[] args) {
Employee[] employees1 = new Employee[] {
new Employee(1."Xiao zhao.".1500),
new Employee(2."Money".3500),
new Employee(3."Note".500),
new Employee(4."Xiao li".4500),}; Employee[] employees2 =new Employee[] {
new Employee(5."Chou".9000),
new Employee(6."Xiao wu".6200),
new Employee(7."Zheng".1850),
new Employee(8."Wang".3210),}; Stream.of(employees1, employees2).flatMap(e -> Arrays.stream(e)).forEach(System.out::println); }}Copy the code
Output result:
Employee{id=1, name=' xiao ', salary=1500.0} Employee{id=2, name=' xiao ', salary=3500.0} Employee{id=2, name=' xiao ', salary=3500.0} Salary =500.0} Employee{id=4, name=' xiao Li ', salary=500.0} Employee{id=5, name=' xiao zhou ', salary=500.0} Employee{id=5, name=' xiao Zhou ', salary=500.0} Employee{id=5, name=' xiao Zhou ', salary=500.0} Employee{id=5, name=' xiao Zhou ', salary=500.0} Employee{id= 5, name=' xiaowang ', salary=6200.0} Employee{id= 5, name=' xiaowang ', salary=6200.0}Copy the code
As a result, flatMap() converts the two arrays into a stream and merges them together.
FlatMap () also has a specific type of method wrapped in the source code as follows:
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
Copy the code
limit
Limit:
Stream<T> limit(long maxSize);
Copy the code
It intercepts the stream based on the size of the maxSize parameter, so that the number of elements does not exceed maxSize.
Let’s give an example to get familiar with the use of limit() :
public class LimitOperator {
public static void main(String[] args) {
String[] strings = new String[]{"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"};
Stream.of(strings).limit(5).forEach(s -> System.out.printf("%s ", s)); }}Copy the code
Output result:
Jan Feb Mar Apr May
Copy the code
skip
Skip’s method is as follows:
Stream<T> skip(long n);
Copy the code
Skip the element and return a stream with the first n elements thrown away. If there are less than n elements in the stream, an empty stream is returned. Complementary to limit.
public class SkipOperator {
public static void main(String[] args) {
String[] strings = new String[]{"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"};
Stream.of(strings).skip(10).forEach(s -> System.out.printf("%s ", s)); }}Copy the code
Output result:
Nov Dec
Copy the code
Terminal operation
A terminal operation is intended to terminate an intermediate operation of a stream and return a result. No further flow can be passed at this point.
What are terminal operations? Let’s take a quick look: ForEach (), forEachOrdered(), toArray(), collect(), reduce(), min(), Max (), count(), anyMatch(), allMatch(), noneMatch(), findFirst() ), findAny(), etc. The following details the use of these terminal operations.
forEach
ForEach’s method is as follows:
void forEach(Consumer<? super T> action);
Copy the code
Basically compiling, we pass in a Consumer function, and Stream iterates internally.
public class ForEachOperator {
public static void main(String[] args) {
String[] strings = new String[]{"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"};
Stream.of(strings).forEach(s -> System.out.printf("%s ", s)); }}Copy the code
forEachOrdered
ForEachOrdered method is as follows:
void forEachOrdered(Consumer<? super T> action);
Copy the code
It does the same thing as forEach(), but is different on parallel streams
public class ForEachOrderedOperator {
public static void main(String[] args) {
String[] strings = new String[]{"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"};
Stream.of(strings).parallel().forEach(s -> System.out.printf("%s ", s));
System.out.println();
Stream.of(strings).parallel().forEachOrdered(s -> System.out.printf("%s ", s)); }}Copy the code
Output result:
Aug May Dec Oct Jun Feb Apr Nov Mar Jan Jul Sep
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Copy the code
As you can see from the output, forEachOrdered() outputs strictly sequentially when working with parallel streams, while forEach() does not.
toArray
The toArray method is as follows:
Object[] toArray();
<A> A[] toArray(IntFunction<A[]> generator);
Copy the code
ToArray has two methods, one with no arguments and one passed in
Let’s give an example to get used to using the toArray() method:
public class ToArrayOperator {
public static void main(String[] args) {
List<String> strings = Arrays.asList("Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec");
// Use toArray() to turn the stream into an array
Object[] objects = strings.stream()
.filter(s -> "J".equals(s.substring(0.1))).toArray();
System.out.println(Arrays.toString(objects));
// Use toArray() to convert the stream to a specific array
String[] strings1 = strings.stream()
.filter(s -> "A".equals(s.substring(0.1))).toArray(size -> {
return new String[size];
});
System.out.println(Arrays.toString(strings1));
// The above notation can be used as a method reference
String[] strings3 = strings.stream()
.filter(s -> "M".equals(s.substring(0.1))).toArray(String[]::new); System.out.println(Arrays.toString(strings3)); }}Copy the code
Output result:
[Jan, Jun, Jul]
[Apr, Aug]
[Mar, May]
Copy the code
From the results, we know that the toArray() method simply converts a stream to an array.
collect
The method of collect is as follows:
<R, A> R collect(Collector<? super T, A, R> collector);
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
Copy the code
Collect is a collection operation. It is converted into other commonly used data structures and collected through streams, such as lists, maps, and so on.
From the above source code, it can be seen that the collect method has two methods.
The first method can be seen from the parameters of the receiving, collect method is through the Java. The util. Stream. The Collector class to collect the flow element to the result set.
public class CollectOperator {
public static void main(String[] args) {
List<String> months1 = Stream.of("Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"."Jun"."Jun"."Feb"."Jan")
.filter(s -> "J".equals(s.substring(0.1))) .collect(Collectors.toList()); System.out.println(months1); }}Copy the code
Output result:
[Jan, Jun, Jul, Jun, Jun, Jan]
Copy the code
As can be seen from the result, we filter out the string whose initial letter is not J through filter, and convert it into List through collect for collection. However, there are repeated elements in the collection, so we convert them into Set for collection.
public class CollectOperator {
public static void main(String[] args) {
Set<String> months = Stream.of("Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"."Jun"."Jun"."Feb"."Jan")
.filter(s -> "J".equals(s.substring(0.1))) .collect(Collectors.toSet()); System.out.println(months); }}Copy the code
Output result:
[Jul, Jun, Jan]
Copy the code
The output is not ordered, and to keep the elements in order, we store them in TreeSet. Collectors do not have toTreeSet(). Therefore, we use Collectors. ToCollection (Supplier
collectionFactory) to build the required collection type.
Stream.of("Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"."Jun"."Jun"."Feb"."Jan")
.filter(s -> "J".equals(s.substring(0.1)))
.collect(Collectors.toCollection(TreeSet::new));
Copy the code
Output result:
[Jan, Jul, Jun]
Copy the code
Collect can also generate maps. The code is as follows:
class Pair {
private final Character c;
private final Integer i;
Pair(Character c) { this.c = c;this.i = (int) c; }
public Character getC(a) { return c; }
public Integer getI(a) { return i; }
@Override
public String toString(a) { return "Pair{" + "c=" + c + ", i=" + i + '} '; }}public class CollectOperator {
public static void main(String[] args) {
Map<Character, Integer> charTables = Stream.of('c'.'a'.'z'.'o'.'y')
.map(c -> newPair(c)).collect(Collectors.toMap(Pair::getC, Pair::getI)); System.out.println(charTables.toString()); }}Copy the code
Output result:
{a=97, c=99, y=121, z=122, o=111}
Copy the code
For the second method, the Supplier parameter is a method that generates an instance of the target type, representing an object of the storage type; BiConsumer
Accumulator parameter is a method of populating the operation target data into an instance of the target type generated by the Supplier. It represents how the element is added to the container. The BiConsumer
combiner is a way to combine multiple instances generated by any Supplier, representing a protocol operation that combines multiple results.
Here is a simple example, counting the frequency of the month:
public class CollectOperator {
public static void main(String[] args) {
Map<String, Integer> wordCount = Stream.of("Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"."Jun"."Jun"."Feb"."Jan")
.collect(TreeMap::new,
(map, word) ->
map.merge(word, 1, Integer::sum), Map::putAll); System.out.println(wordCount); }}Copy the code
Output result:
{Apr=1, Aug=1, Dec=1, Feb=2, Jan=2, Jul=1, Jun=3, Mar=1, May=1, Nov=1, Oct=1, Sep=1}
Copy the code
reduce
The reduce method is as follows:
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);
Copy the code
Reduce combines the elements of an input sequence into a single summary by repeatedly performing some combination operation (summing, maximizing, or putting all the elements into a list).
public class ReduceOperator {
public static void main(String[] args) {
String concat = Stream.of("Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec")
.filter(s -> "J".equals(s.substring(0.1)))
.reduce("", (a, b) -> {
if (!"".equals(a)) {
return a + "," + b;
}
returnb; }); System.out.println(concat); }}Copy the code
Output result:
Jan,Jun,Jul
Copy the code
Min, Max, count
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
long count(a);
Copy the code
The function of count is to find the number of elements in the stream.
The role of min is to find the “smallest” element based on the passed Comparator.
Max is used to find the “smallest” element based on the incoming Comparator.
Both of them rely on Reduce implementation at the bottom.
Now look at the sample code:
public class InfoReduceOperator {
public static void main(String[] args) {
String[] months = {"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"};
long count = Stream.of(months)
.filter(s -> "J".equals(s.substring(0.1)))
.count();
System.out.printf("Calculate the number of strings starting with 'J' : %d",count);
System.out.println();
String min = Stream.of(months).min(Comparator.comparing(Function.identity())).get();
System.out.printf("The smallest string in the string array is: %s", min);
System.out.println();
String max = Stream.of(months).max(String::compareTo).get();
System.out.printf("The largest string in the string array is: %s", max); }}Copy the code
Output result:
Counting the number of strings starting with 'J' is: the smallest string in the 3-string array is: Apr the largest string in the string array is: SepCopy the code
match
Match is a match operation that has three methods: anyMatch, allMatch, and noneMatch.
AnyMatch is used to check that at least one of all elements is a match. Its method is as follows:
boolean anyMatch(Predicate<? super T> predicate);
Copy the code
AllMatch is used to check whether all elements match. The method is as follows:
boolean allMatch(Predicate<? super T> predicate);
Copy the code
NoneMatch is used to check that none of the elements match. The method is as follows:
boolean noneMatch(Predicate<? super T> predicate);
Copy the code
Let’s look at an example of the above method:
public class MatchOperator {
public static void main(String[] args) {
String[] months = {"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"};
boolean isAnyMatch = Stream.of(months).anyMatch(s -> "A".equals(s.substring(0.1)));
System.out.printf("Determine if there is' A ': %s' in the months array",isAnyMatch);
System.out.println();
boolean isAllMath = Stream.of(months).allMatch(s -> "A".equals(s.substring(0.1)));
System.out.printf(Determine if all elements in the months array start with 'A' : %s', isAllMath);
System.out.println();
boolean isNoneMath = Stream.of(months).noneMatch(s -> "A".equals(s.substring(0.1)));
System.out.printf("Check whether the first letter in the months array is not 'A' : %s", isNoneMath); }}Copy the code
Output result:
Check whether the months array starts with 'A' : true Check whether all elements in the months array start with 'A' : false Check whether the months array does not start with 'A' : falseCopy the code
find
Find is a lookup operation that has three methods: findFirst and findAny.
FindFirst returns the first element in the current stream. The method is as follows:
Optional<T> findFirst(a);
Copy the code
FindAny returns any element in the current stream. The method is as follows:
Optional<T> findAny(a);
Copy the code
Here’s how to use them:
public class FindOperator {
public static void main(String[] args) {
String[] months = {"Jan"."Feb"."Mar"."Apr"."May"."Jun"."Jul"."Aug"."Sep"."Oct"."Nov"."Dec"};
String first = Stream.of(months).parallel()
.filter(s -> "J".equals(s.substring(0.1)))
.findFirst().get();
System.out.printf("Get the first element in the stream: %s", first);
System.out.println();
String any = Stream.of(months).parallel()
.filter(s -> "M".equals(s.substring(0.1)))
.findAny().get();
System.out.printf("Get any element in the stream: %s", any); }}Copy the code
Output result:
Gets the first element in the stream: Jan Gets any element in the stream: MarCopy the code
FindFirst () always selects the first element in a stream, whether or not it is parallelized.
For non-parallel streams, findAny() selects the first element in the stream. FindAny (), however, was able to select any element when we parallelized it using parallel().
If you must select the last element in the stream, use reduce().
String last = Stream.of(months).parallel()
.filter(s -> "J".equals(s.substring(0.1)))
.reduce((v1, v2) -> v2).get();
Copy the code
The reduce() argument simply replaces the last two elements with the last one, resulting in only the last element being generated.
summary
Using A Stream Stream is a huge improvement over Java, it makes writing code look simpler and more elegant, and the parallelism of Stream streams takes advantage of the multicore era.
We are looking forward to your attention on the public account “Hai Ren Ji”.
Reply “Resources” to get free learning resources!