JAVA8 Stream series of operations -- java

Keywords: Java Back-end

Java cultivation program -- the 60th day of learning clock in

Java introduction to mastery (60th day of punch in)

Java 8 stream operation follow-up

Time flies. I've been learning java for 2 months. In the first half of the month, I've delayed a lot of progress because of the review. I still have energy to spend on Algorithms and basic Java problems. I find that I really can't do many things. There are several important modules to explain separately. One is the second half of the data results. It's not difficult to learn the data structure before. At that time, a blog will summarize it From the sequence table to the queue, focus on analyzing the hash table and the following B-tree, as well as graph theory. Hash and threads should analyze the source code, such as CurrentHashMap, HashMap,HashSet, ThreadLocal,Simp... Many source codes are very easy to test

Ready to officially end java8 and enter the database. You still need to know how to add, delete, check and change, 🚶 Time is really tight

Stream review

The previous sharing is a little old, because java8 stream has not been used for a long time, so let's briefly review. First, the Lambda expressions and method references of java8 are for functional interfaces, that is, the interface with only one abstract method. Stream is used to process data. For example, noSQL needs to process data in Java service s To manage data, we need to use a stream. The use of a stream is divided into several steps. The first step is the creation of a stream. There are many ways to create a stream, either through a collection or an array. You can also directly create an infinite stream. The stream class is a generic class. Therefore, to give the data type of a stream, simply write the creation of a stream here

List<Employee> employees = Arrays.asList(new NameListService().getAllEmployees());
Stream<Employee> stream = employees.stream();  //Create with collection object. stream
Stream<Employee> parallstream = employees.parallelStream();       //Parallel flow, data has no order, just like multithreading
parallstream.forEach(System.out :: println); //Operate on the data in each stream. The functional interface in parentheses uses method references
		
Employee[] employees1 = new NameListService().getAllEmployees();
Stream<Employee> stream1 = Arrays.stream(employees1); //Using arrays, operations on arrays can be regarded as collections, so use the stream of the arrays tool to create them
stream1.forEach(t -> System.out.println(t == new Employee(8, "c wind", 30, 19800.0))); //Using Lambda expressions


//If not through a collection or array, you can also directly use the of method of Stream
Stream<Employee> stream2 = Stream.of(employees1);   //Using the of method in the Stream interface
		
//There is also an infinite Stream generated by Stream
//1. Through iteration, you can create infinite flow by giving a seed and function
Stream.iterate(2, t -> t * 2).limit(10).forEach(System.out :: println);
//2. Through generate, you need to provide a function that can automatically generate objects
Stream.generate(Math :: random).limit(20).forEach(System.out :: println);

The first is that the collection object can directly use its stream or parallelstream method to create a stream; the array object can use either the strat method of Arrays or the of method of the strat interface; or the generate method of the interface to create a stream. Let's analyze the first two streams

After the flow is created, there is an intermediate execution process and an end

Intermediate operation of Stream

Multiple intermediate operations can be connected to form a pipeline. In my last blog post, I put a picture of a Stream pipeline. Unless the termination condition is triggered on the pipeline, the intermediate operation will not perform any processing. When the operation is terminated, it will be processed all at once, which is called "lazy processing", which was also emphasized before, and is the same as finalize Sample can only be used once. If you want to continue processing, you can only recreate the Stream

Here you can see the effect

stream1.filter(e -> e.getSalary() < 7000).forEach(System.out :: println);   //There is a functional interface for judgment, so write a judgment statement here
stream1.limit(3).forEach(System.out :: println);

Here, there are already intermediate operations and termination operations above. Next, I want to operate the flow again

java.lang.IllegalStateException: stream has already been operated upon or closed

The program directly reported an error 🏷

Filtering and sorting

There are several methods involved

  • Filter (predicted P) -- receive Lambda and exclude some elements from the stream
List<Employee> employees = Arrays.asList(new NameListService().getAllEmployees());
Stream<Employee> stream1 = employees.stream();
//stream1.forEach(System.out :: println);
//We use filter to filter employees whose salary is less than 7000
stream1.filter(e -> e.getSalary() < 7000).forEach(System.out :: println);;   //There is a functional interface for judgment, so a judgment statement is written here. No termination operation is not executed. Here, the foreach operation is used for execution

1 C 35 3000.0
2 C cloud 34 3500.0 programmer FREE Lenovo T4 [6000]
3 C top 30 3800.0 designer FREE 3000.0 Dell [NEC17 inches]
4 Li L 31 3100.0 programmer FREE Dell [Samsung 17 inch]
6 Q 22 6800.0 programmer FREE ASUS [Samsung 17 inches]
10 D 21 6600.0 programmer FREE Dell [NEC 17 inches]

  • distinct() ----- filter and remove duplicate elements through the hashCode() and equals() methods of the generated elements of the stream
