java8

java8新特性简介:

  • 速度更快
  • 代码更少(增加了新的语法Lambda表达式)
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常Optional

其中最为核心的为Lambda表达式与Stream API

Lambda表达式

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使java的语言表达能力得到了提升。

java8中引入了一个新的操作符 -> 该操作符称为箭头操作符或Lmabda操作符,箭头操作符将Lambda表达式拆分成两部分:

左侧:lambda表达式的参数列表

右侧:Lambda表达式中所需要执行的功能,即Lambda体

语法一:无参数,无返回值 () -> System.out.print(“Hello Lambda”);

@Test
public void test1(){
Runnable runnable1 = () -> System.out.println("Hello World");
runnable1.run();
}

语法二:有一个参数,无返回值 (x) -> System.out.println(x)

Consumer接口:有一个参数,无返回值

@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
@Test
public void test1(){
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("Hello World");
}

语法三:若只有一个参数,小括号可以省略不写 x -> System.out.println(x)

@Test
public void test1(){
Consumer<String> consumer = x -> System.out.println(x);
consumer.accept("Hello World");
}

语法四:有两个以上的参数,有返回值,并且Lambda体中有多条语句

Comparator接口:有两个参数,有返回值

@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
@Test
public void test1(){
Comparator<Integer> comparator = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
}

语法五:若Lambda体中只有一条语句,return 和 大括号都可以省略不写

@Test
public void test1(){
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
}

语法六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即类型推断。

(Integer x,Integer y) -> Integer.compare(x,y);

@Test
public void test1(){
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
}

函数式接口

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为 lambda 表达式。使用注解@FunctionalInterface修饰。

JDK 1.8 新增加的函数接口:java.util.function

Consumer

代表了接受一个输入参数并且无返回的操作

@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
public void happy(double money,Consumer<Double> consumer){
consumer.accept(money);
}
@Test
public void test1(){
happy(1000,x -> System.out.println("大保健消费了"+x+"元"));
}

Supplier

无参数,返回一个结果。

@FunctionalInterface
public interface Supplier<T> {
T get();
}
public List<Integer> getNumList(int num, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = supplier.get();
list.add(n);
}
return list;
}
@Test
public void test1(){
List<Integer> list = getNumList(5, () -> (int) (Math.random() * 100));
for(Integer num:list){
System.out.println(num);
}
}

Function<T,R>

接受一个输入参数,返回一个结果。

@FunctionalInterface
public interface Function<T, R> {
R apply(T var1);
}
public String strHandler(String str, Function<String,String> function){
return function.apply(str);
}
@Test
public void test1(){
String s = strHandler("\t\t\t hello World", (str) -> str.trim().substring(2,5));
System.out.println(s);
}

Predicate

接受一个输入参数,返回一个布尔值结果。

@FunctionalInterface
public interface Predicate<T> {
boolean test(T var1);
}
public List<String> filterStr(List<String> list,Predicate<String> predicate){
List<String> strList = new ArrayList<>();
for (String str:list){
if(predicate.test(str)){
strList.add(str);
}
}
return strList;
}
@Test
public void test(){
List<String> list=Arrays.asList("hello","world","ok","lambda");
List<String> stringList = filterStr(list, (s) -> s.length() > 3);
for (String str:stringList){
System.out.println(str);
}
}

方法引用与构造器引用

方法引用

方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用方法引用。

可以理解为方法引用是Lambda表达式的另外一种表达形式。

注意:Lambda体中被调用的方法的参数列表和返回值类型需要与函数式接口中抽象方法的参数列表和返回值类型要一致。

主要有三种语法格式:

对象名::实例方法名

Consumer接口(有一个参数,无返回值)

@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}

PrintStream的println方法(有一个参数,无返回值)

