08. Learn Java's day25 [Java 8 new features: Lambda expression, stream API, etc.]

[what's new in Java 8]

primary coverage

  • Lambda expression
  • StreamAPI
  • Optional

Learning objectives

  • Understand the advantages of functional programming over object-oriented programming
  • Be able to master the standard format of Lambda expression
  • Ability to use Lambda standard format
  • Be able to master the ellipsis format and rules of Lambda expression
  • Ability to use custom interfaces (with and only one abstract method) through Lambda
  • Ability to use @ functional interface annotation
  • Ability to use the Supplier functional interface
  • Ability to use the Consumer functional interface
  • Function interface can be used
  • Ability to use the predict functional interface
  • Ability to use method references and constructor references
  • Be able to understand the advantages of flow compared with collection
  • Be able to understand the delayed execution characteristics of flow
  • Ability to get streams through collections, maps, or arrays
  • Ability to master common flow operations
  • The ability to wrap objects with Optional classes and get the objects wrapped in them

Chapter 18 what's new in Java 8

There are many new features of Java8. Before we learned the static and default methods of the interface when we were learning the interface, and the new version of the date time API when we were learning common classes. Today we're going to learn two of the most revolutionary new features of Java 8: Lambda expressions and the stream API. Then I will lead you to use the Optioanl class to solve the most annoying null pointer exception.

18.1 Lambda expression

18.1.1 functional programming idea

In mathematics, a function is a set of calculation scheme with input and output, that is, "what to do with". Functions in programming have similar concepts. When you call me, you assign parameters to parameters, and then run the method body to return a result to you. For callers, focus on what this approach does. Comparatively speaking, object-oriented overemphasizes that "things must be done in the form of objects", while functional thinking tries to ignore the complex syntax of object-oriented, which emphasizes what to do, rather than in what form.

  • Object oriented idea:

    • Do a thing, find an object that can solve the problem, call the method of the object, and finish the thing
  • Functional programming idea:

    • As long as we can get the results, it doesn't matter who does it or how. What we value is the results, not the process

With the introduction of Lambda expressions in Java 8, Java also began to support functional programming.

Lambda expressions are not the earliest used in Java. Many languages support lambda expressions, such as C + +, C ා, python, Scala, etc. If you have Python or Javascript language foundation, it is very helpful to understand lambda expression. It can be said that lambda expression is actually the syntactic sugar to implement SAM interface, which makes Java a functional programming language. Lambda's good writing can greatly reduce the code redundancy, and the readability is better than the lengthy anonymous inner class.

Note: "syntax sugar" refers to the code syntax that is more convenient to use, but the principle remains unchanged. For example, the for each syntax used when traversing a collection is
The underlying implementation principle is still iterator, which is "grammar sugar". At the application level, Lambda in Java can be regarded as anonymous internal
Class, but they are different in principle.

Redundant anonymous inner class

When you need to start a thread to complete a task, you usually define the task content through the java.lang.Runnable interface, and use the java.lang.Thread class to start the thread. The code is as follows:

public class Demo01Runnable {
	public static void main(String[] args) {
    	// Anonymous Inner Class 
		Runnable task = new Runnable() {
			@Override
			public void run() { // Override override abstract methods
				System.out.println("Multithreaded task execution!");
			}
		};
		new Thread(task).start(); // Startup thread
	}
}

Based on the idea of "everything is an object", this approach is indisputable: first, create an anonymous inner class object of Runnable interface to specify the task content, and then hand it to a thread to start.

Code analysis:

For the anonymous inner class usage of Runnable, we can analyze the following contents:

  • The Thread class needs the Runnable interface as a parameter, and the abstract run method is the core to specify the content of the Thread task;
  • In order to specify the method body of run, the implementation class of Runnable interface must be required;
  • In order to avoid the trouble of defining a RunnableImpl implementation class, we have to use anonymous inner class;
  • The abstract run method must be overridden and rewritten, so the method name, method parameter and method return value must be rewritten again, and cannot be wrong;
  • In fact, it seems that only the method body is the key.

Programming thought conversion

What to do, not who to do it, how to do it

Do we really want to create an anonymous inner class object? No We just had to create an object to do it. What we really want to do is pass the code inside the run method to the Thread class to know.

Passing a piece of code - that's what we really want. However, the creation of objects is only a way restricted by object-oriented syntax. So, is there a simpler way? If we return the focus from "how to do" to "what to do", we will find that as long as we can achieve the goal better, the process and form are not important.

Life example:

When we need to travel from Beijing to Shanghai, we can choose high-speed rail, car, cycling or hiking. Our real goal is to get to Shanghai, and the form of how to get to Shanghai is not important, so we have been exploring whether there is a better way than high-speed rail - by air.

Now this kind of aircraft (or even spaceship) has been born: in March 2014, Oracle released Java 8 (JDK 1.8), adding the heavyweight new features of Lambda expression, which opened the door of a new world for us.

Experience Lambda's better writing

With the new syntax of Java 8, the anonymous internal class writing method of the above Runnable interface can be equivalent through simpler Lambda expressions:

public class Demo02LambdaRunnable {
	public static void main(String[] args) {
		new Thread(() -> System.out.println("Multithreaded task execution!")).start(); // Startup thread
	}
}

The execution effect of this code is exactly the same as that of the previous one, which can be passed at compilation level of 1.8 or higher. From the semantics of the code, we can see that we start a thread, and the content of the thread task is specified in a more concise form.

There is no longer the shackle of "have to create interface object", no longer the burden of "abstract method override rewrite", it is so simple!

18.1.2 functional interface

lambda expression is actually the syntactic sugar to implement the SAM interface. The so-called Sam interface is the Single Abstract Method, that is, there is only one abstract method to be implemented in the interface, of course, the interface can contain other non abstract methods.

In fact, as long as the interface that meets the characteristics of "SAM" can be called a functional interface, Lambda expressions can be used, but if you want to be more specific, it's better to add @ functional interface when declaring the interface. Once the annotation is used to define the interface, the compiler will force to check whether the interface does have and only has one abstract method, otherwise an error will be reported.

Among the SAM interfaces that have been learned before, those marked with @ functional interface are: Runnable, Comparator, FileFilter.

Java 8 adds many functional interfaces in java.util.function, which are mainly divided into four categories: consumption type, supply type, judgment type and function type. It can basically meet our development needs. Of course, you can also define your own functional interface.

1. Custom functional interface

Just make sure there is only one abstract method in the interface:

Modifier interface interface name{
    public abstract return value type method name (optional parameter information);
    //Other non abstract method content
}

public abstract of abstract methods in interfaces can be omitted

For example: declare a Calculator calculator interface, which contains the abstract method calc to calculate two int numbers and return the result:

public interface Calculator {
    int calc(int a, int b);
}

In the test class, declare a method as follows:

    public static void invokeCalc(int a, int b, Calculator calculator) {
        int result = calculator.calc(a, b);
        System.out.println("The result is:" + result);
    }

Test as follows:

	public static void main(String[] args) {
		invokeCalc(1, 2, (int a,int b)-> {return a+b;});
		invokeCalc(1, 2, (int a,int b)-> {return a-b;});
		invokeCalc(1, 2, (int a,int b)-> {return a*b;});
		invokeCalc(1, 2, (int a,int b)-> {return a/b;});
		invokeCalc(1, 2, (int a,int b)-> {return a%b;});
		invokeCalc(1, 2, (int a,int b)-> {return a>b?a:b;});
	}

2. Consumer interface

Abstract method feature of consumption interface: parameter, but return value type is void

Interface name Abstract method describe
Consumer void accept(T t) Receive an object to complete the function
BiConsumer<T,U> void accept(T t, U u) Receive two objects to complete the function
DoubleConsumer void accept(double value) Receive a double value
IntConsumer void accept(int value) Receive an int value
LongConsumer void accept(long value) Receive a long value
ObjDoubleConsumer void accept(T t, double value) Receive an object and a double value
ObjIntConsumer void accept(T t, int value) Receive an object and an int value
ObjLongConsumer void accept(T t, long value) Receive an object and a long value

3. Supply type interface

Abstract method characteristics of this kind of interface: no parameter, but no return value

Interface name Abstract method describe
Supplier T get() Return an object
BooleanSupplier boolean getAsBoolean() Returns a boolean value
DoubleSupplier double getAsDouble() Return a double value
IntSupplier int getAsInt() Return an int value
LongSupplier long getAsLong() Returns a long value

4. Judgment interface

The abstract method feature of the interface here: there are parameters, but the return value type is a boolean result.

Interface name Abstract method describe
Predicate boolean test(T t) Receive an object
BiPredicate<T,U> boolean test(T t, U u) Receive two objects
DoublePredicate boolean test(double value) Receive a double value
IntPredicate boolean test(int value) Receive an int value
LongPredicate boolean test(long value) Receive a long value

5. Functional interface

Abstract method features of this kind of interface: both parameters and return values

Interface name Abstract method describe
Function<T,R> R apply(T t) Receive a T type object and return a R type object result
UnaryOperator T apply(T t) Receive a T type object and return a T type object result
DoubleFunction R apply(double value) Receive a double value and return an object of type R
IntFunction R apply(int value) Receive an int value and return an object of type R
LongFunction R apply(long value) Receive a long value and return an object of type R
ToDoubleFunction double applyAsDouble(T value) Receive a T type object and return a double
ToIntFunction int applyAsInt(T value) Receive an object of type T, return an int
ToLongFunction long applyAsLong(T value) Receive a T type object, return a long
DoubleToIntFunction int applyAsInt(double value) Receive a double value and return an int result
DoubleToLongFunction long applyAsLong(double value) Receive a double value and return a long result
IntToDoubleFunction double applyAsDouble(int value) Receive an int value and return a double result
IntToLongFunction long applyAsLong(int value) Receive an int value and return a long result
LongToDoubleFunction double applyAsDouble(long value) Receive a long value and return a double result
LongToIntFunction int applyAsInt(long value) Receive a long value and return an int result
DoubleUnaryOperator double applyAsDouble(double operand) Receive a double value and return a double
IntUnaryOperator int applyAsInt(int operand) Receive an int value and return an int result
LongUnaryOperator long applyAsLong(long operand) Receive a long value and return a long result
BiFunction<T,U,R> R apply(T t, U u) Receive a T type and a U type object, and return an R type object result
BinaryOperator T apply(T t, T u) Receive two T-type objects and return one T-type object result
ToDoubleBiFunction<T,U> double applyAsDouble(T t, U u) Receive a T type and a U type object, return a double
ToIntBiFunction<T,U> int applyAsInt(T t, U u) Receive a T type and a U type object, return an int
ToLongBiFunction<T,U> long applyAsLong(T t, U u) Receive a T type and a U type object, return a long
DoubleBinaryOperator double applyAsDouble(double left, double right) Receive two double values and return a double result
IntBinaryOperator int applyAsInt(int left, int right) Receive two int values and return an int result
LongBinaryOperator long applyAsLong(long left, long right) Receive two long values and return a long result

18.1.3 Lambda expression syntax

Lambda expressions are used to assign values to variables or parameters of [functional interface].

In essence, Lambda expressions are "abstract methods" used to implement [functional interfaces]

Lambda expression syntax format

(parameter list) - > {lambda body}

Explain:

  • (parameter list) it is the abstract method of the functional interface you want to assign (parameter list). Copy it
  • The {Lambda body} is the method body that implements this abstract method
  • ->It is called Lambda operator (there must be no space between the minus sign and the greater sign, and it must be the half angle input mode in English)

Optimization: Lambda expressions can be streamlined

  • When there is only one statement in {Lambda body}, you can omit {} and {;}
  • When there is only one statement in {Lambda body}, and the statement is still a return statement, return can also be omitted, but if {;} is not omitted, return cannot be omitted
  • The type of (parameter list) can be omitted
  • When there is only one parameter number (parameter list), the data type and () can be omitted together, but the parameter name cannot be omitted
  • () cannot be omitted when (parameter list) is empty

Example code:

public class TestLambdaGrammer {
	@Test
	public void test1(){
		//Using Lambda expression to assign value to parameter or variable of Runnable interface
		/*
		 * To write a lambda expression, you need to determine two things
		 * (1)What are the abstract methods of this interface
		 * 		public void run()
		 * (2)What does the implementation of this abstract method do
		 * 		For example: I want to print "hello lambda“
		 */
		Runnable r = () -> {System.out.println("hello lambda");};
	}
	
	@Test
	public void test2(){
		//The lambda body omits {;}
		Runnable r = () -> System.out.println("hello lambda");
	}
	
	@Test
	public void test3(){
		String[] arr = {"hello","Hello","java","chai"};
		
		//Sort the arr array, but you want to be case insensitive
		/*
		 * public static <T> void sort(T[] a,Comparator<? super T> c)
		 * Here we use Lambda expressions to assign values to parameters of type Comparator
		 * 
		 * Two things:
		 * (1)The abstract method of this interface: int compare(T o1, T o2)
		 * (2)What does this abstract method do?
		 * 		For example: Here we want to compare case insensitive elements of String type
		 */
//		Arrays.sort(arr, (String o1, String o2) -> {return o1.compareToIgnoreCase(o2);});
		
		//Omitted {return;}
//		Arrays.sort(arr, (String o1, String o2) ->  o1.compareToIgnoreCase(o2));
		
		//Two strings are omitted
		Arrays.sort(arr, (o1, o2) ->  o1.compareToIgnoreCase(o2));
		
		for (String string : arr) {
			System.out.println(string);
		}
	}
	
	@Test
	public void test4(){
		ArrayList<String> list = new ArrayList<>();
		list.add("hello");
		list.add("java");
		list.add("world");
		
		/*
		 * JDK1.8 For Collection series, a default method is added to the Iterable interface
		 * 		default void forEach(Consumer<? super T> action) 
		 * This method is used to traverse sets, etc. Instead of the original foreach loop.
		 * 
		 * The parameter of this method is the Consumer interface type, which is the representative of the Consumer interface in the functional interface
		 * I call this method now. I want to use Lambda expression to assign value to parameter of Consumer interface type
		 * 
		 * Two things:
		 * (1)Its abstract method: void accept (t t t)
		 * (2)What is the implementation of abstract methods to accomplish
		 * 		For example: to print this t
		 */
//		list.forEach((String t) -> {System.out.println(t);});
		
		//Ellipsis {;}
//		list.forEach((String t) -> System.out.println(t));
		
		//Ellipsis String
//		list.forEach((t) -> System.out.println(t));
		
		//You can omit the parameter ()
		list.forEach(t -> System.out.println(t));
	}
}

18.1.4 Lambda expression exercise

Exercise 1: no parameter no return value form

If there is a custom functional interface Call, it is as follows:

public interface Call {
    void shout();
}

Declare a method in the test class as follows:

public static void callSomething(Call call){
		call.shout();
	}

The callSomething method is called in the main method of the test class, and the Lambda expression is used to assign the parameter call, so you can shout whatever you want to say.

public class TestLambda {
	public static void main(String[] args) {
		callSomething(()->System.out.println("Go home for dinner"));
		callSomething(()->System.out.println("I love you!"));
		callSomething(()->System.out.println("Rats, screw you"));
		callSomething(()->System.out.println("come back"));
	}
	public static void callSomething(Call call){
		call.shout();
	}
}
interface Call {
    void shout();
}

Exercise 2: consumer interface

Code example: Consumer interface

In JDK 1.8, a default method is added to the Iterable interface, the parent interface of the Collection interface:

Public default void foreach (consumer <? Super T > action) traverses each element of the Collection collection to perform the "xxx consumption type" operation.

A default method is added to the Map collection interface in JDK 1.8:

Public default void foreach (biconsumer <? Super K,? Super V > action) traverses each pair of mapping relationships in the Map set, and performs "xxx consumption type" operations.

Case study:

(1) Create a Collection of Collection series, add the programming language you know, call forEach method to traverse and view

(2) Create a set of Map series, add some (key,value) key value pairs, for example, add programming language ranking and language name, call forEach method to traverse and view

Example code:

	@Test
	public void test1(){
		List<String> list = Arrays.asList("java","c","python","c++","VB","C#");
		list.forEach(s -> System.out.println(s));
    }
	@Test
	public void test2(){
		HashMap<Integer,String> map = new HashMap<>();
		map.put(1, "java");
		map.put(2, "c");
		map.put(3, "python");
		map.put(4, "c++");
        map.put(5, "VB");
        map.put(6, "C#");
		map.forEach((k,v) -> System.out.println(k+"->"+v));
	}

Exercise 3: supply interface

Code example: Supplier interface

The stream API is added in JDK 1.8, and java.util.stream.Stream is a data stream. This type has a static method:

Public static < T > Stream < T > generate (supplier < T > s) can create Stream objects. It also contains a forEach method to traverse the elements in the flow: public void forEach (consumer <? Super T > action).

Case study:

Now call the generate method of Stream to generate a Stream object, and call the Math.random() method to generate data and assign values to the parameters of the Supplier functional interface. Finally, the forEach method is called to traverse the data in the Stream to see the result.

	@Test
	public void test2(){
		Stream.generate(() -> Math.random()).forEach(num -> System.out.println(num));
	}

Exercise 4: functional interface

Code example: function < T, R > interface

In JDK 1.8, many methods are added to the Map interface, such as:

Public default void replaceall (bifunction <? Super K,? Super V,? Extends V > function) replaces the value in the map according to the operation specified in function.

Public default void foreach (biconsumer <? Super K,? Super V > action) traverses each pair of mapping relationships in the Map set, and performs "xxx consumption type" operations.

Case study:

(1) Declare an Employee type, including number, name and salary.

(2) Add n employee objects to a HashMap < integer, employee > collection, where employee number is key and employee object is value.

(3) Call the forEach traversal set of Map

(4) Call the replaceAll method of Map, and set the salary of those whose salary is less than 10000 yuan to 10000 yuan.

(5) Call forEach of Map again to traverse the collection to view the result

Employee class:

class Employee{
	private int id;
	private String name;
	private double salary;
	public Employee(int id, String name, double salary) {
		super();
		this.id = id;
		this.name = name;
		this.salary = salary;
	}
	public Employee() {
		super();
	}
	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 double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
	}
	
}