Stream<Integer> stream2 = Stream.of(1,2,2,2,2,2,2,2,2,2);
stream2.distinct().forEach(System.out :: print);

//12
  • limit(long maxSize) -- truncate the stream so that its elements do not exceed the given value
Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6,7,8,9,10);
stream2.limit(3).forEach(System.out :: println);

1
2
3

  • skip(long n) –--------- skip elements and return a stream that discards the first n elements. If the elements in the stream are less than N, an empty stream is returned, which is complementary to limit
Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6,7,8,9,10);
stream2.limit(3).forEach(System.out :: print);
45678910

Therefore, they are just complementary. For example, limit(3) and skip(3) are just the first three of the stream and the data after the first three of the stream

mapping

The main methods are map related, that is, mapping

  • map(Function f) ---------------- take a function as a parameter, which will be applied to each element and change it into a new element, that is, x to y]
List<String> strs = Arrays.asList("i","am","c","feng","happy");
strs.stream().map(str -> str.toUpperCase()).forEach(System.out :: println);

/*
I
AM
C
FENG
HAPPY
*/
//Another wave of extreme operation
List<Employee> employees = Arrays.asList(new NameListService().getAllEmployees());
employees.stream().map(Employee :: getName).filter(str -> str.length() >= 3).forEach(System.out :: println);
//Employee is a class in previous scheduling.
//Here, after creating a stream from a collection, use getName mapping to get a new stream name stream, and then filter the name stream for output
//The output result is Liu Da W
  • mapToDouble(ToDoubleFunction f) -- receive a function as a parameter, which will be applied to each element and generate a new DoubleStream
  • mapToInt(ToIntFunction f) -- receive a function as a parameter, which will be applied to each element and generate a new IntStream
  • mapToLong(ToLongFunction f) ------ receive a function as a parameter, which will be applied to each element to generate a new LongStream
  • flatMap(Function f) ------------------- receive a function as a parameter, replace each value in the stream with another stream, and then connect all streams into one stream

The difference between map and flatmap

This is somewhat similar to the merging of sets. Here is an example

ArrayList list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
		
ArrayList list2 = new ArrayList<>();
list2.add(3);
list2.add(4);
System.out.println(list1);
//list1.add(list2);
list1.addAll(list2);
System.out.println(list1);

[1, 2]
[1, 2, [3, 4]]

[1, 2, 3, 4]

The two addition methods here are different, so the results are different. Adding a table directly obtains a generalized table, while adding elements is still an ordinary table

What does this have to do with map? 🏷

map is similar to the add method

flatmap is similar to the addAll method

That is, if a normal map map loads a stream, the stream is loaded as a whole, while flatmap connects all streams

Let's test these two methods

public static Stream<Character> fromStringToStream(String str) {
ArrayList<Character> list = new ArrayList<>();
for(Character c : str.toCharArray()) {//Change string to character array
	list.add(c); //Add array to collection
	}
	return list.stream();
}

List<String> list = Arrays.asList("cfeng","clei","cyu","cdian");
//List. Stream(). Map (STR - > fromstringtostream (STR)); / / equivalent to stream of stream
list.stream().map(StreamTest :: fromStringToStream).forEach(System.out :: println);

After the flow here is mapped, each element becomes a stream < < character >, that is, it becomes a stream of the flow. Then it is traversed

java.util.stream.ReferencePipeline$Head@6c629d6e
java.util.stream.ReferencePipeline$Head@5ecddf8f
java.util.stream.ReferencePipeline$Head@3f102e87
java.util.stream.ReferencePipeline$Head@27abe2cd

This is not the result we want

If you want to get data, you can only nest it again and traverse each data stream

list.stream().map(StreamTest :: fromStringToStream).forEach(s -> {
s.forEach(System.out :: println);
});

After that, you get the characters one by one

flatmap is simpler. After recognizing each mapping, it becomes a character stream, so it is directly connected to form a new stream

list.stream().flatMap(StreamTest :: fromStringToStream).forEach(System.out :: println);

After connection, a stream composed of characters is formed, which is no longer a stream of streams

sort

This operation is to sort the data in the stream

  • sorted() ---------------- generate a new stream, sorted in natural order
  • sorted(Comparator com) -- generates a new stream, which is sorted in comparator order

The Comparable interface is thought of in sorting. If the data class implements the interface, you can use the interface implemented by natural sorting to sort. If there is no interface implemented, an error will be reported

public final class String
implements java.io.Serializable, Comparable,

For example, the String class implements the interface and can use natural sorting

List<String> list = Arrays.asList("cfeng","clei","cyu","cdian");
list.stream().sorted().forEach(System.out :: println);

cdian
cfeng
clei
cyu

If you don't implement the interface, you can use custom sorting, so you can use Lambda expression to write the comparator interface