public void println(String var1) {
synchronized(this) {
this.print(var1);
this.newLine();
}
}
@Test
public void test(){
//Consumer接口和PrintStream的println方法参数列表和返回值类型一致
PrintStream ps1 = System.out;
Consumer<String> consumer = (x) -> ps1.println(x);

PrintStream ps2 = System.out;
Consumer<String> consumer2= ps2::println;

Consumer<String> consumer3= System.out::println;
consumer3.accept("aaaa");//输出aaaa
}
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Employee {
private String name; //姓名
private int age; //年龄
private double salary; //薪资
}
@Test
public void test(){
Employee employee=new Employee();
String name=employee.getName();
int age=employee.getAge();
Supplier<String> supplier= () -> name;
//这里supplier2会报错,因为age是int类型,而Supplier中定义的是String类型
Supplier<String> supplier2= () -> age;

Supplier<Integer> supplier3= employee::getAge;
Integer num = supplier3.get();
System.out.println(num);
}

类名::静态方法名

Integer类的compare静态方法源码如下:

public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

Comparator接口

@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
@Test
public void test(){
Comparator<Integer> comparator= (x,y) -> Integer.compare(x,y);
Comparator<Integer> comparator2= Integer::compare;
}

类名::实例方法名

若Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method

BiPredicate 函数式接口,接受两个参数返回一个boolean类型

@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u);
}

String类的equals方法源码如下:

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
@Test
public void test(){
// Lambda表达式写法
BiPredicate<String,String> biPredicate=(x,y) -> x.equals(y);

//方法引用写法,equals是一个实例方法
BiPredicate<String,String> biPredicate2=String::equals;
}

构造器引用

格式:类名::new

需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致

Function函数式接口,有一个参数,一个返回值

@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}

BiFunction函数式接口,有两个参数,一个返回值

@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}

Employee类,使用到其中的无参构造器,一个参数的构造器,两个参数的构造器

public class Employee {
private int id;
private String name;
private int age;
private double salary;

public Employee() {}

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

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

public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
}
@Test
public void test(){
// Lambda写法
Supplier<Employee> sub = () -> new Employee();
sub.get();

// 构造器引用方式(无参构造器)
Supplier<Employee> sub2 = Employee::new;
Employee employee = sub2.get();
System.out.println(employee);

Function<Integer,Employee> function=(x) -> new Employee(x);
// 构造器引用方式(一个参数的构造器),构造器取参数决于Function的参数:R apply(T t);
Function<Integer,Employee> function2=Employee::new;
// 构造器引用方式(两个参数的构造器),构造器取参数决于BiFunction的参数:R apply(T t, U u);
BiFunction<Integer,Integer,Employee> bf=Employee::new;

}

数组引用

格式:类型::new

@Test
public void test(){
// Lambda写法
Function<Integer,String[]> function=(x) -> new String[x];
String[] apply = function.apply(10);
System.out.println(apply.length);//10

//数组引用写法
Function<Integer,String[]> function2=String[]::new;
String[] apply2 = function.apply(20);
System.out.println(apply2.length);//20
}

Stream API