Test class:

import java.util.HashMap;

public class TestLambda {
	public static void main(String[] args) {
		HashMap<Integer,Employee> map = new HashMap<>();
		Employee e1 = new Employee(1, "Zhang San", 8000);
		Employee e2 = new Employee(2, "Li Si", 9000);
		Employee e3 = new Employee(3, "Wang Wu", 10000);
		Employee e4 = new Employee(4, "Zhao Liu", 11000);
		Employee e5 = new Employee(5, "Money seven", 12000);
		
		map.put(e1.getId(), e1);
		map.put(e2.getId(), e2);
		map.put(e3.getId(), e3);
		map.put(e4.getId(), e4);
		map.put(e5.getId(), e5);
		
		map.forEach((k,v) -> System.out.println(k+"="+v));
		System.out.println();
		
		map.replaceAll((k,v)->{
			if(v.getSalary()<10000){
				v.setSalary(10000);
			}
			return v;
		});
		map.forEach((k,v) -> System.out.println(k+"="+v));
	}
}

Exercise 5: judgment interface

Code example: Predicate interface

In JDK1.8, the following methods are added to the collector interface, one of which is as follows:

Public default Boolean removeif (predicate <? Super E > filter) is used to delete a collection that meets the criteria specified by the filter.

Public default void foreach (consumer <? Super T > action) traverses each element of the Collection collection to perform the "xxx consumption type" operation.

