Java8 new features Lambda & Stream API

[TOC]

Lambda & Stream API

Both lambda and stream API are new features of Java8. First, let ’s briefly introduce java8

Java8 (jdk 1.8) is a major version of Java language development

Java8 was released by Oracle in March 2014 and can be regarded as the most revolutionary version since Java5.

Java 8 brings a lot of new features to the Java language, compilers, class libraries, development tools and JVM.

Introduction:

  • faster
  • Less code: add new syntax lambda expression
  • Powerful Stream API
  • Easy to parallel
  • Minimize the null pointer exception
  • Nashorn engine, allows running JS applications on the JVM

1 Lambda expression

1.1 Why use lambda expressions

Lambda is an anonymous function, we can understand the lambda expression as a piece of transferable code, that is, the code is transferred like data. Use it to write more concise and flexible code. As a more compact code style.

Let's first look at a simple case:

Requirements: Start a thread and output hello sky on the console

The following are implemented using three methods

  1. Implement the runnable interface
  • First define a class to implement the Runnable interface
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Hello sky !!!");
    }
}
  • transfer
//方式一 :实现runable接口
MyRunnable myRunable = new MyRunnable();
Thread t1 = new Thread(myRunable);
t1.start();
  1. Anonymous inner class
//方式二 :匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello sky !!!");
}
}).start();
  1. lambda expression
//方式三:lambda
new Thread(() -> System.out.println("Hello sky !!!")).start();

1.2 Lambda expression syntax

Introduces a new syntax elements and operators in Java8 language "->", the operator is called Lambda operator or the arrow operator . It divides Lambda into two parts

Left: Specify the parameter list required by the Lambda expression

On the right: The Lambda body is specified , which is the implementation logic of the abstract method, that is, the function to be performed by the Lambda expression.

//语法格式一:无参,无返回值
Runnable r = () -> {
    System.out.println("Hello Lambda !");
};

//语法格式二:一个参数 没有返回值
Consumer<String> con1 = (String str) -> {
    System.out.println(str);
};

//语法格式三:数据类型可以省略,可由编译器推断得出,称为 “类型推断”
Consumer<String> con2 = (str) -> {
    System.out.println(str);
};

//语法格式四:若只有一个参数,参数的小括号可以省略
Consumer<String> con3 = str -> {
    System.out.println(str);
};

//语法格式五:多个参数 并有返回值
Comparator<Integer> com = (x,y) -> {
    System.out.println("两个参数,有返回值");
    return Integer.compare(x,y);
};

//语法格式六:当只有一条语句时,return和{} 都可以省略
Comparator<Integer> com2 = (x,y) -> Integer.compare(x,y);

Type inference:

The parameter types in the above Lambda expressions are all inferred by the compiler. There is no need to specify the type in the Lambda expression, and the program can still be compiled. This is because javac infers the type of the parameter in the background according to the context of the program. The type inference of the Lambda expression depends on the context. According to the generic type specified in Consumer, it can be inferred that the parameter type is String.

1.3 Functional interface

1.3.1 What is a functional interface?

  • It contains only an abstract interface method, called function interface
  • You can create objects of this interface through Lambda expressions. (If the Lambda expression throws a checked exception (ie: a non-runtime exception), then the exception needs to be declared on the abstract method of the target interface).
  • We can use @FuntionalInterface annotation on an interface, so that we can check whether it is a functional interface.
  • The rich functional interface of Java 8 is defined under the java.util.function package

1.3.2 How to understand functional interfaces

  • Java has always advocated "everything is an object" since its birth. In Java, object-oriented (OOP) is everything. However, with the rise of languages ​​such as python and Scala and the challenges of new technologies, java has to make adjustments to support a wider range of technical requirements, that is, java can support not only OOP but also OOF (functional programming)
  • In functional programming languages, functions are treated as first-class citizens. In programming languages ​​that treat functions as first-class citizens, the type of Lambda expression is a function. But in Java 8, it is different. In Java 8, Lambda expressions are objects, not functions, they must be attached to a special type of object-a functional interface.
  • Simply put, in Java 8, a Lambda expression is an example of a functional interface. This is the relationship between Lambda expressions and functional interfaces. In other words, as long as an object is an instance of a functional interface, the object can be represented by a Lambda expression class
  • All previously expressed with anonymous function implementation classes can now be written with Lambda expressions