Stream API ( java.util.stream.*

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之, Stream API 提供了 一种高效且易于使用的处理数据的方式。

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

流(Stream)是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列。集合讲的是数据,流讲的是计算!

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

注意:

  • Stream自己不会存储元素

  • Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。

  • Stream操作是延迟执行的。意味着他们会等到需要结果的时候才执行。

Stream操作的三个步骤:

通过Collection系列集合提供的Stream()或paralleStream()

List<String> list=new ArrayList<>();
Stream<String> stream = list.stream();

通过Arrays中的静态方法stream()获取数组流

Employee[] employee=new Employee[10];
Stream<Employee> stream = Arrays.stream(employee);

通过Stream类中的静态方法 of()

Stream<String> stream = Stream.of("aa", "bb", "cc");

创建无限流

//迭代
Stream<Integer> stream = Stream.iterate(0, (x) -> x + 2);
//生成
Stream<Double> stream = Stream.generate(() -> Math.random());

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”

中间操作:filter、limit、skip、distinct、map、flatMap、sorted

终止操作:allMatch,anyMatch,noneMatch, findFirst,findAny,count,max,min, reduce,collect

package com.didispace.chapter11;

import java.util.Objects;

public class User {
private Integer id;
private String name;
private Integer age;

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 User(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}

// 重写equals()方法
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User that = (User) o;
return Objects.equals(name, that.name) && Objects.equals(age, that.age);
}

// 重写hashcode()方法
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
package com.didispace.chapter11;

import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class java8Test {
List<User> userList= Arrays.asList(
new User(1,"aa",18),
new User(2,"bb",30),
new User(3,"cc",40),
new User(4,"dd",50),
new User(5,"dd",50)
);

@Test
public void test(){
//filter 接收Lambda,从流中排除某些元素。filter 方法用于通过设置的条件过滤出元素。
//filter 过滤满足条件 筛选出满足条件的对象,最终返回的筛选过后的列表
Stream<User> satisfy = userList.stream().filter(e -> e.getAge() > 18);
System.out.println("满足条件用户列表:" + satisfy.collect(Collectors.toList()));

//limit 返回一个新的流,该流的元素被截断为给定的最大长度。limit方法包含前n个元素,其中n小于或等于给定的最大大小。
//limit 截断流,使其元素不超过给定数量。限制流中元素的个数,即取前n个元素,返回新的流
//原流有5个数字,我们调用了limit(3),最大大小是3。因此,我们的输出将从第一个元素开始最多3个元素,即11 12 13。
//当n>=length时,取所有元素,原封不动、完璧归赵。
Stream.of(11, 12, 13, 14, 15).limit(3).forEach(System.out::println);

//skip 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
//skip 用于跳过前面n个元素,然后再返回新的流。返回结果 6 7 8 9 10 。当n>=length时,跳过所有元素,返回空流。
List<Integer> collect1 = Stream.of(1,2,3,4,5,6,7,8,9,10).skip(5).collect(Collectors.toList());

//可以用.map 获取到遍历对象的所有属性值,拿到属性值后,我们可以重新将属性赋值到一个对象或基本类型的对象里,一般结合collect()方法来使用。
//获取User对象列表的所有对象的id
List<Integer> users = userList.stream().map(User::getId).collect(Collectors.toList());
System.out.println("用户id列表:" + users);//用户id列表:[1, 2, 3, 4, 5]

//distinct 根据类的某个或多个属性去重
//distinct 筛选,通过流所生成元素的hashCode()和equals()去除重复的元素
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 5, 5, 5, 6, 7);
List<Integer> distinctNumbers = numbers.stream().distinct().collect(Collectors.toList());
System.out.println("distinctNumbers"+distinctNumbers);//[1, 2, 3, 4, 5, 6, 7]

//distinct()方法使用hashCode()和equals()方法来获取不同的元素。所以,我们的类必须实现hashCode()和equals()方法。
List<User> users1 = userList.stream().distinct().collect(Collectors.toList());
System.out.println("users1"+ users1);

//map用来归类,结果一般是一组数据
// map 接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
//使用map方法获取list数据中的name
List<String> names = userList.stream().map(User::getName).collect(Collectors.toList());
System.out.println("names"+names);//names[aa, bb, cc, dd, dd]

List<String> list1 = Arrays.asList("aaa", "bbb", "ccc", "eee");
List<String> list2 = list1.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println("list2:"+list2);//list2:[AAA, BBB, CCC, EEE]

//使用map方法获取list数据中的name的长度
List<Integer> length = userList.stream().map(User::getName).map(String::length).collect(Collectors.toList());
System.out.println("length"+length);//length[2, 2, 2, 2, 2]

//将每人的年龄-10
List<Integer> age = userList.stream().map(User::getAge).map(i -> i - 10).collect(Collectors.toList());
System.out.println("age"+age);//age[8, 20, 30, 40, 40]

// sorted()--自然排序(Comparable)
List<String> list3 = Arrays.asList("ccc","aaa", "bbb", "ddd", "eee");
List<String> list4 = list3.stream().sorted().collect(Collectors.toList());
System.out.println("list4:"+list4);//list4:[aaa, bbb, ccc, ddd, eee]

// sorted(Comparator com)--定制排序(Comparator)
List<User> sorted = userList.stream().sorted((e1, e2) -> {
if (e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
} else {
return -e1.getName().compareTo(e2.getName());
}
}).collect(Collectors.toList());
System.out.println("sorted"+sorted);

// allMatch 检查是否匹配所有元素
boolean allMatch = userList.stream().allMatch((e) -> e.getName().equals("bb"));
System.out.println("allMatch:"+allMatch);//allMatch:false

// anyMatch 检查是否至少匹配一个元素
boolean anyMatch = userList.stream().anyMatch((e) -> e.getName().equals("bb"));
System.out.println("anyMatch:"+anyMatch);//anyMatch:true

// noneMatch 检查是否没有匹配所有元素
boolean noneMatch = userList.stream().noneMatch((e) -> e.getName().equals("bb"));
System.out.println("noneMatch:"+noneMatch);//noneMatch:false

// findFirst 返回第一个元素
String[] strs = {"aaa","bbb","ccc","ddddd","abcdefg"};
Optional<String> first = Stream.of(strs).findFirst();
System.out.println("获取第一个元素 : "+first.get()); // 获取第一个元素 : aaa

// findAny 返回当前流中的任意元素
Optional<String> any = Stream.of(strs).findAny();
System.out.println("获取任意一个元素 :"+any.get()); // 获取任意一个元素 :aaa

// count 返回流中元素的总个数
long count = userList.stream().count();
System.out.println("count:"+count);//count:5

// max 返回流中最大值
Optional<User> optional = userList.stream().max((e1, e2) -> Double.compare(e1.getId(), e2.getId()));
System.out.println("max最大值:"+optional.get());//max:Optional[50]

// min 返回流中最小值
Optional<Integer> optional2 = userList.stream().map(User::getId).min(Double::compare);
System.out.println("max最大值:"+optional2.get());//min:Optional[18]

// reduce reduce(T identity,BinaryOperator) / reduce(BinaryOperator) 可以将流中元素反复结合起来,得到一个值
//reduce用来计算值,结果是一个值
//计算总年龄
Integer totalScore1 = userList.stream().map(User::getAge).reduce(0,(a,b) -> a + b);
System.out.println("totalScore1:"+totalScore1);//totalScore1:188

List<Integer> list6=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list6.stream().reduce(0, (x, y) -> x + y);
System.out.println("sum:"+sum);//sum:55

Optional<Integer> optional3 = userList.stream().map(User::getId).reduce(Integer::sum);
System.out.println("optional3:"+optional3.get());//optional3:15

//计算最高年龄和最低年龄
Optional<Integer> max = userList.stream().map(User::getAge).reduce(Integer::max);
Optional<Integer> min = userList.stream().map(User::getAge).reduce(Integer::min);
System.out.println("max:"+max);//max:Optional[50]
System.out.println("min:"+min);//min:Optional[18]
// Collect 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
// Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List,Set,Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例
// toList()和toSet()方法都是将map后的stream转换为一个列表对象,toSet()会去重重复的对象, 需要.map()方法将列表中的对象属性给映射出来。
// toList用法
List<Integer> list = userList.stream().map(User::getId).collect(Collectors.toList());
System.out.println("用户列表为: " + list);//用户列表为: [1, 2, 3, 4, 5]
// toMap用法
Map<Integer, String> map = userList.stream().collect(Collectors.toMap(User::getId, User::getName));
System.out.println("用户map为: " + map);//用户map为: {1=aa, 2=bb, 3=cc, 4=dd, 5=dd}

//内部迭代 for 循环
userList.forEach(user -> System.out.println(user.getId()));
}
}
package com.didispace.chapter11;

