How do I understand Java8 Stream

Before introduction Java8 Stream read a lot of articles, but the initial contact is really hard to understand (my understanding is relatively low), no way can only "rote", but yesterday I hit the king of glory (that I won bureau, cattle magic audience MVP) when a sudden burst of inspiration, did not understand before suddenly feeling a thorough understanding thorough. So I think that the decision to recall at the java8 Stream in a simple manner.

lambda expressions

grammar

lambda expression is the cornerstone Stream API, so you want to learn how to use Stream API, you must first understand lambda expressions, lambda here to do a brief review.

We often see code

Arrays.sort(new Integer[]{1, 8, 7, 4}, new Comparator<Integer>() {
   @Override
   public int compare(Integer first, Integer second) {
       return first.compareTo(second);
   }
});
复制代码

The wording above is the use of anonymous classes, we often use anonymous class, because we only run once, do not want it always existed. Although lambda expression for what is called functional programming, but also everyone in the community come out after a long, but in my opinion is to party (steal) it (lazy).

The above code says trouble, but converted into following this happen?

Arrays.sort(new Integer[]{1, 8, 7, 4},
	(first,second) -> first.compareTo(second));
复制代码

This looked more than comfortable, but some unnecessary details are hidden. For this method contains only an abstract interface, you can create objects of the interface via lambda interface, which is called functional interface.

lambda expression introduces a new operator: -> , which the lambda expression is divided into two parts

(n) -> n*n
复制代码

Parameters needed to specify the left side of the expression, if no parameter may be null. Lambda is a right block, which specifies the operation of a lambda expression.

Note that if the method when only one returned without a statement, the default will return. If you have time to return the branch is required to perform the statement.

(n) -> {
	if( n <= 10) 
		return n*n;
	return n * 10;
}
复制代码

And a constructor method references cited

Method references

In some cases, first passed to the operation of the other codes have been implemented in the method. For example, the GUI must first print event object when the button is clicked, you can call

button.setOnAction(event -> System.out.println(event));
复制代码

This time I want to be lazy, I do not want to write event parameters, because only one parameter, jvm can not help me? Here is the modified code is good


button.setOnAction(System.out::println);
复制代码

Expression System.out::printlnis a reference to a method equivalent to the lambda expression x -> System.out.println(x). ** ** :: operator method name and the name of the object class or separated, are the following three main usage:

  1. :: Object instance methods
  2. :: class static method
  3. :: class instance methods

The first two cases, the method provides a method equivalent to the reference parameters of the lambda expression. For example Math::pow ==== (x,y) -> Math.pow(x,y).

The third case, the first argument of the called object execution method. For example String::compareToIgnoreCase ==== (x,y) -> x.compareToIgnoreCase(y).

There this::equals ==== x -> this.equals(x), super::equals ==== super.equals(x).

Constructor references

List<String> strList = Arrays.asList("1","2","3");
Stream<Integer> stream =  strList.stream().map(Integer::new);
复制代码

The above code Integer::newis the constructor reference, except that the reference in the constructor method name is new. If there are multiple constructors, the compiler will infer and find the right one from the context.

StreamAPI

Stream the word translates to mean stream flow, stream flow and water flow.

Stream

It seems to me like a stream, like the above chart, the data is the beginning of small water droplets, which after various "interceptor" of treatment, the water droplets and some are discarded, some bigger, some with color, and some become a triangle. Finally, they turned round with a color. We finally put the result set. Many times we write the code is as follows: through a collection, and determination of the elements of the set or be converted, is added to satisfy the conditions to which the new collection, this approach to the above is the same as FIG. First look at a piece of code

Map<String,Map<String,Integer>> resultMap = new HashMap<>();
Map<String,Integer> maleMap = new HashMap<>();
Map<String,Integer> femaleMap = new HashMap<>();

resultMap.put("male", maleMap);
resultMap.put("female",femaleMap);

for(int i = 0; i < list.size(); i++) {
    Person person = list.get(i);
    String gender = person.getGender();
    String level = person.getLevel();
    switch (gender) {
        case "male":
            Integer maleCount;
            if("gold".equals(level)) {
                maleCount = maleMap.get("gold");
                maleMap.put("gold", null != maleCount ? maleCount + 1 : 1);
            } else if("soliver".equals(level)){
                maleCount = maleMap.get("soliver");
                maleMap.put("soliver", null != maleCount ? maleCount + 1 : 1);
            }
            break;

        case "female":
            Integer femaleCount;
            if("gold".equals(level)) {
                femaleCount = femaleMap.get("gold");
                femaleMap.put("gold", null != femaleCount ? femaleCount + 1 : 1);
            } else if("soliver".equals(level)){
                femaleCount = femaleMap.get("soliver");
                femaleMap.put("soliver", null != femaleCount ? femaleCount + 1 : 1);
            }
            break;

    }
}

复制代码

The code above effect is the number of engineers rank statistics of different genders, before the Java StreamAPI out, so similar business code in the system should be everywhere, Hand above code I took about two minutes later with Stream, I stole a lazy