1.3.3 Define Functional Interface

  1. First look at a case in the source code, using the Runnable we used above as an example
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
  1. Custom functional interface
@FunctionalInterface
public interface MyInterface {
    int add(int a, int b);
}

note:

@FunctionalInterface The purpose of the annotation is to check whether this interface is a functional interface, it is not necessary to add this annotation

In idea, if the interface does not conform to the specifications of the functional interface, the editor will directly report an error

In Java 8, the methods in the interface can have a default implementation. The method modified by the default keyword is not an abstract method that must be implemented. This interface is also in accordance with the functional interface specification

/**
 * @Author sky
 * @Site cmtianxie163.com 2020/4/10 16:42
 */
@FunctionalInterface
public interface MyInterface {

    int add(int a, int b);

    default void test1(){}
}

1.3.4 The functional interface is passed as a parameter

/**
 * @Author sky
 * @Site cmtianxie163.com 2020/4/10 22:00
 */
public class LambdaTest4 {
    public static void main(String[] args) {
        happyMoney(100, m -> System.out.println("今天花了"+m));

        List<String> list = Arrays.asList("北京", "上海", "南京", "六安", "合肥", "东京");
        List<String> list1 = filterString2(list, s -> s.contains("京"));
        System.out.println(list1);
    }

    static void happyMoney(double money, Consumer<Double> con){
        con.accept(money);
    }

    static List<String> filterString(List<String> list, Predicate<String> pre){
        List<String> newlist = new ArrayList<>();
        for (String s : list) {
            if (pre.test(s)){
                newlist.add(s);
            }
        }
        return newlist;
    }

    static List<String> filterString2(List<String> list, Predicate<String> pre){
        List<String> newlist = new ArrayList<>();
        list.forEach(s -> {if (pre.test(s)){
            newlist.add(s);
        }});
        return newlist;
    }
}

Java four built-in core functional interface

Functional interface Parameter Type Return value type use
Consumer
Consumer interface
T void Apply operations to objects of type T, including methods: void accept (T t)
Supplier
Supply interface
no T Returns an object of type T, including method: T get ()
Function <T, R>
function interface
T R Apply operations to objects of type T and return the result. The result is an object of type R. Including method: R apply (T t)
Predicate
Determined interface
T boolean Determine whether an object of type T satisfies a constraint and return a boolean value. Including method: boolean test (T t)

Other interface

Functional interface Parameter Type Return type use
BiFunction<T,U,R> T,U R Apply operations to parameters of type T and U and return results of type R. The method of inclusion is: R apply (T t, U u);
UnaryOperator
(Function subinterface)
T T Perform unary operations on objects of type T and return results of type T. The method of inclusion is: T apply (T t);
BinaryOperator
(BiFunction subinterface)
T,T T Perform binary operations on objects of type T and return results of type T. The method of inclusion is: T apply (T t1, T t2);
BiConsumer<T,U> T,U void Apply operations to parameters of type T, U. The included method is: void accept (T t, U u)
BiPredicate<T,U> T,U boolean The included method is: boolean test (T t, U u)
ToIntFunction
ToLongFunction
ToDoubleFunction
T int
long
double
Function to calculate int, long and double values ​​separately
IntFunction
LongFunction
DoubleFunction
int
long
double
R Functions with parameters of type int, long, and double

1.4 Method references and constructor references