Case study:

(1) Add some strings to a Collection

(2) Call forEach to traverse the collection

(3) Call the removeIf method to delete the

(4) Call forEach again to traverse the collection

import java.util.ArrayList;

public class TestLambda {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("hello");
		list.add("java");
		list.add("atguigu");
		list.add("ok");
		list.add("yes");
		
		list.forEach(str->System.out.println(str));
		System.out.println();
		
		list.removeIf(str->str.length()<5);
		list.forEach(str->System.out.println(str));
	}
}

Exercise 6: judgment interface

Case study:

(1) Declare an Employee type, including number, name, gender, age, and salary.

(2) Declare an employeeservice employee management class, which contains the property all of the ArrayList collection. In the constructor of employeeservice, create some employee objects to initialize for the all collection.

(3) In the employeservice employee management class, declare a method: ArrayList get (predict p), that is, add the employees who meet the conditions specified by p to a new ArrayList collection to return.

(4) Create the object of employeeservice employee management class in the test class, and call get method to get:

  • All employee objects
  • All employees over 35
  • All female employees with salaries above 15000
  • All employees with even numbers
  • The employee whose name is "Zhang San"
  • Male employees over 25 and under 10000

Example code:

Employee class:

public class Employee{
	private int id;
	private String name;
	private char gender;
	private int age;
	private double salary;
	