Employee[] emp = new NameListService().getAllEmployees();
Stream<Employee> stream2 = Arrays.stream(emp);
stream2.sorted().forEach(System.out :: println);
//If the interface is not implemented, an error will be reported
// java.lang.ClassCastException: class pers.Cfeng.groupsheduing.datafield.Programmer cannot be cast to class java.lang.Comparable (pers.Cfeng.groupsheduing.datafield.Programmer is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')

Let's simply sort by age

Employee[] emp = new NameListService().getAllEmployees();
Stream<Employee> stream2 = Arrays.stream(emp);
stream2.sorted( (e1,e2) -> Integer.compare(e1.getAge(), e2.getAge())).forEach(System.out :: println);

10 D 21 6600.0 programmer FREE Dell [NEC 17 inches]
6 Q 22 6800.0 programmer FREE ASUS [Samsung 17 inches]
11 C 25 7100.0 programmer FREE ASUS [Samsung 17 inches]
9 C rain 26 9800.0 designer FREE 5500.0 HP m6 [5800]
12 C Yang 27 9600.0 designer FREE 4800.0 HP m6 [5800]
5 Lei J 28 10000.0 designer FREE 5000.0 Canon 2900 [laser]
7 Liu Y 29 10800.0 designer FREE 5200.0 ASUS [Samsung 17 inches]
3 C top 30 3800.0 designer FREE 3000.0 Dell [NEC17 inches]
8 C wind 30 19800.0 architect FREE 15000.0 2500 Epson 20K [needle]
13 Liu Da W 30 19500.0 architect FREE 17000.0 3000 HP M401d [inkjet]
4 Li L 31 3100.0 programmer FREE Dell [Samsung 17 inch]
2 C cloud 34 3500.0 programmer FREE Lenovo T4 [6000]
1 C 35 3000.0

You can see that it is sorted by age

Termination of Stream

The termination operation of the stream will generate a result from the stream pipeline. The result can not be the value of any stream, but can be List, Integer, void; After the stream is terminated, it cannot be used again

There are several types of termination operations

Match and find

  • allMatch(Predicate p) checks whether all elements are matched
  • Anymatch (predict P) checks whether at least one element is matched
  • Nonematch (predict P) checks if there are no matching elements
  • findFirst() returns the first element
  • findAny() returns any element in the stream
  • count() returns the total number of elements in the stream
  • max
  • min
Employee[] emp = new NameListService().getAllEmployees();
Stream<Employee> stream2 = Arrays.stream(emp);
boolean is =  stream2.allMatch(e -> e.getAge() > 18);//This is a boolean type to output
System.out.println(is);

The printed result is true

Employee[] emp = new NameListService().getAllEmployees();
Stream<Employee> stream2 = Arrays.stream(emp);
Optional<Employee> is =  stream2.findFirst();
System.out.println(is);

The printed result is

Optional[1 C-35 3000.0]

reduction

The connection between map and reduce is usually called map reduce mode

  • Reduce (T iden, binary operator b) can combine the elements in the stream repeatedly to get a value and return T
  • reduce(BinaryOperator b) can combine the elements in the stream repeatedly to get a value and return Optional
//Calculate the sum of natural numbers from 1 to 10 -- get 55
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0,Integer ::  sum);
System.out.println(sum);
Employee[] emp = new NameListService().getAllEmployees();
Stream<Employee> stream2 = Arrays.stream(emp);
System.out.println(stream2.map(Employee :: getSalary).reduce(Double :: sum));

Optional[113400.0]

collect

Collectors use classes to provide many static methods for creating collectors

The implementation of the methods in the Collector interface determines how to perform collection operations, such as collecting maps and lists

  • collect(Collector c) converts the Stream into other forms, receives the implementation of a collector interface, and is used to summarize the elements in the Stream
Employee[] emp = new NameListService().getAllEmployees();
Stream<Employee> stream2 = Arrays.stream(emp);
List list = stream2.filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
System.out.println(list);

That is, after processing the stream, collect the stream and put it into a container

Here is the List

[5 Lei J 28 10000.0 designer FREE 5000.0 Canon 2900 [laser], 6 Q 22 6800.0 programmer FREE ASUS [Samsung 17 inch], 7 Liu Y 29 10800.0 designer FREE 5200.0 ASUS [Samsung 17 inch], 8 C wind 30 19800.0 architect FREE 15000.0 2500 Epson 20K [needle], 9 C rain 26 9800.0 Designer FREE 5500.0 HP m6 [5800] , 10 D 21 6600.0 programmer FREE Dell [NEC 17 inches], 11 C 25 7100.0 programmer FREE ASUS [Samsung 17 inches], 12 C Yang 27 9600.0 designer FREE 4800.0 HP m6 [5800], 13 Liu Da W 30 19500.0 architect FREE 17000.0 3000 HP M401d [inkjet]]

Can be written as

list.forEach(System.out :: println);

This way, the printing is neat 🏮

Posted by kevin99 on Wed, 10 Nov 2021 13:56:58 -0800