Map<String,Map<String,Integer>> result = list.stream().collect(
    Collectors.toMap(
	    person -> person.getGender(),
	    person -> Collections.singletonMap(person.getLevel(), 1),
	    (existValue,newValue) -> {
	        HashMap<String,Integer> newMap = new HashMap<>(existValue);
	        newValue.forEach((key,value) ->{
	            if(newMap.containsKey(key)) {
	                newMap.put(key, newMap.get(key) + 1);
	            } else {
	                newMap.put(key, value);
	            }
	        });
	        return newMap;
	    })
);

复制代码

Or into such a code

Map<String,Map<String,Integer>> result =  stream.collect(
    Collectors.groupingBy(
        Person::getGender, 
        Collectors.toMap(
            person->person.getLevel(), 
            person -> 1,
            (existValue,newValue) -> existValue + newValue
        )
    )
);

复制代码

Not only reducing the number of code blocks, logic even clearer. Really cool moment with a stream, has been used Shuangya.

Stream as stream, which may be finite or infinite, of course, we use most or flow limited (for loop flow is limited), as described above in FIG goes, we can make the various elements of the convection in the respective common kind of treatment. For example summation, filtering, grouping, maximum, minimum and other common process, so start using it Stream

Stream properties

  1. Stream does not store its own element, the element may be set in the bottom, is produced or stored.
  2. Stream operator does not change the source object, on the contrary, they will return to hold a new stream object
  3. Stream operator is to delay execution, you may need to wait until the results before going to execute.

Stream API

Functional Interface Parameter Type Return Type Abstract method name description Other methods
Runnable no void run Without performing the operation parameters and return values no
Supplier<T> no T get Providing a value of type T
Counsumer<T> T void accept A type of processing value T chain
BiConsumer<T,U> T, U void accept Processing value of type T and U type chain
Function<T,R> T R apply A parameter of type function T compose,andThen,identity
BiFunction<T,U,R> T, U R apply A parameter type is a function of U and T andThen
UnaryOperator<T> T T apply Unary operators of type T is compose,andThen,identity
BinaryOperator<T> T,T T apply T is of type binary operator andThen
Predicate<T> T boolean test Computing a boolean function value And,or,negate,isEqual
BiPredicate<T,U> T, U boolean test A function with two parameters, computing a boolean and,or,negate

Difference map () and flatMap () of

When using the map method, a function equivalent to applying each element, and a new Stream collected values ​​returned.

Stream<String[]>	-> flatMap ->	Stream<String>
Stream<Set<String>>	-> flatMap ->	Stream<String>
Stream<List<String>>	-> flatMap ->	Stream<String>
Stream<List<Object>>	-> flatMap ->	Stream<Object>

{{1,2}, {3,4}, {5,6} } -> flatMap -> {1,2,3,4,5,6}
复制代码

End and intermediate operation

All operations on the Stream into two categories: operational and middle end of the operation, the operation is only a middle mark (calls to these methods, and not really start to traverse the stream.), Only the end of the operation will trigger the actual calculation. Simply means that the return value is still Stream API is the middle of the operation, otherwise it is the end of the operation.

How to debug

  1. Please use the code segment, such as IntStream.of(1,2,3,4,5).fiter(i -> {return i%2 == 0;})the breakpoint hit to the code segment.
  2. Reference method also can be debugged, marked in such a breakpoint in isDoubleIntStream.of(1,2,3,4,5).fiter(MyMath::isDouble)

Those poor understanding of the API

  1. reduce () how do we accumulate before it is complete?

int sum = 0;
for(int value in values) {
	sum = sum + value;
}

复制代码

Now stream into ways to achieve

values.stream().reduce(Integer::sum);
复制代码

The reduce () method is a binary function: from the first two elementary stream starts, it continues to be applied to the other elements in the stream.

How to write the code Stream

stream the API is designed for convenience, not convenient level sql data processing may be implemented by a packet stream, polymerization, maximum, minimum, sorting, etc. summing operation. So do not take it too complicated, just write enough. There is always one day you skilled can write the code too simple. From now on, or put your project for a large number of circulating transformed into a stream mode.

The sample code

I mean to write code to a large segment pattern to convert the stream API, but thought there is no need to find a part of the code hutool github tools to complete the conversion of the example. (You can improve the ability to stream api this way)

  1. Calculate the number of times each element appears (please imagine under jdk7 how to achieve)
代码效果:[a,b,c,c,c]  -> a:1,b:1,c:3

Arrays.asList("a","b","c","c","c").stream().collect(Collectors.groupingBy(str->str, Collectors.counting()));
复制代码
  1. In a particular set of separators to be converted to a string, and adds prefix and suffix (Please imagine how to achieve the jdk7)
List<String> myList = Arrays.asList("a","b","c","c","c");
myList.stream().collect(Collectors.joining(",","{","}"));

复制代码
  1. Judged incomplete list is empty (please imagine under jdk7 how to achieve)
myList.stream().anyMatch(s -> !s.isEmpty());
复制代码

Guess you like

Origin juejin.im/post/5d536870e51d4561c6784066