	public Employee(int id, String name, char gender, int age, double salary) {
		super();
		this.id = id;
		this.name = name;
		this.gender = gender;
		this.age = age;
		this.salary = salary;
	}
	public Employee() {
		super();
	}
	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 double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", salary=" + salary
				+ "]";
	}
}

Employee management:

class EmployeeService{
	private ArrayList<Employee> all;
	public EmployeeService(){
		all = new ArrayList<Employee>();
		all.add(new Employee(1, "Zhang San", 'male', 33, 8000));
		all.add(new Employee(2, "Cui Hua", 'female', 23, 18000));
		all.add(new Employee(3, "You're incompetent", 'male', 46, 8000));
		all.add(new Employee(4, "Li Si", 'female', 23, 9000));
		all.add(new Employee(5, "Lao Wang", 'male', 23, 15000));
		all.add(new Employee(6, "Big mouth", 'male', 23, 11000));
	}
	public ArrayList<Employee> get(Predicate<Employee> p){
		ArrayList<Employee> result = new ArrayList<Employee>();
		for (Employee emp : all) {
			if(p.test(emp)){
				result.add(emp);
			}
		}
		return result;
	}
}

Test class:

public class TestLambda {
	public static void main(String[] args) {
		EmployeeService es = new EmployeeService();
		
		es.get(e -> true).forEach(e->System.out.println(e));
		System.out.println();
		es.get(e -> e.getAge()>35).forEach(e->System.out.println(e));
		System.out.println();
		es.get(e -> e.getSalary()>15000 && e.getGender()=='female').forEach(e->System.out.println(e));
		System.out.println();
		es.get(e -> e.getId()%2==0).forEach(e->System.out.println(e));
		System.out.println();
		es.get(e -> "Zhang San".equals(e.getName())).forEach(e->System.out.println(e));
		System.out.println();
		es.get(e -> e.getAge()>25 && e.getSalary()<10000 && e.getGender()=='male').forEach(e->System.out.println(e));
	}
}

18.1.3 method reference and constructor reference

Lambda expression is a syntax that can simplify the assignment of variables and parameters of functional interface. Method references and constructor references are used to simplify lambda expressions. When lambda expressions meet some special conditions, they can also be simplified:

(1) The body of a Lambda has only one statement and is done by calling an existing method of an object's / class

For example: System.out object, call println() method to complete Lambda body

The Math class calls the random() static method to complete the Lambda body

(2) And the parameter of Lambda expression is exactly the parameter given to the method

For example: T - > system.out.println (T)

() - > math. Random() are all parameterless

Method reference

Syntax format of method reference:

(1) Instance object name:: instance method

(2) Class name:: static method

(3) Class name:: instance method

Explain:

  • :: called method reference operator (two: no space in the middle, and half angle input in English)
  • The parameter list of Lambda expression is all used in the body of Lambda, either as the object calling the method or as the argument of the method.
  • There is no additional data in the whole Lambda body.
	
	@Test
	public void test4(){
//		Runnable r = () -> System.out.println("hello lambda");
		Runnable r = System.out::println;//Print blank line
		
		//Method references cannot be simplified because "hello lambda" cannot be omitted
	}
	
	@Test
	public void test3(){
		String[] arr = {"Hello","java","chai"};
//		Arrays.sort(arr, (s1,s2) -> s1.compareToIgnoreCase(s2));
		
		//Simplify with method reference
		/*
		 * Lambda The parameter of the expression, the first (for example: s1), is exactly the object calling the method, and the remaining parameter (for example: s2) is exactly the parameter given to the method
		 */
		Arrays.sort(arr, String::compareToIgnoreCase);
	}
	
	@Test
	public void test2(){
//		Stream<Double> stream = Stream.generate(() -> Math.random());
		
		//Simplify with method reference
		Stream<Double> stream = Stream.generate(Math::random);
	}
	
	@Test
	public void test1(){
		List<Integer> list = Arrays.asList(1,3,4,8,9);
		
		//list.forEach(t -> System.out.println(t));
		
		//Simplify again with method
		list.forEach(System.out::println);
	}

