Java8 (jdk1.8, jdk8) new features, Lambda expression, functional interface, method reference and constructor reference, Stream API, new date and time API


foreword

JAVA 8 (also known as jdk 1.8 or jdk8) was released by Oracle in March 2014. As we all know, jdk8 can be regarded as the most revolutionary generation since the release of jdk5. It has added many new features and brought great convenience to our programming. Now many companies use java 8 for development.


1. Lambda expression

Lambda expression, one of the most important new features released by Java 8, allows functions to be used as parameters of a method (functions are passed into methods as parameters), which greatly simplifies the code and provides more flexibility.
Lambda expressions introduce a new grammatical element and operator symbol in the Java language: "->", which splits Lambda expressions into two parts.
Left: Refers to all parameters of the Lambda expression.
Right: Refers to the Lambda body, which means the function that the Lambda expression needs to perform.
Another reason why lambda expressions are concise is that they have " type inference ".
Lambda expressions omit many type declarations, and many parameter types are inferred by the compiler. There is no need to specify the type in the expression, and the program can still be compiled. This is because javac infers the parameters in the background according to the context of the program. type.

1.1 Grammar 1: No parameters, no return value

//匿名内部类
Runnable r1 = new Runnable(){
    
    
            @Override
            public void run(){
    
    
                log.info("Hello World!");
            }
 };

Simplified using Lambda expressions:

 //Lambda表达式
 Runnable r2 = () -> log.info("Hello Lambda!");

1.2 Syntax 2: One parameter, no return value

Consumer<String> consumer = new Consumer<String>() {
    
    
            @Override
            public void accept(String s) {
    
    
                log.info(s);
            }
        };
        consumer.accept("Hello World!");

Simplify with Lambda expressions:

 Consumer<String> consumer1 = (s) -> log.info(s);
        consumer1.accept("Hello Lambda!");

1.3 Grammar 3: When there is only one parameter, the () of the parameter can be omitted

 Consumer<String> consumer1 = s -> log.info(s);
        consumer1.accept("Hello Lambda!");

Simplify with Lambda expressions:

 //Lambda表达式
 Runnable r2 = () -> log.info("Hello Lambda");

1.4 Grammar 4: Lambda has two parameters and a return value

BinaryOperator<Long> bo = (x,y)-> {
    
    
	log.info("实现函数接口方法!");
	return x + y;
};

1.5 Grammar 5: When the Lambda body has only one statement, return and braces can be omitted

The code is as follows (example):

BinaryOperator<Long> bo = (x,y)-> x + y;

1.6 Grammar 6: The data type can be omitted, because the compiler can infer