public class Employee {
private int id;
private String name;
private int age;
private double salary;
private Status status;
//枚举类
public enum Status{
FREE,
BUSY,
VOCATION;
}

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

public Employee() {}

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

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

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

public int getId() {
return id;
}

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

public String getName() {
return name;
}

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

public int getAge() {
return age;
}

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

public double getSalary() {
return salary;
}

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

public Status getStatus() {
return status;
}

public void setStatus(Status status) {
this.status = status;
}
}
package com.didispace.chapter11;

import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;

public class ChapterTest {
List<Employee> employees= Arrays.asList(
new Employee("张三",18,9999.99, Employee.Status.FREE),
new Employee("李四",38,5555.99,Employee.Status.BUSY),
new Employee("王五",50,6666.66,Employee.Status.VOCATION),
new Employee("赵六",16,3333.33,Employee.Status.FREE),
new Employee("田七",8,7777.77,Employee.Status.BUSY)
);

@Test
public void test(){
List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList());
list.forEach(System.out::println);

Set<String> set = employees.stream().map(Employee::getName).collect(Collectors.toSet());
set.forEach(System.out::println);

HashSet<String> hashSet = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
hashSet.forEach(System.out::println);

//总数
Long count = employees.stream().collect(Collectors.counting());
System.out.println(count);

//平均值
Double avg = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);