1.4.1 Method reference

  • When the operation to be passed to the Lambda body already has a method implemented, you can use the method reference
  • Method references can be seen as deep expressions of Lambda expressions. In other words, a method reference is a Lambda expression, that is, an instance of a functional interface. The method name refers to a method, which can be considered as a syntactic sugar for Lambda expressions.
  • Requirements: implement abstract methods of the interface parameter list and return type, the method must be referenced in the method parameter list and return type is consistent!
  • Format: Use the operator "::" to separate the class (or object) from the method name.
  • The following three main use cases:
    1. Object :: instance method name
    2. Class :: static method name
    3. Class :: instance method name

First define an Employee class and EmployeeData class (provide fake data)

package org.itsky.study.test2;
import com.sun.org.apache.xpath.internal.operations.Equals;
import java.util.Objects;

public class Employee {

	private int id;
	private String name;
	private int age;
	private double salary;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}

	public Employee() {
		System.out.println("Employee().....");
	}

	public Employee(int id) {
		this.id = id;
		System.out.println("Employee(int id).....");
	}

	public Employee(int id, String name) {
		this.id = id;
		this.name = name;
	}

	public Employee(int id, String name, int age, double salary) {

		this.id = id;
		this.name = name;
		this.age = age;
		this.salary = salary;
	}

	@Override
	public String toString() {
		return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}';
	}

	@Override
	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (o == null || getClass() != o.getClass())
			return false;

		Employee employee = (Employee) o;

		if (id != employee.id)
			return false;
		if (age != employee.age)
			return false;
		if (Double.compare(employee.salary, salary) != 0)
			return false;
		return name != null ? name.equals(employee.name) : employee.name == null;
	}




	@Override
	public int hashCode() {
		int result;
		long temp;
		result = id;
		result = 31 * result + (name != null ? name.hashCode() : 0);
		result = 31 * result + age;
		temp = Double.doubleToLongBits(salary);
		result = 31 * result + (int) (temp ^ (temp >>> 32));
		return result;
	}
}

public class EmployeeData {
	
	public static List<Employee> getEmployees(){
		List<Employee> list = new ArrayList<>();
		
		list.add(new Employee(1001, "鲁班七号", 34, 6000.38));
		list.add(new Employee(1002, "黄忠", 12, 9876.12));
		list.add(new Employee(1003, "孙尚香", 33, 3000.82));
		list.add(new Employee(1004, "后羿", 26, 7657.37));
		list.add(new Employee(1005, "成吉思汗", 65, 5555.32));
		list.add(new Employee(1006, "狄仁杰", 42, 9500.43));
		list.add(new Employee(1007, "伽罗", 26, 4333.32));
		list.add(new Employee(1008, "马可波罗", 35, 2500.32));
        list.add(new Employee(1008, "马可波罗", 35, 2500.32));
		
		return list;
	}
	
}

Method reference test code:

// 情况一:对象 :: 实例方法
	//Consumer中的void accept(T t)
	//PrintStream中的void println(T t)
	public static void test1() {
		Consumer<String> con1 = str -> System.out.println(str);
		con1.accept("北京");

		System.out.println("*******************");
		PrintStream ps = System.out;
		Consumer<String> con2 = ps::println;
		con2.accept("beijing");
	}
	
	//Supplier中的T get()
	//Employee中的String getName()
	public static void test2() {
		Employee emp = new Employee(1001,"Tom",23,5600);

		Supplier<String> sup1 = () -> emp.getName();
		System.out.println(sup1.get());

		System.out.println("*******************");
		Supplier<String> sup2 = emp::getName;
		System.out.println(sup2.get());

	}

	// 情况二:类 :: 静态方法
	//Comparator中的int compare(T t1,T t2)
	//Integer中的int compare(T t1,T t2)
	public static void test3() {
		Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
		System.out.println(com1.compare(12,21));

		System.out.println("*******************");

		Comparator<Integer> com2 = Integer::compare;
		System.out.println(com2.compare(12,3));

	}
	
	//Function中的R apply(T t)
	//Math中的Long round(Double d)
	public static void test4() {
		Function<Double,Long> func = new Function<Double, Long>() {
			@Override
			public Long apply(Double d) {
				return Math.round(d);
			}
		};

		System.out.println("*******************");

		Function<Double,Long> func1 = d -> Math.round(d);
		System.out.println(func1.apply(12.3));

		System.out.println("*******************");

		Function<Double,Long> func2 = Math::round;
		System.out.println(func2.apply(12.6));
	}

	// 情况三:类 :: 实例方法
	// Comparator中的int comapre(T t1,T t2)
	// String中的int t1.compareTo(t2)
	public static void test5() {
		Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
		System.out.println(com1.compare("abc","abd"));

		System.out.println("*******************");

		Comparator<String> com2 = String :: compareTo;
		System.out.println(com2.compare("abd","abm"));
	}

	//BiPredicate中的boolean test(T t1, T t2);
	//String中的boolean t1.equals(t2)
	public static void test6() {
		BiPredicate<String,String> pre1 = (s1,s2) -> s1.equals(s2);
		System.out.println(pre1.test("abc","abc"));

		System.out.println("*******************");
		BiPredicate<String,String> pre2 = String :: equals;
		System.out.println(pre2.test("abc","abd"));
	}
	
	// Function中的R apply(T t)
	// Employee中的String getName();
	public static void test7() {
		Employee employee = new Employee(1001, "Jerry", 23, 6000);


		Function<Employee,String> func1 = e -> e.getName();
		System.out.println(func1.apply(employee));

		System.out.println("*******************");


		Function<Employee,String> func2 = Employee::getName;
		System.out.println(func2.apply(employee));
	}

1.4.2 Constructor reference

Format: ClassName :: new

Combined with the functional interface, it is automatically compatible with the methods in the functional interface. You can assign a constructor reference to a defined method, requiring the constructor parameter list to be consistent with the parameter list of the abstract method in the interface! And the return value of the method is the object of the corresponding class of the constructor.

E.g:

Function<Integer,MyClass> fun = (n) → new MyClass(n);

Equivalent to:

Function<Integer,MyClass> fun = MyClass::new;

1.4.3 Array reference

Format: type [] :: new

E.g:

Function<Integer,Integer[]> fun = (n) → new Integer[n];

Equivalent to:

Function<Integer,Integer[]> fun = (n) → Integer[]::new;

//构造器引用
    //Supplier中的T get()
    //Employee的空参构造器:Employee()

    public static void test1(){

        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println("*******************");

        Supplier<Employee>  sup1 = () -> new Employee();
        System.out.println(sup1.get());

        System.out.println("*******************");

        Supplier<Employee>  sup2 = Employee :: new;
        System.out.println(sup2.get());
    }

    //Function中的R apply(T t)

    public static void test2(){
        Function<Integer,Employee> func1 = id -> new Employee(id);
        Employee employee = func1.apply(1001);
        System.out.println(employee);

        System.out.println("*******************");

        Function<Integer,Employee> func2 = Employee :: new;
        Employee employee1 = func2.apply(1002);
        System.out.println(employee1);

    }

    //BiFunction中的R apply(T t,U u)

    public static void test3(){
        BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);
        System.out.println(func1.apply(1001,"Tom"));

        System.out.println("*******************");

        BiFunction<Integer,String,Employee> func2 = Employee :: new;
        System.out.println(func2.apply(1002,"Tom"));

    }

    //数组引用
    //Function中的R apply(T t)

    public static void test4(){
        Function<Integer,String[]> func1 = length -> new String[length];
        String[] arr1 = func1.apply(5);
        System.out.println(Arrays.toString(arr1));

        System.out.println("*******************");

        Function<Integer,String[]> func2 = String[] :: new;
        String[] arr2 = func2.apply(10);
        System.out.println(Arrays.toString(arr2));

    }

2 Stream API