Constructor reference

(1) When the Lambda expression is to create an object and satisfy the Lambda expression parameters, it is exactly the argument list for the constructor that creates the object.

(2) When the Lambda expression is to create an array object and satisfy the Lambda expression parameters, it is exactly the length of the array object to be created

Syntax format of constructor reference:

  • Class name: new
  • Array type name:: new

Example code:

public class TestMethodReference {
    @Test
	public void teset04() {
		Stream<Integer> stream = Stream.of(1,2,3);
		Stream<int[]> map = stream.map(int[]::new);
	}
    
	
	//This method is to imitate the code in HashMap that corrects the length of the array you specified to the nth power of 2
	//The purpose of createArray() is to create an array with length of 2 to the nth power
	public <R> R[] createArray(Function<Integer,R[]> fun,int length){
		int n = length - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        length = n < 0 ? 1 : n + 1;
		return fun.apply(length);
	}
	
	@Test
	public void test3(){
		/*
		 * Function It is a functional interface, which can be assigned with Lambda expression
		 * Function<T,R>R apply (t t t)
		 * 
		 * createArray In this method, function < Integer, R [] > fun is used. Description type T has been specified as Integer
		 * Explain
		 */
//		Function<Integer,String[]> f = (Integer len) -> new String[len];
		
		//Because the Lambda body is created by creating an array object, and the parameter of the Lambda expression is exactly the length used to create the array
		//Omitted by constructor reference
		Function<Integer,String[]> f = String[]::new;
		String[] array = createArray(f, 10);
		
		System.out.println(array.length);//16
	}
       
    
    @Test
	public void teset02() {
		Stream<String> stream = Stream.of("1.0","2.3","4.4");
		
//		Stream<BigDecimal> stream2 = stream.map(num -> new BigDecimal(num));
		
		Stream<BigDecimal> stream2 = stream.map(BigDecimal::new);
	}
	
	@Test
	public void test1(){
//		Supplier < string > s = () - > New string(); / / provide an empty string object through the supply type interface
		
		//Constructor reference
		Supplier<String> s = String::new;//Provide an empty string object through the supply interface
	}

}

18.2 StreamAPI

There are two most important changes in Java 8. The first is a Lambda expression; the other is the Stream API.

The Stream API (Java. Util. Stream) introduces the real functional programming style into Java. This is the best supplement to Java class library so far, because Stream API can greatly improve the productivity of Java programmers and let them write efficient, clean and concise code.

Stream is a key abstract concept in Java 8 to deal with collections. It can specify the operations you want to perform on collections, and can perform very complex operations such as finding, filtering, and mapping data. Using Stream API to operate on collection data is similar to database query 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.

Stream is a data channel used to manipulate the sequence of elements generated by data sources (sets, arrays, etc.). "Collection is about data, storing data, stream is about calculation, processing data!"

Be careful:

① Stream itself does not store elements.

② Stream does not change the source object. Each processing returns a new stream holding the result.

③ Stream operations are deferred. This means that they wait until they need results to execute.

There are three steps for Stream operation:

1 - create Stream: obtain a Stream through a data source (such as a collection or an array)

2 - intermediate operation: the intermediate operation is an operation chain, which processes the data of the data source n times, but does not really execute before the operation is terminated.

3-terminate operation: once the terminate operation is performed, the intermediate operation chain is executed, and the result is finally generated and the Stream is ended.

17.2.1 create Stream

1. Create Stream mode 1: through collection

The Collection interface in Java8 is extended to provide two ways to get streams:

  • public default Stream stream(): returns a sequential stream

  • public default Stream parallelStream(): returns a parallel stream

2. Create Stream mode 2: through array

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

  • Public static stream stream (t [] array): returns a stream

Overloaded form, which can handle arrays of corresponding basic types:

  • Public static int stream stream (int [] array): returns an integer data stream
  • Public static long stream stream (long [] array): returns a long integer data stream
  • Public static doublestrream stream (double [] array): returns a floating-point data stream

3. Create Stream mode 3: through of()

You can call the Stream class static method of() to create a Stream by displaying the value. It can receive any number of parameters.

  • public static Stream of(T… values): returns a sequential flow

4. Create Stream mode 4: create infinite Stream

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

  • public static Stream iterate(final T seed, final UnaryOperator f): returns an infinite stream
  • public static Stream generate(Supplier s): returns an infinite stream
package com.atguigu.test06;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import org.junit.Test;

public class Test07StreamCreate {
	@Test
	public void test06(){
		/*
		 * Stream<T> iterate(T seed, UnaryOperator<T> f)  
		 * UnaryOperator Interface, SAM interface, abstract method:
		 * 
		 * UnaryOperator<T> extends Function<T,T>
		 * 		T apply(T t)
		 */
		Stream<Integer> stream = Stream.iterate(1, num -> num+=2);
//		stream = stream.limit(10);
		stream.forEach(System.out::println);
	}
	
	@Test
	public void test05(){
		Stream<Double> stream = Stream.generate(Math::random);
		stream.forEach(System.out::println);
	}
	
	@Test
	public void test04(){
		Stream<Integer> stream = Stream.of(1,2,3,4,5);
		stream.forEach(System.out::println);
	}
	
	@Test
	public void test03(){
		String[] arr = {"hello","world"};
		Stream<String> stream = Arrays.stream(arr);
	}
	
	@Test
	public void test02(){
		int[] arr = {1,2,3,4,5};
		IntStream stream = Arrays.stream(arr);
	}
	
	@Test
	public void test01(){
		List<Integer> list = Arrays.asList(1,2,3,4,5);
		
		//In JDK 1.8, Collection series Collection adds methods
		Stream<Integer> stream = list.stream();
	}
}

