Learning notes on new features of JAVA 8
Lambda expression
1, Introduction to Lambda expressions
What is Lambda?
Lambda is a new feature added to JAVA 8. To put it bluntly, lambda is an anonymous function
Why Lambda
Using Lambda expressions, you can implement the methods of an interface very concisely
Lambda's requirements for interfaces
Although some interfaces can be simply implemented with Lambda expressions, not all interfaces can be implemented with Lambda expressions. It is required that only one abstract method defined in the interface must be implemented
Lambda expressions require functional interface support
Functional interface: an interface with only one abstract method, which becomes a functional interface. You can use the annotation @ FunctionalInterface to modify it. The function of the annotation is to check whether the interface is a functional interface
stay JAVA8 In, a new feature is added to the interface: default have access to default Modify the interface method. The modified method can be implemented by default in the interface
@FunctionalInterface
Modifies a functional interface. There is only one abstract method in the interface
2, Basic grammar of Lambda
Basic syntax of Lambda expression: JAVA 8 introduces a new operator "- >", which becomes an arrow operator or Lambda operator
The arrow operator splits the Lambda expression into two parts:
On the left is the parameter list of Lambda expression
On the right is the function to be performed in the Lambda expression, that is, the Lambda body
grammar
/** * Syntax format 1: no parameter, no return value * () -> System.out.println("Hello Lambda!"); */ @Test public void test1() { // Before JDK 1.8, when global parameters are passed into local internal classes (anonymous internal classes), they need to be modified with final. After JDK 1.8, they will be modified with final by default, which can be omitted int num = 0; // Original usage Runnable r = new Runnable() { @Override public void run() { System.out.println("Hello Lambda!" + num); } }; r.run(); System.out.println("----------------------------------"); // Lambda expression usage Runnable r1 = () -> System.out.println("Hello Lambda!" + num); r1.run(); } /** * Syntax format 2: there is a parameter and no return value * (x) -> System.out.println(x); */ @Test public void test2() { Consumer<String> con = (x) -> System.out.println(x); con.accept("Hello Lambda!"); Consumer<String> con1 = System.out::println; con1.accept("Hello Lambda!!!"); } /** * Syntax format 3: if there is only one parameter, parentheses can be omitted * x -> System.out.println(x); */ @Test public void test3() { Consumer<String> con = x -> System.out.println(x); con.accept("Hello Lambda!"); } /** * Syntax format 4: there are two or more parameters, and there are multiple statements in the Lambda body * (x, y) - { * System.out.println(x+"->"+y) * return Integer.compare(x, y); * } */ @Test public void test4() { Comparator<Integer> com = (x, y) -> { System.out.println(x + y); return Integer.compare(x, y); }; } /** * Syntax format 5: if there are two or more parameters and there is only one statement in the Lambda body, return and braces {} can be omitted * (x, y) -> Integer.compare(x, y); * Integer::compare; */ @Test public void test5() { // First format Comparator<Integer> com = (x, y) -> Integer.compare(x, y); // Second format Comparator<Integer> com1 = Integer::compare; } /** * Syntax format 6: the data type of the parameter list of Lambda expression can be omitted, because the JVM compiler will infer according to the context, that is, "type inference" * (x, y) -> Integer.compare(x, y); * (Integer x, Integer y) -> Integer.compare(x, y); */
summary
Upper couplet: left and right meet a bracket, and lower couplet: infer the type on the left. Horizontal batch: save if you can
3, Four core built-in functional interfaces of Java 8
After learning the four built-in interfaces, you can use most of Lambda's methods!!!
Interface | method | describe |
---|---|---|
Consumer | void accept(T t) | Consumer interface |
Supplier | T get() | Supply type interface |
Function<T, R> | R apply(T t) | Functional interface |
Predicate | boolean test(T t) | Assertive interface |
Consumer: consumer interface
It is used to consume some services. Examples are as follows
// Consumer < T >: consumer interface @Test public void test() { happy(10000, x -> System.out.println("Xiaoming spends 1000 yuan today")); } public void happy(double money, Consumer<Double> consumer) { consumer.accept(money); }
Supplier: supply type interface
Used to provide services, examples are as follows
// Supplier < T >: supply type interface @Test public void test() { List<Integer> purchase = Purchase(10, () -> (int) (Math.random() * 100)); purchase.forEach(System.out::println); } // Requirement: generate a specified number of integers and put them into the interface public List<Integer> Purchase(int num, Supplier<Integer> supplier) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < num; i++) { list.add(supplier.get()); } return list; }
Function < T, R >: functional interface
It is used to process data and return some of the same or different data types. Examples are as follows
// Function < T, R >: functional interface @Test public void test3() { System.out.println(fun("biandekaixin", k -> k.toUpperCase(Locale.ROOT).substring(2, 4))); System.out.println(fun1(new Employee(1, "Zhang San", 18, 6000), Employee::getName)); } public String fun(String str, Function<String, String> function) { return function.apply(str); } public String fun1(Employee employee, Function<Employee, String> function) { return function.apply(employee); }
Predicate: predicate interface
It is used to process the data that meets the conditions. For example, elements with filter length greater than 3 are placed in a new array. Examples are as follows:
// Predicate < T >: predicate interface @Test public void test4() { List<String> list = new ArrayList<>(); list.add("www"); list.add("Hello"); list.add("Lambda"); list.add("ok"); list.add("cccc"); List<String> str = filterStr(list, k -> k.length() > 3); str.forEach(System.out::println); } // Requirement: put the string meeting the requirement into the collection public List<String> filterStr(List<String> strs, Predicate<String> predicate) { List<String> list = new ArrayList<>(); for (String str : strs) { if (predicate.test(str)) { list.add(str); } } return list; }
Extended sub interface with built-in four core functional interfaces
Interface | method | describe |
---|---|---|
BiFunction <T, U, R> | R apply (T t, U u) | Operate on the passed in parameters and return the R-type processing results |
UnaryOperator | T apply (T t) | Perform unary operation on the parameter and return the result of type T |
BinaryOperator | T apply (T t1, T t2) | Binary operation is performed on the parameter to return the result of type T |
BiConsumer <T, U> | void accept (T t, U u) | Operate on parameters t and u without returning results |
ToIntFunction | int applyAsInt (T t) | Strong conversion of the passed in parameter to int type return |
ToLongFunction | long applyAsLong (T t) | Strong conversion of the passed in parameter to long type return |
ToDoubleFunction | double applyAsDouble (T t) | Force the passed in parameter into double type and return |
IntFunction | R apply(int param) | After processing, an int type is forcibly converted to R type and returned |
LongFunction | R apply(long param) | After processing, a long type is forcibly converted to R type and returned |
DoubleFunction | R apply(double param) | After processing, a double parameter is forcibly converted to R type and returned |
4, Method reference
Method reference: if Lambda The content in the body has methods that have been implemented. We can use "method reference" (It can be understood that a method reference is Lambda Another form of expression) There are three main syntax formats: Object name::Instance method name class::Static method name class::Instance method name be careful: 1,Lambda The parameter list and return value type of the calling method are consistent with the function list and the return value type of the abstract method in the functional interface.. 2,if Lambda This parameter can be used when the first parameter in the parameter list is the caller of the instance method and the second parameter is the parameter of the instance method ClassName::method.
Object name:: instance method name
// Object name:: instance method name @Test public void test1() { PrintStream out = System.out; Consumer<String> con = (x) -> out.println(x); Consumer<String> con2 = out::println; Consumer<String> con3 = System.out::println; con3.accept("ccc"); } @Test public void test2() { Employee emp = new Employee(1, "zs", 18, 2000); Supplier<String> s = () -> emp.getName(); System.out.println(s.get()); Supplier<Integer> s1 = emp::getAge; System.out.println(s1.get()); }
Class name:: static method name
// Class:: static method name @Test public void test3() { Comparator<Integer> com = (x, y) -> Integer.compare(x, y); Comparator<Integer> com1 = Integer::compare; }
Class name:: instance method name
// Class:: instance method name @Test public void test4() { BiPredicate<String, String> bp = (x, y) -> x.equals(y); BiPredicate<String, String> bp1 = String::equals; }
5, Constructor reference
Format: ClassName :: new be careful: The parameter list of the constructor to be called should be consistent with the parameter list of the abstract method in the functional interface!
ClassName :: new
// Entity class @Data @Accessors(chain = true) public class Employee { /** * id */ private Integer id; /** * Name of */ private String name; /** * Age */ private Integer age; /** * wages */ private Integer salary; public Employee(Integer id, String name, Integer age, Integer salary) { this.id = id; this.name = name; this.age = age; this.salary = salary; } public Employee(Integer id, Integer age) { this.id = id; this.age = age; } public Employee(Integer id) { this.id = id; } public Employee() { } }
// Constructor reference @Test public void test5() { Supplier<Employee> s = () -> new Employee(); System.out.println(s.get()); Supplier<Employee> s1 = Employee::new; System.out.println(s1.get()); } @Test public void test6() { Function<Integer, Employee> fun = Employee::new; System.out.println(fun.apply(15)); BiFunction<Integer, Integer, Employee> bf = Employee::new; System.out.println(bf.apply(11, 18)); }
6, Array reference
// Array reference @Test public void test7() { Function<Integer, String[]> fun = (x) -> new String[x]; System.out.println(fun.apply(10).length); Function<Integer, String[]> fun2 = String[]::new; System.out.println(fun2.apply(15).length); }
Stream API
1, Introduction to Stream API
What is Stream?
A Stream is a queue of elements from a data source and supports aggregation operations
- Elements are specific types of objects that form a queue. Stream in Java does not store elements, but calculates on demand.
- The source of the data stream. It can be set, array, I/O channel, generator, etc.
- Aggregation operations are similar to SQL statements, such as filter, map, reduce, find, match, sorted, etc.
2, Three operation steps of Stream
Stream There are three steps: 1,establish Stream 2,Intermediate operation 3,Abort operation (terminal operation)
Create Stream
// There are four ways to create a Stream @Test public void test1() { // Stream() (serial stream) and parallelStream() (parallel stream) provided through the Collection series Collection List<String> list = new ArrayList<>(); // First: serial stream Stream<String> stream1 = list.stream(); // Second: parallel flow Stream<String> stream2 = list.parallelStream(); // Get the array stream through the static method stream() in Arrays Employee[] arr = new Employee[]{}; Stream<Employee> stream3 = Arrays.stream(arr); // You can pass variable parameters, arrays and collections through the of() method in the Stream class Stream<String> stream4 = Stream.of("zs", "ls", "ww"); // Create infinite flow // The first method: the first parameter of the iteration is from which to start, and the second is a word interface of the functional interface Function Stream<Integer> stream5 = Stream.iterate(0, x -> x + 2); stream5.limit(10) .forEach(System.out::println); // The second kind: the production wears a functional interface and a consumer interface Stream<Double> stream6 = Stream.generate(() -> Math.random()); stream6.limit(5) .forEach(System.out::println); }
Intermediate operation
Note: multiple intermediate operations can be connected to form a pipeline. Unless the termination operation is triggered on the pipeline, the intermediate operation will not perform any processing! When the operation is terminated, it is processed all at once, which is called * * "lazy evaluation" * *. The intermediate operation of Stream will not have any result data output.
As a whole, the intermediate operations of Stream can be divided into filtering and slicing, mapping and sorting.
// Data sources used for the following operations List<Employee> employees = Arrays.asList( new Employee(1, "Zhang San", 18, 2500), new Employee(2, "Li Si", 25, 6500), new Employee(3, "Wang Wu", 38, 6000), new Employee(4, "Zhao Liu", 45, 8500), new Employee(5, "pseudo-ginseng", 25, 1500), new Employee(5, "pseudo-ginseng", 25, 1500), new Employee(5, "pseudo-ginseng", 25, 1500) );
Screening and slicing
method | describe |
---|---|
filter(Predicate p) | Receive a Lambda expression to exclude some elements from the stream |
distinct() | Filter to remove duplicate elements through hashCode() and equals() of the elements generated by the flow |
limit(long maxSize) | Truncate the stream so that its elements do not exceed the given number |
skip(long n) | Skip elements and return a stream that throws away the first n elements. If there are less than n elements in the stream, an empty stream is returned. Complementary to limit(n) |
// filter filtering // Internal iteration: the iteration operation is completed by the Stream API @Test public void test1() { // Intermediate operations do not perform anyone's operations Stream<Employee> stream = employees.stream() .filter(emp -> emp.getAge() > 35); // Abort all operations at once, becoming lazy evaluation stream.forEach(System.out::println); /** *Output: Employee(id=3, name = Wang Wu, age=38, salary=6000) * Employee(id=4, name=Zhao Liu (age=45, salary=8500) */ } // External iteration @Test public void test2() { Iterator<Employee> iterator = employees.iterator(); if (iterator.hasNext()) { System.out.println(iterator.next()); } } // limit truncated flow // As long as we find the data we need, such as limit(2), after finding two data, we won't continue the internal iteration. If the limit number is satisfied, it will be short circuited and will not be executed @Test public void test3() { employees.stream() .filter(e -> e.getSalary() > 3500) .forEach(System.out::println); /** *Output: Employee(id=2, name = Li Si, age=25, salary=6500) * Employee(id=3, name=Wang Wu (age=38, salary=6000) * Employee(id=4, name=Zhao Liu (age=45, salary=8500) */ employees.stream() .filter(e -> e.getSalary() > 3500) .limit(2) .forEach(System.out::println); /** *Output: Employee(id=2, name = Li Si, age=25, salary=6500) * Employee(id=3, name=Wang Wu (age=38, salary=6000) */ } // Skip skip element @Test public void test4() { employees.stream() .filter(e -> e.getSalary() > 3500) .forEach(System.out::println); /** *Output: Employee(id=2, name = Li Si, age=25, salary=6500) * Employee(id=3, name=Wang Wu (age=38, salary=6000) * Employee(id=4, name=Zhao Liu (age=45, salary=8500) */ employees.stream() .filter(e -> e.getSalary() > 3500) .skip(1) .forEach(System.out::println); /** *Output: Employee(id=4, name = Zhao Liu, age=45, salary=8500) */ } // distinct de duplication // Filter through hashCode() and equals() @Test public void test5() { employees.stream() .filter(e -> e.getSalary() < 3500) .forEach(System.out::println); /** * Output: Employee(id=1, name = Zhang San, age=18, salary=2500) * Employee(id=5, name=Tianqi (age=25, salary=1500) * Employee(id=5, name=Tianqi (age=25, salary=1500) * Employee(id=5, name=Tianqi (age=25, salary=1500) */ employees.stream() .filter(e -> e.getSalary() < 3500) .distinct() .forEach(System.out::println); /** *Output: Employee(id=1, name = Zhang San, age=18, salary=2500) * Employee(id=5, name=Tianqi (age=25, salary=1500) */ }
mapping
method | describe |
---|---|
map(Function f) | Receive a function as an argument, which is applied to each element and mapped to a new element. |
mapToDouble(ToDoubleFunction f) | Receive a function as an argument, which will be applied to each element to generate a new DoubleStream. |
mapToInt(ToIntFunction f) | Receive a function as a parameter, which will be applied to each element to generate a new IntStream. |
mapToLong(ToLongFunction f) | Receive a function as an argument, which will be applied to each element to generate a new LongStream |
flatMap(Function f) | Take a function as a parameter, replace each value in the stream with another stream, and then connect all streams into one stream |
// Map mapping flow is to apply the functional interface in map (function < T > fun) to each element @Test public void test6() { List<String> list = Arrays.asList("aa", "bb", "cc", "dd"); list.stream() .map(String::toUpperCase) .forEach(System.out::println); /** * Output: * AA * BB * CC * DD */ employees.stream() .map(Employee::getName) .distinct() .forEach(System.out::println); /** * Output: * Zhang San * Li Si * Wang Wu * Zhao Liu * pseudo-ginseng */ } // Maptodouble (todoublefunction f), maptoint (tointfunction f) and maptolong (tolongfunction f) are not examples // flatMap() takes a stream as a parameter, converts each value in one stream into another stream, and connects all streams into one stream. The relationship between map() and flatMap() is similar to the relationship between methods in list and add() and addAll() @Test public void test7() { List<String> list = Arrays.asList("aa", "bb", "cc", "dd"); // map() list.stream() .map(TestStreamAPI::filterCharacter) // There's this {[a,a],[b,b],[c,c],[d,d]} .forEach(k -> k.forEach(System.out::println)); // flatMap() list.stream() .flatMap(TestStreamAPI::filterCharacter) // Inside the village is this {a,a,b,b,c,c,d,d} .forEach(System.out::println); } public static Stream<Character> filterCharacter(String str) { ArrayList<Character> list = new ArrayList<>(); for (char c : str.toCharArray()) { list.add(c); } return list.stream(); } // The difference between add() and addAll() @Test public void test8() { List<String> list = Arrays.asList("aa", "bb", "cc", "dd"); List list2 = new ArrayList(); list2.add(11); list2.add(22); list2.add(list); list2.forEach(System.out::println); /** *Output: * 11 * 22 * [aa, bb, cc, dd] */ list2.addAll(list); list2.forEach(System.out::println); /** *Output: * 11 * 22 * aa * bb * cc * dd */ }
sort
method | describe |
---|---|
sorted() | Generate a new stream, which is sorted in natural order |
sorted(Comparator comp) | Generates a new stream, sorted in comparator order |
// sorted() @Test public void test9() { // Natural sorting List<String> list = Arrays.asList("a", "ccc", "bbb", "dd"); list.stream() .sorted() .forEach(System.out::println); /** *Output: * a * bbb * ccc * dd */ // Comparator sort employees.stream() .distinct() .forEach(System.out::println); /** *Output: * Employee(id=1, name=Zhang San (age=18, salary=2500) * Employee(id=2, name=Li Si, age=25, salary=6500) * Employee(id=3, name=Wang Wu (age=38, salary=6000) * Employee(id=4, name=Zhao Liu (age=45, salary=8500) * Employee(id=5, name=Tianqi (age=25, salary=1500) */ employees.stream() .sorted((e1, e2) -> { if (e1.getAge() == e2.getAge()) { return e1.getName().compareTo(e2.getName()); } else { return Integer.compare(e1.getAge(), e2.getAge()); } }) .distinct() .forEach(System.out::println); /** *Output: * Employee(id=1, name=Zhang San (age=18, salary=2500) * Employee(id=2, name=Li Si, age=25, salary=6500) * Employee(id=5, name=Tianqi (age=25, salary=1500) * Employee(id=3, name=Wang Wu (age=38, salary=6000) * Employee(id=4, name=Zhao Liu (age=45, salary=8500) */ }
Terminate operation
The terminal operation generates results from the pipeline of the stream. The result can be any value that is not a stream, such as List, Integer, Double, String, etc., or even void.
In Java 8, the termination operation of Stream can be divided into: find and match, specification and collection.
// Data source used List<Employee> employees = Arrays.asList( new Employee(1, "Zhang San", 18, 2500, Employee.Status.FREE), new Employee(2, "Li Si", 25, 6500, Employee.Status.BUSY), new Employee(3, "Wang Wu", 38, 6000, Employee.Status.VACATION), new Employee(4, "Zhao Liu", 45, 8500, Employee.Status.BUSY), new Employee(5, "pseudo-ginseng", 25, 1500, Employee.Status.VACATION) );
Find and match
method | describe |
---|---|
allMatch(Predicate p) | Check that all elements match |
anyMatch(Predicate p) | Check to see if at least one element matches |
noneMatch(Predicate p) | Check that no elements match |
findFirst() | Returns the first element |
findAny() | Returns any element in the current stream |
count() | Returns the total number of elements in the stream |
max(Comparator c) | Returns the maximum value in the stream |
min(Comparator c) | Returns the minimum value in the stream |
forEach(Consumer c) | Internal iteration (using the Collection interface requires users to do iterations, which is called external iteration. On the contrary, the Stream API uses internal iteration) |
@Test public void test1() { // allMatch() checks whether all elements match. All elements are BUSY AND true. Otherwise, it is false, similar to AND boolean allMatch = employees.stream() .allMatch(x -> x.getStatus().equals(Employee.Status.BUSY)); System.out.println(allMatch); // false // anyMatch() checks that at least one match of the element contains this BUSY. Otherwise, it is false, similar to: OR boolean anyMatch = employees.stream() .anyMatch(x -> x.getStatus().equals(Employee.Status.BUSY)); System.out.println(anyMatch); // true // noneMatch() checks that the element does not match. This BUSY is false, otherwise it is true, similar to:! wrong boolean noneMatch = employees.stream() .noneMatch(x -> x.getStatus().equals(Employee.Status.BUSY)); System.out.println(noneMatch); // flase // The first element returned by findFirst() is the optional < T > container class, which will be supplemented later Optional<Employee> findFirst = employees.stream() .sorted(Comparator.comparingInt(Employee::getSalary)) .findFirst(); System.out.println(findFirst.get()); // Employee(id=5, name = Tianqi, age=25, salary=1500, status=VACATION) // findAny() returns any element, which is an optional < T > container class, which will be supplemented later in the parallel stream of parallelStream() Optional<Employee> findAny = employees.parallelStream() .filter(k -> k.getStatus().equals(Employee.Status.BUSY)) .findAny(); System.out.println(findAny.get()); // Employee(id=2, name = Li Si, age=25, salary=6500, status=BUSY) } @Test public void test2() { // count() returns the total number of elements in the stream long count = employees.stream() .count(); System.out.println(count); // max() returns the maximum value in the stream Optional<Employee> max = employees.stream() .max(Comparator.comparingInt(Employee::getSalary)); System.out.println(max.get()); // min() returns the minimum value in the stream Optional<Integer> min = employees.stream() .map(Employee::getSalary) .min(Integer::compare); System.out.println(min.get()); } // forEach doesn't need to be added
Statute
method | describe |
---|---|
reduce(T iden, BinaryOperator b) | You can combine the elements in the flow repeatedly to get a value. Return T |
reduce(BinaryOperator b) | You can combine the elements in the flow repeatedly to get a value. Return to Optional |
@Test public void test3() { // reduce(T iden, BinaryOperator b)/reduce(BinaryOperator b) can combine the elements in the stream repeatedly to obtain a value. Return T / optional < T > List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); Integer reduce = list.stream() // Integer returns T because the first parameter is the starting value and it will not be empty .reduce(0, Integer::sum); System.out.println(reduce); // 45 Optional<Integer> optional = employees.stream() .map(Employee::getSalary) // Optional is returned. Because there is no starting value, it may be empty, so optional is returned .reduce(Integer::sum); System.out.println(optional.get()); }
collect
method | describe |
---|---|
collect(Collector c) | Convert the Stream to another form. Receive the implementation of a Collector interface, which is used to summarize the elements in the Stream |
How do I collect Stream streams?
method | Return type | effect |
---|---|---|
toList | List | Collect the elements in the stream into a List |
toSet | Set | Collect the elements in the stream into a Set |
toCollection | Collection | Collect the elements in the stream into the created collection |
counting | Long | Count the number of elements in the flow |
summingInt | Integer | Summing integer attributes of elements in a stream |
averagingInt | Double | Calculates the average value of the Integer attribute of the element in the flow |
summarizingInt | IntSummaryStatistics | Collect statistics for the Integer attribute in the stream. E.g. average value |
joining | String | Each string in the connection stream |
maxBy | Optional | Select the maximum value according to the comparator |
minBy | Optional | Select the minimum value according to the comparator |
reducing | Type of reduction | Starting from an initial value as an accumulator, BinaryOperator is combined with the elements in the stream one by one to reduce it to a single value |
collectingAndThen | The type returned by the conversion function | Wrap another collector and convert its result to a function |
groupingBy | Map<K, List> | According to an attribute value, the attribute is K and the result is V |
partitioningBy | Map<Boolean, List> | Partition according to true or false |
The use examples corresponding to each method are shown in the following table.
method | Use example |
---|---|
toList | List employees= list.stream().collect(Collectors.toList()); |
toSet | Set employees= list.stream().collect(Collectors.toSet()); |
toCollection | Collection employees=list.stream().collect(Collectors.toCollection(ArrayList::new)); |
counting | long count = list.stream().collect(Collectors.counting()); |
summingInt | int total=list.stream().collect(Collectors.summingInt(Employee::getSalary)); |
averagingInt | double avg= list.stream().collect(Collectors.averagingInt(Employee::getSalary)) |
summarizingInt | IntSummaryStatistics iss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary)); |
Collectors | String str= list.stream().map(Employee::getName).collect(Collectors.joining()); |
maxBy | Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary))); |
minBy | Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary))); |
reducing | int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum)); |
collectingAndThen | int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); |
groupingBy | Map<Emp.Status, List> map= list.stream() .collect(Collectors.groupingBy(Employee::getStatus)); |
partitioningBy | Map<Boolean,List>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage)); |
// Collection @Test public void test4() { // toList List<String> list = employees.stream() .map(Employee::getName) .collect(Collectors.toList()); list.forEach(System.out::println); // toSet Set<String> set = employees.stream() .map(Employee::getName) .collect(Collectors.toSet()); set.forEach(System.out::println); // toCollection LinkedList<String> linkedList = employees.stream() .map(Employee::getName) .collect(Collectors.toCollection(LinkedList::new)); // In the latter, the type you want is new, LinkedList, HashSet, etc linkedList.forEach(System.out::println); } @Test public void test5() { // total Long count = employees.stream() .collect(Collectors.counting()); System.out.println(count); // average Double aDouble = employees.stream() .collect(Collectors.averagingInt(Employee::getSalary)); System.out.println(aDouble); // the sum Integer sum = employees.stream() .collect(Collectors.summingInt(Employee::getSalary)); System.out.println(sum); // Maximum Optional<Employee> max = employees.stream() .collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getSalary(), e2.getSalary()))); System.out.println(max.get()); // minimum value Optional<Integer> min = employees.stream() .map(Employee::getSalary) .collect(Collectors.minBy((x, y) -> Integer.compare(x, y))); System.out.println(min.get()); } // grouping @Test public void test6() { Map<Employee.Status, List<Employee>> groupingBy = employees.stream() .collect(Collectors.groupingBy(Employee::getStatus)); groupingBy.forEach((k, v) -> System.out.println(k + "--->" + v)); /** * Output: * VACATION--->[Employee(id=3, name=Wang Wu, age=38, salary=6000, status=VACATION), Employee(id=5, name = Tianqi, age=25, * salary=1500, status=VACATION), Employee(id=5, name = Tianqi, age=25, salary=1500, status=VACATION)] * * BUSY--->[Employee(id=2, name=Li Si, age=25, salary=6500, status=BUSY), Employee(id=4, name = Zhao Liu, age=45, * salary=8500, status=BUSY)] * * FREE--->[Employee(id=1, name=Zhang San, age=18, salary=2500, status=FREE)] */ } // Multi column grouping @Test public void test7() { Map<Employee.Status, Map<String, List<Employee>>> collect = employees.stream() .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e -> { if (e.getAge() < 30) { return "youth"; } else { return "Prime of life"; } }))); collect.forEach((k, v) -> System.out.println(k + "--->" + v)); /** * Output: * BUSY--->{Youth = [Employee(id=2, name = Li Si, age=25, salary=6500, status=BUSY)], adult = [Employee(id=4, name = Zhao Liu, * age=45, salary=8500, status=BUSY)]} * * FREE--->{Youth = [Employee(id=1, name = Zhang San, age=18, salary=2500, status=FREE)]} * * VACATION--->{Youth = [Employee(id=5, name = Tianqi, age=25, salary=1500, status=VACATION), Employee(id=5, name = Tianqi, * age=25, salary=1500, status=VACATION)], adult = [Employee(id=3, name = Wang Wu, age=38, salary=6000, status=VACATION)]} */ } // Slice / partition @Test public void test8() { Map<Boolean, List<Employee>> partitioningBy = employees.stream() .distinct() .collect(Collectors.partitioningBy(e -> e.getSalary() > 6000)); partitioningBy.forEach((k, v) -> System.out.println(k + "---" + v)); /** * Output: * false---[Employee(id=1, name=Zhang San, age=18, salary=2500, status=FREE), Employee(id=3, name = Wang Wu, age=38, salary=6000, * status=VACATION),Employee(id=5, name = Tianqi, age=25, salary=1500, status=VACATION)] * * true---[Employee(id=2, name=Li Si, age=25, salary=6500, status=BUSY), Employee(id=4, name = Zhao Liu, age=45, salary=8500, * status=BUSY)] */ } @Test public void test9() { DoubleSummaryStatistics dds = employees.stream() .collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println(dds.getMax()); System.out.println(dds.getAverage()); System.out.println(dds.getCount()); System.out.println(dds.getMin()); System.out.println(dds.getSum()); } // After obtaining the data, it can be used for splicing @Test public void test10() { String names1 = employees.stream() .map(Employee::getName) .distinct() .collect(Collectors.joining()); System.out.println(names1); // Zhang San Li Si Wang Wu Zhao Liu Tian Qi String names2 = employees.stream() .map(Employee::getName) .distinct() .collect(Collectors.joining(",")); System.out.println(names2); // Zhang San, Li Si, Wang Wu, Zhao Liu, Tian Qi String names3 = employees.stream() .map(Employee::getName) .distinct() .collect(Collectors.joining(",", "==", "==")); System.out.println(names3); // ==Zhang San, Li Si, Wang Wu, Zhao Liu, Tian Qi== }
3, Parallel stream and serial stream
The bottom layer of Java 8 is the ForkJoin framework, which is infinitely split and finally combined into one. Generally speaking, it is faster than serial flow
/** * @author G */ public class ForkJoinCalculate extends RecursiveTask<Long> { private Long start; private Long end; private static final long THRESHOLD = 10000; public ForkJoinCalculate(long start, long end) { this.start = start; this.end = end; } @Override protected Long compute() { long length = end - start; if (length <= THRESHOLD) { long sum = 0; for (long i = start; i <= end; i++) { sum += i; } return sum; } else { long middle = (start + end) / 2; ForkJoinCalculate left = new ForkJoinCalculate(start, middle); left.fork(); ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end); right.fork(); return left.join() + right.join(); } } } public class TestForkJoin { /** * ForkJoin frame */ @Test public void test1() { Instant start = Instant.now(); ForkJoinPool pool = new ForkJoinPool(); ForkJoinTask<Long> task = new ForkJoinCalculate(0, 100000000); Long sum = pool.invoke(task); System.out.println(sum); Instant end = Instant.now(); System.out.println("Time consuming:" + Duration.between(start, end).toMillis()); //133 } /** * Ordinary for */ @Test public void test2() { Instant start = Instant.now(); Long sum = 0L; for (long i = 0; i <= 100000000L; i++) { sum += i; } System.out.println(sum); Instant end = Instant.now(); System.out.println("Time consuming:" + Duration.between(start, end).toMillis()); //958 } /** * java8 Parallel stream */ @Test public void test3() { Instant start = Instant.now(); long sum = LongStream.rangeClosed(0, 100000000L) .parallel() .reduce(0, Long::sum); System.out.println(sum); Instant end = Instant.now(); System.out.println("Time consuming:" + Duration.between(start, end).toMillis()); // 220 } }
Optional container class
The optional class (java.util.Optional) is a container class that represents the existence or nonexistence of a value. Originally, null was used to indicate the nonexistence of a value. Now optional can better express this concept. And you can avoid null pointer exceptions.
- Optional. Of (T): create an optional instance
- Optional.empty(): create an empty optional instance
- Optional. Ofnullable (T): if t is not null, create an optional instance; otherwise, create an empty instance
- isPresent(): judge whether the value is included
- Orelse (T): if the calling object contains a value, return the value; otherwise, return t
- orElseGet(Supplier s): if the calling object contains a value, return the value; otherwise, return the value obtained by S
- map(Function f): if there is a value, process it and return the processed Optional. Otherwise, return Optional empty()
- flatMap(Function mapper): similar to map, the return value must be Optional
@Test public void test() { // Optional. Of (T): encapsulates an optional instance, where the value t cannot be null, otherwise there is a NullPointException Optional<Employee> optional1 = Optional.of(new Employee()); System.out.println(optional1.get()); // Running result: Employee{name='null', age=null, salary=null, status=null} // Optional.empty(): encapsulates an empty optional object (encapsulates null) Optional<Employee> optional2 = Optional.empty(); System.out.println(optional2.get()); // Running result: exception in thread "main" Java util. NoSuchElementException: No value present // at java.util.Optional.get(Optional.java:135) // at TestOptional.main(TestOptional.java:16) // Optional. Ofnullable (T): non null is the same as the of method, and null is the same as empty() Optional<Employee> optional3 = Optional.ofNullable(new Employee()); // isPresent(): judge whether it contains a value if (optional3.isPresent()) { System.out.println(optional3.get()); } // Running result: Employee{name='null', age=null, salary=null, status=null} // Orelse (T): returns a value if it contains a value; Otherwise, the alternative value t is returned Optional<Employee> optional4 = Optional.ofNullable(null); Employee Employee1 = optional4.orElse(new Employee(18, "Zhang San", 24, 12450, Employee.Status.FREE)); System.out.println(Employee1); // Running result: Employee{name = 'Zhang San', age=24, salary=15000.1, status=FREE} // orElseGet(Supplier s): returns a value if it contains a value; Otherwise, the value obtained by s is returned Employee Employee2 = optional4.orElseGet(() -> new Employee()); System.out.println(Employee2); // Running result: Employee{name='null', age=null, salary=null, status=null} // map(Function f): if there is a value, process it and return the processed Optional. Otherwise, return Optional empty() Optional<Employee> optional5 = Optional.ofNullable(new Employee(15, "Zhang San", 24, 38462, Employee.Status.FREE)); Optional<String> stringOptional1 = optional5.map(Employee::getName); System.out.println(stringOptional1.get()); // Operation result: Zhang San // flatMap(Function mapper): similar to map, the return value must be Optional Optional<String> stringOptional2 = optional5.flatMap(x -> Optional.of(x.getName())); System.out.println(stringOptional2.get()); // Operation result: Zhang San }