2.1 Stream API description

  • There are two most important changes in Java8. The first one is Lambda expression; the other one is Stream API
  • Stream API (java.util.stream) introduces true functional programming style to java. This is by far the best supplement to the Java class library, because the Stream API can greatly provide the productivity of Java programmers, allowing programmers to write efficient, clean, and concise code.
  • The Stream API is a key abstract concept for processing collections in Java 8. It can specify the operations you want to perform on the collection, and can perform very complex operations such as searching, filtering, and mapping data. Using the Stream API to operate on a collection is similar to a database query performed using SQL. You can also use the Stream API to perform operations in parallel. In short, the Stream API provides an efficient and easy-to-use way to process data.

2.2 Why use Stream API

  • In actual development, most data sources in the project come from Mysql, Oracle, etc. But now there are more data sources, such as MongoDB, Redis, etc., and these NoSQL data need to be processed at the Java level.
  • The difference between Stream and Collection:
    • Collection is a static memory data structure, and Stream is about calculation
    • The former is mainly for memory, stored in memory, and the latter is mainly for CPU, which is realized by CPU calculation.

2.3 What is Stream

Is a data channel, used to manipulate the sequence of elements generated by a data source (collection, array, etc.).

Collection is about data, Stream is about calculation

  • Stream itself does not store elements.
  • Stream itself does not change the source object. Instead, they will return a new Stream holding the result.
  • Stream operation is delayed. This means that they will wait until the results are needed.

2.4 Three steps of Stream operation

  1. Create Stream
  2. Intermediate operation
  3. Terminate operation

Once the termination operation is performed, the intermediate operation chain is executed and the result is produced. Will not be used again

2.4.1 Create Stream

  1. Create from collection

    • default Stream stream () returns a sequential stream
    • default Stream parallelStream () returns a parallel stream
    /**
     * @Author sky
     * @Site cmtianxie163.com 2020/4/13 10:24
     */
    public class StreamAPITest1 {
        public static void main(String[] args) {
            List<String> list = Arrays.asList("java","python","go");
    
            Stream<String> stream = list.stream();
            Stream<String> parallelStream = list.parallelStream();
    
            stream.forEach(s -> System.out.println(s));
            System.out.println("----------------------");
            parallelStream.forEach(s -> System.out.println(s));
        }
    }
    
  2. Create from array

    The static method stream () of Arrays in Java8 can get the array stream

    /**
         * Returns a sequential {@link Stream} with the specified array as its
         * source.
         *
         * @param <T> The type of the array elements
         * @param array The array, assumed to be unmodified during use
         * @return a {@code Stream} for the array
         * @since 1.8
         */
        public static <T> Stream<T> stream(T[] array) {
            return stream(array, 0, array.length);
        }
    

    Overloaded form, able to handle arrays corresponding to basic types:

    • public static IntStream stream(int[] array)
    • public static LongStream stream(long[] array)
    • public static DoubleStream stream(double[] array)
    int[] array1 = new int[]{1,2,3,4,5};
    IntStream intStream = Arrays.stream(array1);
    
    double[] array2 = new double[]{11,22,33,44};
    DoubleStream doubleStream = Arrays.stream(array2);
    
    intStream.forEach(s -> System.out.println(s));
    doubleStream.forEach(s -> System.out.prinln(s));
    
  3. By stream of ()

You can call the static method of () of the Stream class to create a stream by displaying values, which can receive any number of parameters.

  • public static Stream of(T t)
Stream<Object> objectStream = Stream.of("1", 1, 1.0, intStream);
objectStream.forEach(s -> System.out.println(s));
  1. Create an infinite stream

You can use the static methods Stream.iterate () and Stream.generate () to create infinite streams.

  • Iterate

    public static Stream iterate(final T seed, final UnaryOperator f)

  • Generate

    public static Stream generate(Supplier s)

//创建无限流
//从10开始 遍历前十个偶数
Stream<Integer> iterateStream = Stream.iterate(0, t -> t + 2).limit(10);
iterateStream.forEach(s -> System.out.println(s));