17.2.2 intermediate operation

Multiple intermediate operations can be connected to form a pipeline. Unless the pipeline triggers the termination operation, the intermediate operation will not perform any processing! When the operation is terminated, all of them are processed at one time, which is called "lazy evaluation".

Method Description
filter(Predicate p) Receive Lambda, exclude some elements from the stream
distinct() Filtering, removing duplicate elements through equals() of the elements generated by the stream
limit(long maxSize) Truncate the flow so that its elements do not exceed the given number
skip(long n) Skip elements and return a stream that discards the first n elements. If there are less than n elements in the stream, an empty stream is returned. Complementary to limit(n)
peek(Consumer action) Receive Lambda and perform Lambda body operation for each data in the flow
sorted() Generates a new stream, which is ordered in natural order
sorted(Comparator com) Generates a new stream, sorted in comparator order
map(Function f) Receives a function as an argument that is applied to each element and mapped to a new element.
mapToDouble(ToDoubleFunction f) Receives a function as an argument that is applied to each element to produce a new doublestrream.
mapToInt(ToIntFunction f) Receives a function as an argument that is applied to each element to produce a new IntStream.
mapToLong(ToLongFunction f) Receives a function as an argument that is applied to each element to produce a new LongStream.
flatMap(Function f) Take a function as a parameter, change each value in the flow into another flow, and then connect all flows into one flow
package com.atguigu.test06;

import java.util.Arrays;
import java.util.stream.Stream;

import org.junit.Test;

public class Test08StreamMiddle {
	
	@Test
	public void test12(){
		String[] arr = {"hello","world","java"};
		Arrays.stream(arr)
			.flatMap(t -> Stream.of(t.split("|")))//Function < T, R > interface Abstract Method R apply (t t t) now R is a Stream
			.forEach(System.out::println);
	}
	
	
	@Test
	public void test11(){
		String[] arr = {"hello","world","java"};
		
		Arrays.stream(arr)
			.map(t->t.toUpperCase())
			.forEach(System.out::println);
	}
	
	@Test
	public void test10(){
		Stream.of(1,2,3,4,5)
			.map(t -> t+=1)//Function < T, R > interface Abstract Method R apply (t t t)
			.forEach(System.out::println);
	}
	
	@Test
	public void test09(){
		//Hope to find out the top three maximums, the top three maximums, and do not repeat
		Stream.of(11,2,39,4,54,6,2,22,3,3,4,54,54)
			.distinct()
			.sorted((t1,t2) -> -Integer.compare(t1, t2))//Comparator interface int compare(T t1, T t2)
			.limit(3)
			.forEach(System.out::println);
	}
	
	@Test
	public void test08(){
		long count = Stream.of(1,2,3,4,5,6,2,2,3,3,4,4,5)
			.distinct()
			.peek(System.out::println)  //The abstract method void accept (t t t) of the Consumer interface
			.count();
		System.out.println("count="+count);
	}
	
	
	@Test
	public void test07(){
		Stream.of(1,2,3,4,5,6,2,2,3,3,4,4,5)
			.skip(5)
			.distinct()
			.filter(t -> t%3==0)
			.forEach(System.out::println);
	}

	@Test
	public void test06(){
		Stream.of(1,2,3,4,5,6,2,2,3,3,4,4,5)
			.skip(5)
			.forEach(System.out::println);
	}
	
	@Test
	public void test05(){
		Stream.of(1,2,2,3,3,4,4,5,2,3,4,5,6,7)
			.distinct()  //(1,2,3,4,5,6,7)
			.filter(t -> t%2!=0) //(1,3,5,7)
			.limit(3)
			.forEach(System.out::println);
	}
	
	
	@Test
	public void test04(){
		Stream.of(1,2,3,4,5,6,2,2,3,3,4,4,5)
			.limit(3)
			.forEach(System.out::println);
	}
	
	
	@Test
	public void test03(){
		Stream.of(1,2,3,4,5,6,2,2,3,3,4,4,5)
			.distinct()
			.forEach(System.out::println);
	}
	
	
	@Test
	public void test02(){
		Stream.of(1,2,3,4,5,6)
			.filter(t -> t%2==0)
			.forEach(System.out::println);
	}
	
	@Test
	public void test01(){
		//1. Create Stream
		Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
		
		//2. Processing
		//Filter (predict P)
		//Take the even number out of it
		/*
		 * filter(Predicate p)
		 * Predicate Is a functional interface, abstract method: boolean test(T t)
		 */
		stream = stream.filter(t -> t%2==0);
		
		//3. End operation: for example: traversal
		stream.forEach(System.out::println);
	}
}

17.2.3 end operation

Terminal operations generate results from the flow's pipeline. The result can be any value that is not a stream, such as List, Integer, or even void. After the stream has been terminated, it cannot be used again.

Method describe
boolean allMatch(Predicate p) Check to see if all elements match
boolean anyMatch(Predicate p) Check to see if at least one element matches
boolean noneMatch(Predicate p) Check if not all elements match
Optional findFirst() Returns the first element
Optional findAny() Returns any element in the current stream
long count() Total number of elements in the return stream
Optional max(Comparator c) Returns the maximum value in the stream
Optional min(Comparator c) Minimum value in return flow
void forEach(Consumer c) iteration
T reduce(T iden, BinaryOperator b) You can combine elements in the flow repeatedly to get a value. Return to T
U reduce(BinaryOperator b) You can combine elements in the flow repeatedly to get a value. Back to Optional
R collect(Collector c) Convert the flow to another form. Receive the implementation of a Collector interface to summarize the elements in the Stream

The implementation of the methods in the Collector interface determines how collection operations (such as List, Set, Map) are performed on the stream. In addition, the Collectors utility class provides many static methods to easily create common Collector instances.

package com.atguigu.test06;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

public class Test09StreamEnding {
	
	@Test
	public void test14(){
		List<Integer> list = Stream.of(1,2,4,5,7,8)
				.filter(t -> t%2==0)
				.collect(Collectors.toList());
		
		System.out.println(list);
	}
	
	
	@Test
	public void test13(){
		Optional<Integer> max = Stream.of(1,2,4,5,7,8)
			 .reduce((t1,t2) -> t1>t2?t1:t2);//BinaryOperator interface T apply(T t1, T t2)
		System.out.println(max);
	}
	
