Lambda expressions & functional interfaces

1.1. What is a Lambda expression?

Lambda expressions can be understood as an anonymous substitute for functions that allow functions to be passed as arguments to a method, passing code as if it were data, with the goal of simplifying code writing.

1.2. What is a functional interface?

Lambda expressions require the support of a functional interface, which means that there is only one abstract method, and JDK8 also provides an annotation to help check syntax compliance at compile time

@FunctionInterface
Copy the code

1.3. Lambda expression use cases

Basic syntax for lambda expressions:

Function interface variable name = (parameter 1, parameter 2...) ->{// method body};Copy the code

Case 1: Method body has no parameter

	 //_____________ The first anonymous inner class _______________________
  Runnable runnable = new Runnable() {
      @Override
      public void run(a) {
          System.out.println("run----------"); }};new Thread(runnable).start();
  //_________ Second: the lambda expression ____________________

  Runnable runnable1 = ()->{
      System.out.println("Half Jane");
  };
  new Thread(runnable1).start();

 //_________ The third: fully simplified lambda expression ____________________
  new Thread(()->{
      System.out.println("All Jane");
  }).start();

  //_________ The fourth type: the super degenerate lambda expression ____________________
  new Thread(()-> System.out.println(Super simple)).start();
Copy the code

Case 2: Method body has parameters

 // Traditional mode
 Comparator<String> comparator = new Comparator<String>() {
     @Override
     public int compare(String o1, String o2) {
         returno1.length() - o2.length(); }}; TreeSet<String> treeSet =new TreeSet<>(comparator);

 / / lambda expressions
 Comparator<String> comparator1 = (o1,o2) -> o1.length() - o2.length();
 TreeSet<String> treeSet1 = new TreeSet<>(comparator1);

 // The simplest lambda expression
 TreeSet<String> treeSet2 = new TreeSet<>((o1,o2)-> o1.length() - o2.length());
Copy the code

1.4, Lambda expressions notes

Lambda introduces new operators :->(arrow operator), which splits the expression into two parts left: (argument 1, argument 2...) Represents a parameter list; 1. The data type of the parameter list is automatically inferred; 2. If the parameter list is empty, just leave (); 3. If the parameter has only one parameter, () can be omitted. If {} does not return a value, then {} must be omitted. If {} does return a value, then {} must be omitted. If {} does return a value, then {} must be omitted. Lambda does not generate a single inner class file; If a local variable is accessed by a lambda expression, the local variable must be final. If the local variable is not added with the final keyword, the system will add it automatically. After that, an error will be reported when the local variable is modified.Copy the code

2. Streaming programming -StreamAPI

2.1. What is a Stream?

Stream is an abstraction for dealing with arrays and collections in Java8. It can specify what you want to do with collections, and can perform very complex operations such as finding, filtering, and mapping data. Manipulating collection data using the Stream API is similar to database queries executed using SQL. A Stream is superficially similar to a collection that holds data, whereas a Stream sets up operations on that data. Stream features:

1. Stream does not store elements by itself. 2. Stream does not change the source object. Instead, they return a new Stream holding the result. 3. The Stream operation is delayed. This means they wait until they need results. Stream follows the "do, not how" principle. Just describe what needs to be done, regardless of how the program is implemented.Copy the code

2.2. Experience StreamAPI features quickly

public static void main(String[] args){ 
	List<String> data = new ArrayList<>();
	data.add("hello"); data.add("stream"); 
	data.add("good night!"); 
	// Traditional practice
	long count = 0; 
	for (String s : data) { 
            if (s.length()>3) { 
                count++; 
            } 
	}
	System.out.println(count); 
	//StreamAPI combines lambda expressions
	// chain programming
	long count2 = data.stream().filter(s->s.length()>3).count();
	System.out.println(count2); 
}

Copy the code

2.3, Steps to use StreamAPI

1. Create a Stream. 2. The intermediate operation of converting an initial Stream to another Stream in one or more steps. 3. Use a termination operation to produce a result. This operation forces his previous deferred operation to execute immediately. After that, the Stream is no longer used. (Terminate operation)Copy the code

2.4. How to create a Stream

I’ve already shown you how collections create streams and I’m going to add an array to that

int[] array = new int[] {1.2.3}; 
IntStream stream = Arrays.stream(array);
long result = stream.filter(i -> i > 1).count();
System.out.println(result);
Copy the code

2.5. Intermediate operation of Stream

2.5.1, Filter and Slice (filter,limit, Skip (n),distinct)

package com.hgz.jdk8; 
/ * * *@author huangguizhao */ 
public class Employee{ 
	private String name; 
	private int age; 
	private int salary;

	public Employee(String name, int age, int salary) { 
		this.name = name; 
		this.age = age; 
		this.salary = salary; 
	}
	public Employee(a) {}@Override 
	public String toString(a) { 
		return "Employee{" + "name='" + name + '\' ' + ", age=" + age + ", salary=" + salary + '} '; 
	}
	@Override 
	public boolean equals(Object obj) { 
		return true; 
	}
	@Override 
	public int hashCode(a) { 
		return 1; 
	}
	public String getName(a) { 
		return name; 
	}
	public void setName(String name) { 
		this.name = name; 
	}
	public int getAge(a) { 
		return age;
	}
	public void setAge(int age) { 
	this.age = age; 
	}
	public int getSalary(a) { 
		return salary; 
	}
	public void setSalary(int salary) { 
		this.salary = salary; }}Copy the code
public static void main(String[] args){ 
	List<Employee> employees = new ArrayList<>(); 
	employees.add(new Employee("zhangsan".20.8000)); 
	employees.add(new Employee("lisi".30.18000)); 
	employees.add(new Employee("wangwu".40.28000)); 
	employees.add(new Employee("wangwu".40.28000)); 
	/ / filter
	Stream<Employee> employeeStream = employees.stream().filter(e -> 
	 e.getAge() > 30); 
	employeeStream.forEach(t->System.out.print(t.getName())); 
	// get the first one
	Stream<Employee> limitStream = employees.stream().limit(1);  
	limitStream.forEach(System.out::println); 
	// Skip two
	Stream<Employee> skipStream = employees.stream().skip(2); 
	skipStream.forEach(System.out::println); 
	System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --"); 
	// Automatically call equals and hashcode
	Stream<Employee> distinctStream = employees.stream().distinct();
	distinctStream.forEach(System.out::println); 
}
Copy the code

2.5.2 Mapping

Object conversion

// map -- receive Lambda,
// Convert elements to other forms or extract information. Take as an argument a function that is applied to each element and mapped to a new element.
Stream<String> stringStream = employees.stream().map(e -> e.getName()); 
stringStream.forEach(System.out::println); 

// Convert lowercase to uppercase
List<String> list = Arrays.asList("a"."b"."c"); 
Stream<String> upperCaseStream = list.stream().map(String::toUpperCase); 
upperCaseStream.forEach(System.out::println);

Copy the code

2.5.3 Sorting (sorted)

System.out.println("------------- in natural order of age --------------"); 	
Stream<Integer> sortedStream = employees.stream().map(Employee::getAge).sorted(); 
sortedStream.forEach(System.out::println);
System.out.println("------------- custom sort ------------------------");
Stream<Employee> sortedStream2 = employees.stream().sorted((x, y) -> { 
    if (x.getAge() == y.getAge()) {
            return x.getName().compareTo(y.getName()); 
    } else { 
            returnx.getAge() - y.getAge(); }}); sortedStream2.forEach(System.out::println);Copy the code

2.6. Terminate the operation

2.6.1, Traversal operation

forEach

2.6.2. Find and match

  • AllMatch — Checks if all elements match
  • AnyMatch – Checks if at least one element matches
  • NoneMatch — Checks if there are no matching elements
  • FindFirst – Returns the first element
  • FindAny – Returns any element in the current stream
  • Count – Returns the total number of elements in the stream
  • Max – Returns the stream medium value
  • Min – Returns a small value for the stream
boolean b1 = employees.stream().allMatch(e -> e.getAge() > 30); 
boolean b2 = employees.stream().anyMatch(e -> e.getAge() > 30); Optional<Employee> max = employees.stream().max((x, y) -> x.getAge() - y.getAge()); 
System.out.println(b1); System.out.println(b2); System.out.println(max.get());
Copy the code

2.7, Serial and parallel of Stream

There are serial and parallel streams. Operations on a serial Stream are performed sequentially in one thread, while operations on a parallel Stream are performed simultaneously in multiple threads

Serial:

public static void main(String[] args){ 
        Int Max = 1000000;
        List<String> values = new ArrayList<>(max); 
        for (int i = 0; i < max; i++) { 
                UUID uuid = UUID.randomUUID(); 
                values.add(uuid.toString()); 
        }
        Long start = system.currentTimemillis ();
        long count = values.stream().sorted().count(); 
        System.out.println(count);
        long end = System.currentTimeMillis();
        long millis = end-start; System.out.println(millis);
}
Copy the code

parallel

// Parallel computation
long start = System.currentTimeMillis(); 
long count = values.parallelStream().sorted().count(); 
System.out.println(count); 
long end = System.currentTimeMillis();
long millis = end-start;
System.out.println(millis);
Copy the code