//生成
//生成十个随机数
Stream<Double> generateStream = Stream.generate(Math::random).limit(10);
generateStream.forEach(System.out::println);

2.4.2 Stream intermediate operations

A plurality of intermediate operations may be joined to form a pipeline, the pipeline operation unless the terminating trigger, as otherwise the operation does not perform any process, and at the end all of the processing operation performed one time, called lazy evaluation

2.4.2.1 Screening and slicing
method description
filter(Predicate p) Receive Lambda to exclude certain elements from the stream
distinct() Filter, remove the duplicate elements by hashCode () and equals () of the elements generated by the stream
limit(long maxSize) Truncate the stream so that its elements do not exceed the given number
skip(long n) Skip the 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)
List<Employee> list = EmployeeData.getEmployees();
//练习:查询员工表中薪资大于7000的员工信息
list.stream().filter(employee -> employee.getSalary()>7000).forEach(System.out::println);
System.out.println("-------------------");
//截断流,使其元素不超过给定数量
list.stream().limit(3).forEach(System.out::println);
System.out.println("-------------------");
//跳过元素,返回一个扔掉了前 n 个元素的流
list.stream().skip(3).forEach(System.out::println);
System.out.println("-------------------");
//筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
list.stream().distinct().forEach(System.out::println);
2.4.2.2 Mapping
method description
map(Function f) Receive a function as a parameter, the function will be applied to each element, and map it to a new element.
mapToDouble(ToDoubleFunction f) Receive a function as a parameter, the function will be applied to each element, a new DoubleStream is generated.
mapToInt(ToTIntFunction f) Receive a function as a parameter, the function will be applied to each element, a new IntStream is generated.
mapToLong (ToLongFunction f) Receive a function as a parameter, the function will be applied to each element, a new LongStream is generated.
flatMap(Function f) Receive a function as a parameter, replace each value in the stream with another stream, and then connect all the streams into one stream
List<String> list1 = Arrays.asList("aa", "bb", "cc", "dd", "ee");
list1.stream().skip(1).map(str -> str.toUpperCase()).forEach(System.out::println);
System.out.println("-------------------");
//获取员工姓名长度大于3的员工的姓名
list.stream().map(Employee::getName).filter(name -> name.length()>3).forEach(System.out::println);

Stream<Stream<Character>> streamStream = list1.stream().map(StreamAPITest2::fromStringToStream);
streamStream.forEach(System.out::println);
System.out.println("-------------------");
//flatMap
Stream<Character> characterStream = list1.stream().flatMap(StreamAPITest2::fromStringToStream);
characterStream.forEach(System.out::println);
//将字符串中的多个字符构成的集合转换为对应的Stream实例
public static Stream<Character> fromStringToStream(String str){
    ArrayList<Character> list = new ArrayList<>();
    for (Character c : str.toCharArray()) {
        list.add(c);
    }
    return list.stream();
}

flatMap has a similar example

If the list collection wants to add an element, the element itself is also a collection

  1. Elements are collections
  2. Equivalent to collection (elements) traversed first and then added to the collection one by one
ArrayList list1 = new ArrayList();
list1.add(1);
list1.add(2);
list1.add(3);

ArrayList list2 = new ArrayList();
list2.add(4);
list2.add(5);
list2.add(6);
//集合长度加一
//list1.add(list2);
//集合长度加三
list1.addAll(list2);
2.4.2.3 Sort
method description
sorted Produces a new stream, sorted in natural order
sorted(Comparator c) Generate a new stream, sorted in the order of the comparator
//自然排序
List<Integer> list2 = Arrays.asList(1,4,7,3,2,8,111,4);
list2.stream().sorted().forEach(System.out::println);
//定制排序
//安装年龄排序 年龄相同的再安装薪资排序
list.stream().sorted(((o1, o2) -> {
    int compare = Integer.compare(o1.getAge(), o2.getAge());
    if(compare == 0){
        return Double.compare(o1.getSalary(),o2.getSalary());
    }else{
        return compare;
    }
})).forEach(System.out::println);