	@Test
	public void test12(){
		Integer reduce = Stream.of(1,2,4,5,7,8)
			 .reduce(0, (t1,t2) -> t1+t2);//BinaryOperator interface T apply(T t1, T t2)
		System.out.println(reduce);
	}
	
	@Test
	public void test11(){
		Optional<Integer> max = Stream.of(1,2,4,5,7,8)
				.max((t1,t2) -> Integer.compare(t1, t2));
		System.out.println(max);
	}
	
	@Test
	public void test10(){
		Optional<Integer> opt = Stream.of(1,2,4,5,7,8)
				.filter(t -> t%3==0)
				.findFirst();
		System.out.println(opt);
	}
	
	@Test
	public void test09(){
		Optional<Integer> opt = Stream.of(1,2,3,4,5,7,9)
				.filter(t -> t%3==0)
				.findFirst();
		System.out.println(opt);
	}
	
	@Test
	public void test08(){
		Optional<Integer> opt = Stream.of(1,3,5,7,9).findFirst();
		System.out.println(opt);
	}
	
	@Test
	public void test04(){
		boolean result = Stream.of(1,3,5,7,9)
			.anyMatch(t -> t%2==0);
		System.out.println(result);
	}
	
	
	@Test
	public void test03(){
		boolean result = Stream.of(1,3,5,7,9)
			.allMatch(t -> t%2!=0);
		System.out.println(result);
	}
	
	@Test
	public void test02(){
		long count = Stream.of(1,2,3,4,5)
				.count();
		System.out.println("count = " + count);
	}
	
	@Test
	public void test01(){
		Stream.of(1,2,3,4,5)
				.forEach(System.out::println);
	}
}

17.2.4 exercise

Case study:

There are now two ArrayList collection storage teams with multiple member names, which are required to use the traditional for loop (or enhanced for loop) to
The following operation steps:

  1. The first team only needs the names of members whose names are three words; they are stored in a new set.
  2. After the first team is filtered, only the first three people are needed; they are stored in a new collection.
  3. The second team only needs the name of the member whose surname is Zhang; it is stored in a new collection.
  4. Do not use the first two people after the second team screening; store in a new collection.
  5. Merge two teams into one team; store in a new collection.
  6. Creates a Person object based on a name; stores it in a new collection.
  7. Print the Person object information for the entire team.

The code of the Person class is:

public class Person {
    private String name;
    public Person() {}
    public Person(String name) {
        this.name = name;
    }    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{name='" + name + "'}";
    }
}

The codes of the two teams (sets) are as follows:

public static void main(String[] args) {
       //The first team
        ArrayList<String> one = new ArrayList<>();
        one.add("Di Ali Gerba");
        one.add("Song Yuan Qiao");
        one.add("Su Xing He");
        one.add("Shi Tian Tian");
        one.add("Stone jade");
        one.add("Lao Tzu");
        one.add("Chuang-tzu");
        one.add("Master Hongqi");
        //Second team
        ArrayList<String> two = new ArrayList<>();
        two.add("Guli Nazha");
        two.add("Zhang Wuji");
        two.add("Zhao Liying");
        two.add("Zhang Sanfeng");
        two.add("Nicholas Zhao Si");
        two.add("Zhang Tian AI");
        two.add("Zhang Er dog");
    
		// Write code to complete the requirements 
    }

Reference answer:

public static void main(String[] args) {
       //The first team
        ArrayList<String> one = new ArrayList<>();
        one.add("Di Ali Gerba");
        one.add("Song Yuan Qiao");
        one.add("Su Xing He");
        one.add("Shi Tian Tian");
        one.add("Stone jade");
        one.add("Lao Tzu");
        one.add("Chuang-tzu");
        one.add("Master Hongqi");
    
        //Second team
        ArrayList<String> two = new ArrayList<>();
        two.add("Guli Nazha");
        two.add("Zhang Wuji");
        two.add("Zhao Liying");
        two.add("Zhang Sanfeng");
        two.add("Nicholas Zhao Si");
        two.add("Zhang Tian AI");
        two.add("Zhang Er dog");
        
		// The first team only needs the name of the member whose name is 3 words;
        // After the first team selection, only the first three people are needed;
        Stream<String> streamOne = one.stream().filter(s ‐> s.length() == 3).limit(3);
    
        // The second team only needs the name of Zhang;
        // The second team should not be the first two after screening;
        Stream<String> streamTwo = two.stream().filter(s ‐> s.startsWith("Zhang")).skip(2);
    
        // Merge two teams into one team;
        // Create Person object based on name;
        // Print the Person object information for the entire team.
        Stream.concat(streamOne, streamTwo).map(Person::new).forEach(System.out::println);
        
}

18.3 Optional

So far, the infamous null pointer exception is the most common cause of Java application failure. Previously, in order to solve the null pointer exception, Google's famous guava project introduced the Optional class. Guava prevents code pollution by checking null values, which encourages programmers to write cleaner code. Inspired by Google Guava, the Optional class has become part of the Java 8 class library.

Optional is actually a container: it can hold values of type T, or just null. Optional provides many useful methods so that we don't need to explicitly detect null values.

18.3.1 API

1. How to create an Optional object? Or how to use Optional to install value object or null value

(1) Static Optional empty(): used to create an empty Optional

(2) Static Optional of (t value): used to create a non empty Optional

(3) Static Optional of nullable (t value): used to create an Optional that may or may not be empty

2. How to remove the wrapped object from the Optional container?

(1) T get(): Optional container is required to be non empty

T get() and of(T value) are safe to use

(2)T orElse(T other) :

orElse(T other) is used with ofNullable(T value),

If the Optional container is not empty, the wrapped value will be returned. If it is empty, the default value (spare wheel) specified by orElse(T other)other will be used instead

(3)T orElseGet(Supplier<? extends T> other) :

If the Optional container is not empty, the wrapped value is returned. If it is empty, the value provided by the Lambda expression of the Supplier interface is used instead

(4) T orElseThrow(Supplier<? extends X> exceptionSupplier)