//总和
Double sum = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);

//最大值
Optional<Employee> optional = employees.stream().collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(optional.get());

//最小值
Optional<Double> optional2 = employees.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare));
System.out.println(optional2.get());

//分组
Map<Employee.Status, List<Employee>> map2 = employees.stream().collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map2);

//多级分组
Map<Employee.Status, Map<String, List<Employee>>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() <= 35) {
return "青年";
} else if (e.getAge() <= 50) {
return "中年";
} else {
return "老年";
}
})));
System.out.println(map);

//分区
Map<Boolean, List<Employee>> map3 = employees.stream().collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
System.out.println(map3);


DoubleSummaryStatistics statistics = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(statistics.getSum());
System.out.println(statistics.getMax());
System.out.println(statistics.getAverage());
System.out.println(statistics.getCount());
System.out.println(statistics.getMin());

//连接
String s = employees.stream().map(Employee::getName).collect(Collectors.joining(","));
System.out.println(s);
}

}

Optional类

Optional< T>java.util.Optional是一个容器类,代表一个值存在或不存在。原来用null表示一个值不存在,现在 Optional可以更好的表达这个概念。并且可以避免空指针异常。

  • Optional.of(T t) : 创建一个 Optional 实例
@Test
public void test(){
Optional<Employee> optional = Optional.of(new Employee());
Employee employee = optional.get();
}

//Optional类的of方法的源码如下:
//返回一个指定非null值的Optional。
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}

//Optional类的get方法的源码如下:
//如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
private final T value;
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
  • Optional.empty() : 创建一个空的 Optional 实例
@Test
public void test(){
Optional<Object> optional = Optional.empty();
Object o = optional.get();
}

//Optional类的empty方法的源码如下:
//返回空的 Optional 实例。
private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
  • Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
@Test
public void test(){
Optional<Employee> optional = Optional.ofNullable(new Employee());
Employee employee = optional.get();
}

//Optional类的ofNullable方法的源码如下:
//如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
  • isPresent() : 判断是否包含值
@Test
public void test(){
Optional<Employee> optional = Optional.ofNullable(new Employee());
if(optional.isPresent()){
System.out.println(optional.get());
}
}

//Optional类的isPresent方法的源码如下:
//如果值存在则方法会返回true,否则返回 false。
private final T value;
public boolean isPresent() {
return value != null;
}
  • orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
@Test
public void test(){
Optional<Employee> optional = Optional.ofNullable(new Employee());
Employee employee = optional.orElse(new Employee("田七", 8, 7777.77, Employee.Status.BUSY));
}

//Optional类的orElse方法的源码如下:
//如果存在该值,返回值, 否则返回 other。
private final T value;
public T orElse(T other) {
return value != null ? value : other;
}
  • orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
@Test
public void test(){
Optional<Employee> optional = Optional.ofNullable(new Employee());
Employee employee = optional.orElseGet(() -> new Employee());
}

//Optional类的orElseGet方法的源码如下:
//如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。
private final T value;
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
  • map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
@Test
public void test(){
Optional<Employee> optional = Optional.ofNullable(new Employee("田七",8,7777.77,Employee.Status.BUSY));
Optional<String> optional1 = optional.map((e) -> e.getName());
String s = optional1.get();
}

//Optional类的map方法的源码如下:
//如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
  • flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
@Test
public void test(){
Optional<Employee> optional = Optional.ofNullable(new Employee("田七",8,7777.77,Employee.Status.BUSY));
Optional<String> stringOptional = optional.flatMap((e) -> Optional.of(e.getName()));
String s = stringOptional.get();
}

//Optional类的flatMap方法的源码如下:
//如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}

接口中的默认方法与静态方法

新时间日期API

其他新特性