2.4.3 Stream termination operation

  • The termination operation generates results from the pipeline. The result can be any value that is not a stream, such as: List, Integer, void
  • After the stream is terminated, it cannot be used again
2.4.3.1 Matching and searching
method description
allMatch(Predicate p) Check if all elements are matched
anyMatch(Predicate p) Check if at least one element is matched
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
count() 返回流中元素总数
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代, 称为外部迭代。相反,Stream API 使用内部迭 代——它帮你把迭代做了)
List<Employee> employees = EmployeeData.getEmployees();

//是否所有员工年龄都大于18
boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println(allMatch);
//是否存在员工姓 孙
boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("孙"));
System.out.println(noneMatch);
//返回第一个元素
Optional<Employee> first = employees.stream().findFirst();
Employee employee = first.get();
System.out.println(employee);
//返回当前流中的任意元素
Employee employee1 = employees.parallelStream().findAny().get();
System.out.println(employee1);

//返回流中元素总个数
long count = employees.stream().count();
System.out.println(count);
//返回最高工资
Stream<Double> doubleStream = employees.stream().map(e -> e.getSalary());
Double maxSalary = doubleStream.max(Double::compare).get();
System.out.println(maxSalary);
//返回最低工资的员工
Employee minSalaryEmp = employees.stream().min((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary())).get();
System.out.println(minSalaryEmp);
//内部迭代
employees.stream().forEach(System.out::println);
//集合遍历
employees.forEach(System.out::println);
2.4.3.2 规约
方法 描述
reduce(T iden, BInaryOperator b) 可以将流中的元素反复结合起来,得到一个值。返回T
reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一 个值。返回 Optional

map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。

//计算 1-10 的自然数之和
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);
//计算公司所有员工工资的总和
Optional<Double> sumSalary = employees.stream().map(e -> e.getSalary()).reduce((s1, s2) -> s1 + s2);
System.out.println(sumSalary.get());
2.4.3.3 收集
方法 描述
collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
//练习1:查找工资大于6000的员工,结果返回为一个List或Set

List<Employee> employees = EmployeeData.getEmployees();
List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());

employeeList.forEach(System.out::println);
System.out.println();
Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());

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

Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、 Map)。 另外, Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例, 具体方法与实例如下表:

方法 返回类型 作用
toList List 把流中元素收集到List
toSet Set 把流中元素收集到Set
toCollection Collection 把流中元素收集到创建的集合
counting Long 计算流中元素的个数
summingInt Integer 对流中元素的整数属性求和
averagingInt Double 计算流中元素Integer属性的平均值
summarizingInt IntSummaryStatistics 收集流中Integer属性的统计值。如:平 均值
joining String 连接流中每个字符串
maxBy Optional 根据比较器选择最大值
minBy Optional 根据比较器选择最小值
reducing 归约产生的类型 从一个作为累加器的初始值开始, 利用BinaryOperator与流中元素逐 个结合,从而归约成单个值
collectingAndThen 转换函数返回的类型 包裹另一个收集器,对其结果转 换函数
groupingBy Map<K,List > 根据某属性值对流分组,属性为K, 结果为V
partitioningBy Map<Boolean,List > 根据true或false进行分区
List<Employee> emps= list.stream().collect(Collectors.toList());
Set<Employee> emps= list.stream().collect(Collectors.toSet());
Collection<Employee> emps =list.stream().collect(Collectors.toCollection(ArrayList::new));
long count = list.stream().collect(Collectors.counting());
int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));
int SummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
String str= list.stream().map(Employee::getName).collect(Collectors.joining());
Optional<Emp>max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
Map<Emp.Status, List<Emp>> map= list.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
Map<Boolean,List<Emp>> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage));

Guess you like

Origin www.cnblogs.com/chengming104/p/12691408.html
Recommended