```java
BinaryOperator<Long> bo = (Long x,Long y)-> {
    
    
	log.info("实现函数接口方法!");
	return x + y;
};

Simplify using a Lambda expression, removing the x and y declarations:

BinaryOperator<Long> bo = (x,y)-> {
    
    
	log.info("实现函数接口方法!");
	return x + y;
};

2. Functional interface

2.1 What is a functional interface

Before java8, if a new method was added to the interface, then all implementation classes would need to be changed, and this method would need to be implemented synchronously.
Java8 adds two new keywords to the interface: default and static, so that default methods can be added to the interface, and the subclasses do not need to be changed.

A functional interface refers to an interface with only one abstract method and several default methods in an interface. Generally, a functional interface will be marked with the @FunctionalInterface annotation to detect whether it conforms to a functional interface. At the same time, javac will also include a statement stating whether the interface conforms to the functional interface.
But it does not mean that without this annotation, it is not a functional interface. This annotation is only used for compile-time checking. If there are multiple abstract methods, the compilation will fail.

2.2 Custom functional interface

@FunctionalInterface
public interface MyNumber{
    
    
    public double getValue();
}

2.3 Using Generics in Functional Interfaces

@FunctionalInterface
public interface MyFunc<T>{
    
    
    public T getValue(T t);
}

2.4 Passing Lambda Expressions as Parameters

public String toUpperString(MyFunc<String> mf, String str){
    
    
    public T getValue(T t);
}
//作为参数传递Lambda表达式:
String newStr = toUpperString(
		(str) -> str.toUpperCase(), "abcd");
    log.info(newStr);
}

2.5 Java built-in four large functional interfaces

insert image description here

3. Method references and constructor references

3.1 Method reference

When the operation to be passed to the Lambda body already has an implementation method, you can directly use the method reference ( note: the list of implementation abstract methods must be consistent with the method parameter list of the method reference )
format: use the operator " :: " to combine the method name and objects or classes.
There are the following three cases:
object::instance method
class::instance method
class::static method

(x) -> System.out.println(x);
//等同于:
System.out::println;
BinaryOperator<Double> bo = (x,y) -> Math.pow(x,y);
//等同于:
BinaryOperator<Double> bo = Math::pow;
compare((x,y) -> x.equals(y),"abcd","abcd");
//等同于:
compare(String::equals,"abcd","abcd");

3.2 Constructor reference

Format: ClassName::new

Function<Integer, MyClass> fun = (n) -> new MyClass(n);
//等同于:
Function<Integer, MyClass> fun = MyClass::new;

3.3 Array references

Format: type[]::new

Function<Integer,Integer[]> fun = (num) ->new Integer[num];
//等同于:
Function<Integer,Integer[]> fun = Integer[]::new;

4. Three steps of Stream API

The Stream API is another of the most important changes in Java8, and the other one is the Lambda expression we mentioned at the beginning.
Stream API (java.util.stream.*) greatly simplifies the processing of collections in programming, and can perform very complex operations such as searching, filtering and mapping data on collections.
Three steps to use the Stream API:
1. Create a Stream: a data source (for example: collection, array), get a stream
2. Intermediate operation: a chain of intermediate operations to process the data of the data source
3. Termination operation: a Terminate the operation, execute the chain of intermediate operations, and produce results.
It should be noted that all intermediate operations in the stream must meet terminal operations before they are executed, otherwise it is a definition and will not produce results

4.1 Create a stream

4.1.1 Create stream through Collection

The Collection interface in Java8 is extended to provide two methods for obtaining streams:

default Stream<E> stream() //返回一个顺序流
default Stream<E> parallelStream 返回一个并行流(可多线程)
//例如
List<String> list = new ArrayList<>();
Stream<String> stringStream = list.stream(); //返回一个顺序流
Stream<String> parallelStream = list.parallelStream(); //返回一个并行流(可多线程)

4.1.2 Create a stream through the array Arrays

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

static <T> Stream<T> stream(T[] array) //返回一个流
//重载形式,能够处理对应基本类型的数组:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
//例如
 Stream<String> stream1 = Arrays.stream(new String[]{
    
    "ABB", "BBC", "CCD", "XCC"});

4.1.3 Create a stream from a value

A stream can be created by displaying values ​​using the static method Stream.of(). It can take any number of arguments.

public static<T> Stream<T> of(T... values)//返回一个流
//例如
Stream<String> stream = Stream.of("A", "B", "C", "D");

4.1.4 Creating a stream from a function: creating an infinite stream

Infinite streams can be created using the static methods Stream.iterate() and Stream.generate().

//迭代
public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f)//返回一个流
//生成
public static<T> Stream<T> generate(Supplier<T> s)//返回一个流
//例如
//迭代:遍历10个奇数
Stream.iterate(1,t->t+2).limit(10).forEach(System.out::println);//生成:生成10个随机数      
Stream.generate(Math::random).limit(10).forEach(System.out::println);

4.2 Intermediate operations of stream

Multiple intermediate operations can be connected to form a pipeline, and unless a termination operation is triggered on the pipeline, the intermediate operations will not perform any processing! And when the operation is terminated, it is processed all at once, which is called "lazy evaluation".

4.2.1 Screening and slicing

insert image description here
The specific usage method can be used in the following 4.4 exercises.

4.2.2 Mapping

insert image description here

List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
Stream<String> stream = strList.stream()
			   .map(String::toUpperCase);
stream.forEach(System.out::println);

4.2.3 Sorting

insert image description here

public class TestStreamAPI1 {
    
    
	List<Employee> emps = Arrays.asList(
			new Employee(101, "张三", 18, 9999.99),
			new Employee(102, "李四", 59, 6666.66),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);
	/*
		sorted()——自然排序
		sorted(Comparator com)——定制排序
	 */
	@Test
	public void test2(){
    
    
		emps.stream()
			.map(Employee::getName)
			.sorted()
			.forEach(System.out::println);
		
		System.out.println("------------------------------------");
		
		emps.stream()
			.sorted((x, y) -> {
    
    
				if(x.getAge() == y.getAge()){
    
    
					return x.getName().compareTo(y.getName());
				}else{
    
    
					return Integer.compare(x.getAge(), y.getAge());
				}
			}).forEach(System.out::println);
	}
}

4.3 Termination operation

4.3.1 Find and match

insert image description here
insert image description here

public class TestStreamAPI2 {
    
    
	
	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 59, 6666.66, Status.BUSY),
			new Employee(101, "张三", 18, 9999.99, Status.FREE),
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)
	);
	
	//3. 终止操作
	/*
		allMatch——检查是否匹配所有元素
		anyMatch——检查是否至少匹配一个元素
		noneMatch——检查是否没有匹配的元素
		findFirst——返回第一个元素
		findAny——返回当前流中的任意元素
		count——返回流中元素的总个数
		max——返回流中最大值
		min——返回流中最小值
	 */
	@Test
	public void test1(){
    
    
			boolean bl = emps.stream()
				.allMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl);
			
			boolean bl1 = emps.stream()
				.anyMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl1);
			
			boolean bl2 = emps.stream()
				.noneMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl2);
	}
	
	@Test
	public void test2(){
    
    
		Optional<Employee> op = emps.stream()
			.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
			.findFirst();
		
		System.out.println(op.get());
		
		System.out.println("--------------------------------");
		
		Optional<Employee> op2 = emps.parallelStream()
			.filter((e) -> e.getStatus().equals(Status.FREE))
			.findAny();
		
		System.out.println(op2.get());
	}
	
	@Test
	public void test3(){
    
    
		long count = emps.stream()
						 .filter((e) -> e.getStatus().equals(Status.FREE))
						 .count();
		
		System.out.println(count);
		
		Optional<Double> op = emps.stream()
			.map(Employee::getSalary)
			.max(Double::compare);
		
		System.out.println(op.get());
		
		Optional<Employee> op2 = emps.stream()
			.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
		
		System.out.println(op2.get());
	}
	
	//注意:流进行了终止操作后,不能再次使用
	@Test
	public void test4(){
    
    
		Stream<Employee> stream = emps.stream()
		 .filter((e) -> e.getStatus().equals(Status.FREE));
		
		long count = stream.count();
		
		stream.map(Employee::getSalary)
			.max(Double::compare);
	}
}

Employee class:

public class Employee {
    
    

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

	public Employee() {
    
    
	}

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

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

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

	public Employee(int id, String name, int age, double salary, Status status) {
    
    
		this.id = id;
		this.name = name;
		this.age = age;
		this.salary = salary;
		this.status = status;
	}

	public Status getStatus() {
    
    
		return status;
	}

	public void setStatus(Status status) {
    
    
		this.status = status;
	}

	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 String show() {
    
    
		return "测试方法引用!";
	}

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

	@Override
	public boolean equals(Object obj) {
    
    
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (age != other.age)
			return false;
		if (id != other.id)
			return false;
		if (name == null) {
    
    
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
			return false;
		return true;
	}

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

	public enum Status {
    
    
		FREE, BUSY, VOCATION;
	}

}

4.3.2 Reductioninsert image description here

public class TestStreamAPI3 {
    
    
	
	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 79, 6666.66, Status.BUSY),
			new Employee(101, "张三", 18, 9999.99, Status.FREE),
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)
	);
	
	//3. 终止操作
	/*
		归约
		reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。
	 */
	@Test
	public void test1(){
    
    
		List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
		
		Integer sum = list.stream()
			.reduce(0, (x, y) -> x + y);
		
		System.out.println(sum);
		
		System.out.println("----------------------------------------");
		
		Optional<Double> op = emps.stream()
			.map(Employee::getSalary)
			.reduce(Double::sum);
		
		System.out.println(op.get());
	}
	
	//需求:搜索名字中 “六” 出现的次数
	@Test
	public void test2(){
    
    
		Optional<Integer> sum = emps.stream()
			.map(Employee::getName)
			.flatMap(TestStreamAPI1::filterCharacter)
			.map((ch) -> {
    
    
				if(ch.equals('六'))
					return 1;
				else 
					return 0;
			}).reduce(Integer::sum);
		
		System.out.println(sum.get());
	}
}

4.3.3 Collection

insert image description here
The implementation of the methods in the Collector interface determines how to perform collection operations on the stream (such as collecting into List, Set, Map). However, the Collectors utility class provides many static methods, which can easily create common collector instances. The specific methods and instances are as follows:
insert image description here
insert image description here

public class TestStreamAPI3 {
    
    
	
	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 79, 6666.66, Status.BUSY),
			new Employee(101, "张三", 18, 9999.99, Status.FREE),
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)
	);
	//3. 终止操作
	//collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
	@Test
	public void test3(){
    
    
		List<String> list = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toList());
		
		list.forEach(System.out::println);
		
		System.out.println("----------------------------------");
		
		Set<String> set = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toSet());
		
		set.forEach(System.out::println);

		System.out.println("----------------------------------");
		
		HashSet<String> hs = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toCollection(HashSet::new));
		
		hs.forEach(System.out::println);
	}
	
	@Test
	public void test4(){
    
    
		Optional<Double> max = emps.stream()
			.map(Employee::getSalary)
			.collect(Collectors.maxBy(Double::compare));
		
		System.out.println(max.get());
		
		Optional<Employee> op = emps.stream()
			.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
		
		System.out.println(op.get());
		
		Double sum = emps.stream()
			.collect(Collectors.summingDouble(Employee::getSalary));
		
		System.out.println(sum);
		
		Double avg = emps.stream()
			.collect(Collectors.averagingDouble(Employee::getSalary));
		
		System.out.println(avg);
		
		Long count = emps.stream()
			.collect(Collectors.counting());
		
		System.out.println(count);
		
		System.out.println("--------------------------------------------");
		
		DoubleSummaryStatistics dss = emps.stream()
			.collect(Collectors.summarizingDouble(Employee::getSalary));
		
		System.out.println(dss.getMax());
	}
	
	//分组
	@Test
	public void test5(){
    
    
		Map<Status, List<Employee>> map = emps.stream()
			.collect(Collectors.groupingBy(Employee::getStatus));
		
		System.out.println(map);
	}
	
	//多级分组
	@Test
	public void test6(){
    
    
		Map<Status, Map<String, List<Employee>>> map = emps.stream()
			.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
    
    
				if(e.getAge() >= 60)
					return "老年";
				else if(e.getAge() >= 35)
					return "中年";
				else
					return "成年";
			})));
		
		System.out.println(map);
	}
	
	//分区
	@Test
	public void test7(){
    
    
		Map<Boolean, List<Employee>> map = emps.stream()
			.collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));
		
		System.out.println(map);
	}
	
	//
	@Test
	public void test8(){
    
    
		String str = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.joining("," , "----", "----"));
		
		System.out.println(str);
	}
	
	@Test
	public void test9(){
    
    
		Optional<Double> sum = emps.stream()
			.map(Employee::getSalary)
			.collect(Collectors.reducing(Double::sum));
		
		System.out.println(sum.get());
	}
}

4.4 Stream API exercises

4.4.1 Exercise 1

public class TestStreamAPI {
    
    
	
	/*
	  	1.	给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?
		,给定【1,2,3,4,5】, 应该返回【1,4,9,16,25】。
	 */
	@Test
	public void test1(){
    
    
		Integer[] nums = new Integer[]{
    
    1,2,3,4,5};
		
		Arrays.stream(nums)
			  .map((x) -> x * x)
			  .forEach(System.out::println);
	}

	/*
	 2.	怎样用 map 和 reduce 方法数一数流中有多少个Employee呢?
	 */
	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 59, 6666.66, Status.BUSY),
			new Employee(101, "张三", 18, 9999.99, Status.FREE),
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)
	);
	
	@Test
	public void test2(){
    
    
		Optional<Integer> count = emps.stream()
			.map((e) -> 1)
			.reduce(Integer::sum);
		
		System.out.println(count.get());
	}
}

4.4.2 Exercise 2

public class TestTransaction {
    
    
	
	List<Transaction> transactions = null;
	
	@Before
	public void before(){
    
    
		Trader raoul = new Trader("Raoul", "Cambridge");
		Trader mario = new Trader("Mario", "Milan");
		Trader alan = new Trader("Alan", "Cambridge");
		Trader brian = new Trader("Brian", "Cambridge");
		
		transactions = Arrays.asList(
				new Transaction(brian, 2011, 300),
				new Transaction(raoul, 2012, 1000),
				new Transaction(raoul, 2011, 400),
				new Transaction(mario, 2012, 710),
				new Transaction(mario, 2012, 700),
				new Transaction(alan, 2012, 950)
		);
	}
	
	//1. 找出2011年发生的所有交易, 并按交易额排序(从低到高)
	@Test
	public void test1(){
    
    
		transactions.stream()
					.filter((t) -> t.getYear() == 2011)
					.sorted((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()))
					.forEach(System.out::println);
	}
	
	//2. 交易员都在哪些不同的城市工作过?
	@Test
	public void test2(){
    
    
		transactions.stream()
					.map((t) -> t.getTrader().getCity())
					.distinct()
					.forEach(System.out::println);
	}
	
	//3. 查找所有来自剑桥的交易员,并按姓名排序
	@Test
	public void test3(){
    
    
		transactions.stream()
					.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
					.map(Transaction::getTrader)
					.sorted((t1, t2) -> t1.getName().compareTo(t2.getName()))
					.distinct()
					.forEach(System.out::println);
	}
	
	//4. 返回所有交易员的姓名字符串,按字母顺序排序
	@Test
	public void test4(){
    
    
		transactions.stream()
					.map((t) -> t.getTrader().getName())
					.sorted()
					.forEach(System.out::println);
		
		System.out.println("-----------------------------------");
		
		String str = transactions.stream()
					.map((t) -> t.getTrader().getName())
					.sorted()
					.reduce("", String::concat);
		
		System.out.println(str);
		
		System.out.println("------------------------------------");
		
		transactions.stream()
					.map((t) -> t.getTrader().getName())
					.flatMap(TestTransaction::filterCharacter)
					.sorted((s1, s2) -> s1.compareToIgnoreCase(s2))
					.forEach(System.out::print);
	}
	
	public static Stream<String> filterCharacter(String str){
    
    
		List<String> list = new ArrayList<>();
		
		for (Character ch : str.toCharArray()) {
    
    
			list.add(ch.toString());
		}
		
		return list.stream();
	}
	
	//5. 有没有交易员是在米兰工作的?
	@Test
	public void test5(){
    
    
		boolean bl = transactions.stream()
					.anyMatch((t) -> t.getTrader().getCity().equals("Milan"));
		
		System.out.println(bl);
	}
	
	
	//6. 打印生活在剑桥的交易员的所有交易额
	@Test
	public void test6(){
    
    
		Optional<Integer> sum = transactions.stream()
					.filter((e) -> e.getTrader().getCity().equals("Cambridge"))
					.map(Transaction::getValue)
					.reduce(Integer::sum);
		
		System.out.println(sum.get());
	}
	
	
	//7. 所有交易中,最高的交易额是多少
	@Test
	public void test7(){
    
    
		Optional<Integer> max = transactions.stream()
					.map((t) -> t.getValue())
					.max(Integer::compare);
		
		System.out.println(max.get());
	}
	
	//8. 找到交易额最小的交易
	@Test
	public void test8(){
    
    
		Optional<Transaction> op = transactions.stream()
					.min((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()));
		
		System.out.println(op.get());
	}

}
//交易类
public class Transaction {
    
    

	private Trader trader;
	private int year;
	private int value;

	public Transaction() {
    
    
	}

	public Transaction(Trader trader, int year, int value) {
    
    
		this.trader = trader;
		this.year = year;
		this.value = value;
	}

	public Trader getTrader() {
    
    
		return trader;
	}

	public void setTrader(Trader trader) {
    
    
		this.trader = trader;
	}

	public int getYear() {
    
    
		return year;
	}

	public void setYear(int year) {
    
    
		this.year = year;
	}

	public int getValue() {
    
    
		return value;
	}

	public void setValue(int value) {
    
    
		this.value = value;
	}

	@Override
	public String toString() {
    
    
		return "Transaction [trader=" + trader + ", year=" + year + ", value="
				+ value + "]";
	}

}
//交易员类
public class Trader {
    
    

	private String name;
	private String city;

	public Trader() {
    
    
	}

	public Trader(String name, String city) {
    
    
		this.name = name;
		this.city = city;
	}

	public String getName() {
    
    
		return name;
	}

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

	public String getCity() {
    
    
		return city;
	}

	public void setCity(String city) {
    
    
		this.city = city;
	}

	@Override
	public String toString() {
    
    
		return "Trader [name=" + name + ", city=" + city + "]";
	}

}

5. New date and time API

You can refer to an article I wrote before, which introduces it in detail:
link: java method to get the current time: LocalDateTime, Date, Calendar, and the comparison of the three


Summarize

The new features of Java 8 have brought great convenience to our daily development. You may not be used to it or a little difficult to understand at first, but it is better to learn it. Even if you don’t use it, it doesn’t mean that others don’t. Using the new feature syntax may not be easy to understand, so it still needs to be mastered.
Let's study together and cheer together!

Guess you like

Origin blog.csdn.net/sunzixiao/article/details/129489381