If the Optional container is not empty, the wrapped value will be returned. If it is empty, the exception type you specified will be thrown instead of the original NoSuchElementException

3. Other methods

(1) boolean isPresent(): judge whether the value in the Optional container exists

(2)void ifPresent(Consumer<? super T> consumer) :

Determine whether the value in the Optional container exists. If it exists, perform the operation specified by the Consumer. If not, do not

(3) Optional map(Function<? super T,? extends U> mapper)

Determine whether the value in the Optional container exists. If it exists, perform the operation specified by the Function interface. If not, do not

package com.atguigu.test07;

import java.util.ArrayList;
import java.util.Optional;

import org.junit.Test;

public class TestOptional {
	@Test
	public void test9(){
		String str = "Hello";
		Optional<String> opt = Optional.ofNullable(str);
        //Determine whether it is a pure letter word. If it is, change it to uppercase, otherwise it will remain unchanged
		String result = opt.filter(s->s.matches("[a-zA-Z]+")).
				map(s -> s.toLowerCase()).
				orElse(str);
		System.out.println(result);
	}
	
	
	@Test
	public void test8(){
		String str = null;
		Optional<String> opt = Optional.ofNullable(str);
		String string = opt.orElseThrow(()->new RuntimeException("Value does not exist."));
		System.out.println(string);
	}
	
	
	@Test
	public void test7(){
		String str = null;
		Optional<String> opt = Optional.ofNullable(str);
		String string = opt.orElseGet(String::new);
		System.out.println(string);
	}
	
	@Test
	public void test6(){
		String str = "hello";
		Optional<String> opt = Optional.ofNullable(str);
		String string = opt.orElse("atguigu");
		System.out.println(string);
	}
	
	@Test
	public void test5(){
		String str = null;
		Optional<String> opt = Optional.ofNullable(str);
//		System.out.println(opt.get());//java.util.NoSuchElementException: No value present
	}
	
	@Test
	public void test4(){
		String str = "hello";
		Optional<String> opt = Optional.of(str);

		String string = opt.get();
		System.out.println(string);
	}
	
	
	@Test
	public void test3(){
		String str = null;
		Optional<String> opt = Optional.ofNullable(str);
		System.out.println(opt);
	}
	
	@Test
	public void test2(){
		String str = "hello";
		Optional<String> opt = Optional.of(str);
		System.out.println(opt);
	}
	

}

18.3.2 exercise

Exercise 1

Case study:

(1) Declare a Girl type with a name (String) attribute

(2) Declare a Boy type, including name (String), girlfriend (Girl) attribute

(3) In the test class, create a Boy object and

If he has a girlfriend, show her name;

If he does not have a girlfriend, his girlfriend defaults to "Chang'e", that is, he can only appreciate "Chang'e"

class Girl{
	private String name;

	public Girl(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

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

	@Override
	public String toString() {
		return "Girl [name=" + name + "]";
	}
	
}
class Boy{
	private String name;
	private Girl girlFriend;
	public Boy(String name, Girl girlFriend) {
		super();
		this.name = name;
		this.girlFriend = girlFriend;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Girl getGirlFriend() {
		return girlFriend;
	}
	public void setGirlFriend(Girl girlFriend) {
		this.girlFriend = girlFriend;
	}
	@Override
	public String toString() {
		return "Boy [name=" + name + ", girlFriend=" + girlFriend + "]";
	}
	
}

Test class

	public static void main(String[] args) {
//		Boy boy = new Boy("Zhang San", null);
		Boy boy = new Boy("Zhang San",new Girl("Cui Cui"));
		Optional<Girl> grilFriend = Optional.ofNullable(boy.getGirlFriend());
		Optional.of(grilFriend.orElse(new Girl("Chang'e"))).ifPresent(g->System.out.println(g));
	}

Exercise 2

Case study:

(1) State the student category, including name and age

(2) Add several student objects to an ArrayList collection

(3) Operate the students in the set, find out the students older than 30 years old, and take out the first student. If there is no such student, construct a new student object with no parameters, and print the student information

Student sample code:

class Student{
	private String name;
	private int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Student() {
		super();
	}
	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;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}

Test class

	
	@Test
	public void test1(){
		ArrayList<Student> list = new ArrayList<>();
		list.add(new Student("Zhang San", 23));
		//...
		
		//Take out the age of the first student in the stream who is older than 30 years old, and print its age. If not, create a student object with the nonparametric structure
		Student stu = list.stream()
			.filter(s -> s.getAge()>30)
			.findFirst().orElse(new Student());
		System.out.println("Age of student:" + stu.getAge());
	}
public Girl getGirlFriend() {
	return girlFriend;
}
public void setGirlFriend(Girl girlFriend) {
	this.girlFriend = girlFriend;
}
@Override
public String toString() {
	return "Boy [name=" + name + ", girlFriend=" + girlFriend + "]";
}

}

//Test class

```java
	public static void main(String[] args) {
//		Boy boy = new Boy("Zhang San", null);
		Boy boy = new Boy("Zhang San",new Girl("Cui Cui"));
		Optional<Girl> grilFriend = Optional.ofNullable(boy.getGirlFriend());
		Optional.of(grilFriend.orElse(new Girl("Chang'e"))).ifPresent(g->System.out.println(g));
	}

Exercise 2

Case study:

(1) State the student category, including name and age

(2) Add several student objects to an ArrayList collection

(3) Operate the students in the set, find out the students older than 30 years old, and take out the first student. If there is no such student, construct a new student object with no parameters, and print the student information

Student sample code:

class Student{
	private String name;
	private int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Student() {
		super();
	}
	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;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}

Test class

	
	@Test
	public void test1(){
		ArrayList<Student> list = new ArrayList<>();
		list.add(new Student("Zhang San", 23));
		//...
		
		//Take out the age of the first student in the stream who is older than 30 years old, and print its age. If not, create a student object with the nonparametric structure
		Student stu = list.stream()
			.filter(s -> s.getAge()>30)
			.findFirst().orElse(new Student());
		System.out.println("Age of student:" + stu.getAge());
	}
Published 42 original articles, won praise 0, visited 124
Private letter follow

Tags: Lambda Java Programming JDK

Posted on Fri, 06 Mar 2020 03:15:56 -0800 by wherertheskips