Java8的新特性
速度更快,代码更少(Lambda表达式),强大的Stream API,便于并行,最大化
减少空指针异常(Optional),Nashorn引擎,允许在JVM上允许jS应用
一、Lambda表达式
1.Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,使用它可以写出更简洁、更灵活的代码.
- Lambda表达式:在java8语言中引入的一种新的语法元素和操作符,这个操作符为"->" ,该操作符为称为Lambda操作符
或者箭头操作符,他将Lambda分成两部分:
左侧:指定了Lambda表达式需要的参数列表。
右侧:指定了Lambda体,是抽象方法的实现逻辑,也是Lambda表达式要执行的功能。
3.Lambda表达式的本质:作为一个函数式接口的实例
4.如果一个接口中,只声明了一个抽象方法,则此接口就是一个函数式接口。我们可以在一个接口上使用@FunctionalInterface注解,这样可以检查它是否是一个函数式接口。
基本的使用方式
@Test
public void test1(){
Comparator<Integer> comparator =new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int compare = comparator.compare(12, 21);
System.out.println(compare);
System.out.println("***********************");
//Lambda表达式
Comparator<Integer> comparator1 = (o1,o2) ->Integer.compare(o1,o2);
int compare1 = comparator1.compare(32, 23);
System.out.println(compare1);
System.out.println("********************");
//方法引用
Comparator<Integer> comparator2 = Integer::compare;
int compare2 = comparator2.compare(23, 21);
System.out.println(compare2);
}
Lambda表达式的使用:6种情况
总结:
左边:lambda形参列表的参数类型可以省略(类型推断),如果lambda形参列表只有一个参数,可以省略括号。
右边:lambda体应该使用一对{}包裹,如果lambda体只有一条执行语句(或return时),可以省略括号不写。
语法格式一:无参,无返回值
@Test
public void test(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Lambda表达式");
}
};
//对象调方法
runnable.run();
System.out.println("*************************");
//箭头操作符
Runnable runnable1 =() -> System.out.println("Lambda表达式111");
//对象调方法
runnable1.run();
}
语法格式二:Lambda表达式需要一个参数,但是没有返回值
@Test
public void test1(){
Consumer<String> consumer =new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("语法格式二:Lambda表达式需要一个参数,但是没有返回值1");
System.out.println("*********************");
//Lambda表达式的写法
Consumer<String> consumer1 = (String s) -> { System.out.println(s);};
consumer1.accept("语法格式二:Lambda表达式需要一个参数,但是没有返回值2");
}
语法格式三:数据类型可以省略,因为可由编译器推断得出,称为"类型推断"
@Test
public void test2(){
Consumer<String> consumer = (String s) -> {
System.out.println(s);
};
consumer.accept("语法格式三:数据类型可以省略,因为可由编译器推断得出,称为类型推断");
System.out.println("********************");
Consumer<String> consumer1 = ( s) -> {//类型推断
System.out.println(s);
};
consumer1.accept("语法格式三:数据类型可以省略,因为可由编译器推断得出,称为类型推断1");
}
语法格式四:Lambda 若只需要一个参数,参数的小括号也可以省略
@Test
public void test3(){
Consumer<String> consumer1 = ( s) -> {//类型推断
System.out.println(s);
};
consumer1.accept("语法格式四:Lambda 若只需要一个参数,参数的小括号也可以省略");
System.out.println("***********************");
Consumer<String> consumer = s -> {//类型推断
System.out.println(s);
};
consumer.accept("语法格式四:Lambda 若只需要一个参数,参数的小括号也可以省略1");
}
语法格式五:lambda表达式需要两个或以上参数,多条执行语句,并且可以有返回值
@Test
public void test4(){
Comparator<Integer> comparator = new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
System.out.println(comparator.compare(12,21));
System.out.println("****************");
Comparator<Integer> comparator1 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(comparator1.compare(23,13));
}
语法格式六:当lambda体只有一条语句时,return 与 大括号若有,都可以省略
@Test
public void test5(){
Comparator<Integer> comparator1 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(comparator1.compare(23,13));
System.out.println("****************");
Comparator<Integer> comparator2 = (o1,o2) -> o1.compareTo(o2);
System.out.println(comparator2.compare(23,13));
}
二、 java8 四大内置核心函数式接口
2.1、Consumer:消费型接口 —> void accept(T t)
2.2、Supplier:供给型接口 —> T get()
2.3、Function<T, R>:函数型接口 —> R apply(T t)
2.4、Predicate:断言型接口 —> boolean test(T t)
其他的函数式接口
1.BiFunction<T, U, R>
参数类型有2个,为T,U,返回值为R,对类型T,U参数的应用操作,其中方法为R apply(T t, U u)
2.UnaryOperator(Function子接口)
参数为T,对参数为T的对象进行一元操作,并返回T类型结果,其中方法为T apply(T t)
3.BinaryOperator(BiFunction子接口)
参数为T,对参数为T得对象进行二元操作,并返回T类型得结果,其中方法为T apply(T t1, T t2)
4.BiConsumcr(T, U)
参数为T,U无返回值,其中方法为 void accept(T t, U u)
5.ToIntFunction、ToLongFunction、ToDoubleFunction
参数类型为T,返回值分别为int,long,double,分别计算int,long,double得函数。
6.IntFunction、LongFunction、DoubleFunction
参数分别为int,long,double,返回值为R。
2.1、Consumer:消费型接口 —> void accept(T t)
@Test
public void test(){
happTime(500, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("Consumer<T>:消费型接口 ---> void accept(T t): " + aDouble);
}
});
System.out.println("*******************");
//lambda表达式
happTime(450,money -> System.out.println("Consumer<T>:消费型接口 ---> void accept(T t): " + money));
}
public void happTime(double money, Consumer<Double> con){
con.accept(money);
}
2.4、Predicate:断言型接口 —> boolean test(T t)
@Test
public void test1(){
List<String> list = Arrays.asList("刘备","刘邦","刘婵","流畅","流弊","刘二狗");
List<String> strings = filterString(list, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("刘");
}
});
System.out.println(strings);//[刘备, 刘邦, 刘婵, 刘二狗]
System.out.println("*********************");
//lambda表达式
List<String> strings1 = filterString(list,s -> s.contains("刘"));
System.out.println(strings1);
}
//根据特点的规则,过滤集合中的字符串,此规则由Predicate的方法决定
public List<String> filterString(List<String> list, Predicate<String> pre){
ArrayList<String> filterList = new ArrayList<>();
for (String s : list){
if (pre.test(s)){
filterList.add(s);
}
}
return filterList;
}
三、方法引用和构造器引用
1.方法引用的使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
2.方法引用,本质上是Lambda表达式,而Lambda表达式作为函数式接口的实例。所有方法引用,也是函数式接口的实例
3.要求:实现接口的抽象方法的参数列表和返回类型,必须与方法引用的方法的参数列表和返回值类型保持一致。
4.格式:使用操作符"::"将类(或对象)与方法名分隔开来
如下三种主要使用情况:
①对象::实例方法名
②类::静态方法名
③类::实例方法名
方法引用的实例
@Test
public void test(){
Comparator<Integer> com1 = (t1,t2) ->Integer.compare(t1,t2);
System.out.println(com1.compare(12,21));
System.out.println("**********************");
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(12,3));
}
@Test
public void test1(){
Function<Double,Long> function = new Function<Double, Long>() {
@Override
public Long apply(Double aDouble) {
return Math.round(aDouble);
}
};
System.out.println("************************");
Function<Double,Long> function1 =d -> Math.round(d);
System.out.println(function1.apply(12.3));
System.out.println("**************************");
Function<Double,Long> function2 = Math::round;
System.out.println(function1.apply(12.6));
}
//情况三
@Test
public void test2(){
Comparator<String> com1 =(s1,s2) -> s1.compareTo(s2);
System.out.println(com1.compare("abc", "abd"));
System.out.println("*************************");
//方法引用
Comparator<String> com2 = String::compareTo;
System.out.println(com2.compare("abd", "abm"));//-9
}
@Test
public void test3(){
//比较两个参数,是否相等
BiPredicate<String,String> pre1 = (s1,s2) ->s1.equals(s2);
System.out.println(pre1.test("abc","abc"));//true
System.out.println("**********************");
BiPredicate<String,String> pre2 = String::equals;
System.out.println(pre2.test("abc","abd"));//false
}
@Test
public void test4(){
Consumer<String> consumer1 = str -> System.out.println(str);
consumer1.accept("北京");
System.out.println("***********************");
PrintStream ps = System.out;
Consumer<String > consumer2 =ps::println;
consumer2.accept("beijing");
}
构造器引用和数组引用
构造器引用
1.Supplier中的T get()
2.Function中的R apply(T t)
@Test
public void test(){
Supplier<Employee> sup = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};
System.out.println(sup.get());
System.out.println("*********************");
Supplier<Employee> sup1 = () -> new Employee();
System.out.println("************************");
Supplier<Employee> sup2 = Employee::new;
}
数组引用
Function中的R apply(T t)
@Test
public void test1(){
Function<Integer,String[]> function1 = length -> new String[length];
String[] arr = function1.apply(5);
System.out.println(Arrays.toString(arr));//[null, null, null, null, null]
System.out.println("******************");
Function<Integer,String[]> function2 = String[]::new;
String[] arr1 = function2.apply(10);
System.out.println(Arrays.toString(arr1));
}
三、函数式接口:只有一个抽象方法的接口,我们可以在接口中使用@FunctionalInterface来检查他是否是函数式接口
强调:Lambda表达式的本质:作为一个函数式接口的实例
@FunctionalInterface
public interface MyInterface {//只能有应该抽象方法
void method();
}
四、强大的Stream API
Stream API:把真正的函数式编程风格引入到了Java中,这是目前为止对java类库的最后的补充, 因为Stream API 可以极大的提供生产力,让代码更加的简洁、干净、高效率
1.使用Stream API 对集合数据进行操作,就类似于SQL执行的数据库查询,
Stream 和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存的,存储在内存的,后者主要是面向CPU, 通过CPU实现计算。
2.什么是Stream?
是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列。“集合讲的是数据,Stream讲的是计算!”
3.注意:
①Stream自己不会存储对象。
②Stream不会改变源对象,相反,他们会返回一个持有结果的新Stream。
③Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。
4.Stream的操作的三个步骤
①创建Stream:一个数据源(集合,数组),获取一个流()实例化
②中间操作:一个中间的操作(过滤,排序、映射、归约…)链,对数据源的数据进行处理
③终止操作:一旦执行终止操作,就执行中间操作链,并产生结果之后,不会在被使用
Stream API的测试类1
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
if (id != employee.id) return false;
if (age != employee.age) return false;
if (Double.compare(employee.salary, salary) != 0) return false;
return name != null ? name.equals(employee.name) : employee.name == null;
}
public Employee() {
}
@Override
public int hashCode() {
int result;
long temp;
result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
temp = Double.doubleToLongBits(salary);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
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) {
this.id = id;
this.name = name;
this.age = age;
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public Employee(int id) {
this.id = id;
}
}
Stream API的测试类2
public class EmployeeData {
public static List<Employee> getEmployees(){
List<Employee> list = new ArrayList<>();
list.add(new Employee(1001,"张三1",18,1234));
list.add(new Employee(1002,"张三2",19,3244));
list.add(new Employee(1003,"张三3",20,14545));
list.add(new Employee(1004,"张三4",21,215));
list.add(new Employee(1005,"张三5",22,2154));
list.add(new Employee(1006,"张三6",23,5788));
list.add(new Employee(1007,"张三7",24,2894));
list.add(new Employee(1008,"张三8",25,9845));
list.add(new Employee(1009,"张三9",26,25854));
return list;
}
}
测试Stream的实例化
创建Stream方式一:通过集合
@Test
public void test(){
List<Employee> employees = EmployeeData.getEmployees();
//default Stream<E> stream():返回一个顺序流
Stream<Employee> stream = employees.stream();
//default Stream<E> parallelStream():返回一个并行流
Stream<Employee> stream1 = employees.parallelStream();
}
创建Stream方式二:通过数组
@Test
public void test1(){
int[] arr = new int[]{1,2,3,4,5};
//调用Arrays类的static <T> Stream<T> stream(T[] array):返回一个流
IntStream stream = Arrays.stream(arr);
Employee employee1 =new Employee(1001,"Tom");
Employee employee2 =new Employee(1002,"Jerry");
Employee[] employees = new Employee[]{employee1,employee2};
Stream<Employee> stream1 = Arrays.stream(employees);
}
创建Stream方式三:通过Stream的of()
@Test
public void test2(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
}
创建Stream方式四:创建无限流
@Test
public void test3(){
//迭代
//public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f)
//遍历前10个偶数
Stream.iterate(0,t-> t + 2).limit(10).forEach(System.out::println);
//生成
//public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
Stream的中间操作:多个中间操作可以连接成一个流水线,除非流水线上的触发终止操作,否则中间操作不会执行任何的处理,而是在终止操作时一次性全部处理称为"惰性求值"
一.筛选与切片
1、filter(Predicate p)——过滤Lambda , 从流中排除某些元素。
2、limit(n)——截断,使其元素不超过给定数量。
3、skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
4、distinct——除重,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
@Test
public void test(){
List<Employee> list = EmployeeData.getEmployees();
// 1、filter(Predicate p)——过滤Lambda , 从流中排除某些元素。
Stream<Employee> stream = list.stream();
//查询大于3000的salary数
stream.filter(e -> e.getSalary() > 3000).forEach(System.out::println);
System.out.println("********************");
//2、limit(n)——截断,使其元素不超过给定数量。
//异常IllegalStateException,一旦进行终止操作,就关闭了,的重新创建
//stream.limit(3).forEach(System.out::println);
list.stream().limit(3).forEach(System.out::println);
System.out.println("*********************");
//3、skip(n) —— 跳过,返回一个扔掉了前 n 个元素的流。
list.stream().skip(3).forEach(System.out::println);
System.out.println("******************");
//4、distinct——除重,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
list.add(new Employee(1010,"张三10",2285));
list.add(new Employee(1010,"张三10",2285));
list.add(new Employee(1010,"张三10",2285));
list.add(new Employee(1010,"张三10",2285));
list.stream().distinct().forEach(System.out::println);
}
二、映射
@Test
public void test1(){
/*
2.1、map(Function f):接收一个函数作为参数,将元素转换为其他形式或提取信息,该函数会被应用到
每个元素上,并将其映射成为一个新的元素。
2.2、flatMap(Function f):接收一个函数作为参数,
将流中的每一个值都转换成为另一个流,然后把流连接成一个流
*/
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
list.stream().map( str -> str.toUpperCase()).forEach(System.out::println);
//练习1:
List<Employee> employees = EmployeeData.getEmployees();
Stream<String> stringStream = employees.stream().map(Employee::getName);
stringStream.filter(name -> name.length() > 3).forEach(System.out::println);
System.out.println("***************");
//练习2:得到list中的一个个的字符
Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::formStringToStream);
streamStream.forEach(s ->{
s.forEach(System.out::print);//aabbccdd
});
/*
2.2、flatMap(Function f):接收一个函数作为参数,
将流中的每一个值都转换成为另一个流,然后把流连接成一个流
*/
Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::formStringToStream);
characterStream.forEach(System.out::print);//aabbccdd
}
//将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> formStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for (Character character:str.toCharArray()){
list.add(character);
}
return list.stream();
}
三、排序
@Test
public void test2(){
//sorted()---自然排序
List<Integer> list = Arrays.asList(12,254,45,0,-52,43,7);
list.stream().sorted().forEach(System.out::println);
System.out.println("*******************");
//抛异常:原因:Employee没有实现Comparable接口
//在java中涉及到对象的排序Comparator和Comparable
// List<Employee> employees = EmployeeData.getEmployees();
// employees.stream().sorted().forEach(System.out::println);
//sorted(Comparator com) ---定制排序
//方式一
// List<Employee> employees = EmployeeData.getEmployees();
// employees.stream().sorted((e1,e2) -> {
// //按照年龄排序
// return Integer.compare(e1.getAge(),e2.getAge());
//
// }).forEach(System.out::println);
//方式二
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted((e1,e2) -> {
//按照年龄排序,年龄相同salary按照排
int ageValue = Integer.compare(e1.getAge(),e2.getAge());
if (ageValue!=0){
return ageValue;
}else {
return -Double.compare(e1.getSalary(),e2.getSalary());
}
}).forEach(System.out::println);
}
Stream的终止操作
1.匹配与查找
allMatch(Predicate p) 检查是否匹配所有元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
count() 返回流中总数
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。
@Test
public void test() {
//allMatch(Predicate p) 检查是否匹配所有元素
List<Employee> employees = EmployeeData.getEmployees();
boolean anyMatch = employees.stream().anyMatch(e -> e.getAge() > 18);
System.out.println(anyMatch);//true
// anyMatch(Predicate p) 检查是否至少匹配一个元素
boolean anyMatch1 = employees.stream().anyMatch(e -> e.getSalary() > 10000);
System.out.println(anyMatch1);//true
// noneMatch(Predicate p) 检查是否没有匹配所有元素
boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("张"));
System.out.println(noneMatch);//false
// findFirst() 返回第一个元素
Optional<Employee> first = employees.stream().findFirst();
System.out.println(first);//Optional[Employee{id=1001, name='张三1', age=18, salary=1234.0}]
// findAny() 返回当前流中的任意元素
Optional<Employee> any = employees.parallelStream().findAny();
System.out.println(any);//Optional[Employee{id=1001, name='张三1', age=18, salary=1234.0}]
// count() 返回流中总数
long count = employees.stream().filter(e -> e.getSalary() > 3000).count();
System.out.println(count);//5
// max(Comparator c) 返回流中最大值
Stream<Double> doubleStream = employees.stream().map(e -> e.getSalary());
Optional<Double> maxSalary = doubleStream.max(Double::compare);
System.out.println(maxSalary);//Optional[25854.0]
// min(Comparator c) 返回流中最小值
Optional<Employee> min = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(min);//Optional[Employee{id=1004, name='张三4', age=21, salary=215.0}]
// forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代)。
System.out.println("*****************");
employees.stream().forEach(System.out::println);//终止操作
}
2.归约
reduce(T identity, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional
@Test
public void test1(){
// reduce(T iden, BinaryOperator b)
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer reduce = list.stream().reduce(0, Integer::sum);
System.out.println(reduce);//55 累加和
// reduce(BinaryOperator b)
List<Employee> employees = EmployeeData.getEmployees();
Stream<Double> stream = employees.stream().map(Employee::getSalary);
Optional<Double> reduce1 = stream.reduce(Double::sum);
System.out.println(reduce1);//Optional[65773.0]求总金额
}
3.收集
@Test
public void test2(){
//collect (Collector c) 将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
//Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List,Set,Map).
// 但是Collectors实现类中提供了许多静态方法,可以方便的创建常见的收集器实例.
List<Employee> employees = EmployeeData.getEmployees();
List<Employee> collect = employees.stream().filter(e -> e.getSalary() > 3000).collect(Collectors.toList());
collect.forEach(System.out::println);//返回salary大于3000的集合
}
五、 Optional类:为例避免空指针异常而创建的。
1.NullPointerException相信每个JAVA程序员都不陌生,是JAVA应用程序中最常见的异常。之前,Google Guava项目曾提出用Optional类来包装对象从而解决NullPointerException。受此影响,JDK8的类中也引入了Optional类
2.Optional 实际上是个容器类:它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念,并且可以避免空指针异常
Optional.of(T t) : 创建一个 Optional 实例。
Optional.empty() : 创建一个空的 Optional 实例。
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例。
isPresent() : 判断是否包含值。
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t。
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值。
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()。
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional。
Optional测试类1
public class Boy {
private Girl girl;
@Override
public String toString() {
return "Boy{" +
"girl=" + girl +
'}';
}
public Girl getGirl() {
return girl;
}
public void setGirl(Girl girl) {
this.girl = girl;
}
public Boy() {
}
public Boy(Girl girl) {
this.girl = girl;
}
}
Optional测试类2
public class Girl {
private String name;
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Girl() {
}
public Girl(String name) {
this.name = name;
}
}
创建Optional类和对象的方法
@Test
public void test() {
//Optional.of(T t) : 创建一个 Optional 实例。
Girl girl = new Girl();
//如果为空,就出现空指针异常
//girl = null;
Optional<Girl> optionalGirl = Optional.of(girl);
//Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例。
}
@Test
public void test1(){
//Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例。
Girl girl = new Girl();
girl = null;
Optional<Girl> optionalGirl = Optional.ofNullable(girl);
System.out.println(optionalGirl);//Optional.empty
//orElse(T t1):如果当前的Optional内部封装的t时非空的,就将其返回的t
//如果内部的t时空的,就返回toElse()方法中的参数t1。
Girl girl1 = optionalGirl.orElse(new Girl("张三"));
System.out.println(girl1);//Girl{name='张三'}
}
public String getGirlName(Boy boy){
return boy.getGirl().getName();
}
@Test
public void tets2(){
Boy boy = new Boy();
String girlName = getGirlName(boy);
System.out.println(girlName);//出现空指针异常
}
//优化后的getGirlName方法
public String getGirlName1(Boy boy){
if(boy != null){
Girl girl = boy.getGirl();
if (girl !=null){
return girl.getName();
}
}
return null;
}
@Test
public void tets3(){
Boy boy = new Boy();
String girlName = getGirlName1(boy);
System.out.println(girlName);//null
}
//使用Optional类的getGirlName()
public String getGirlName2(Boy boy){
Optional<Boy> optionalBoy = Optional.ofNullable(boy);
Boy boy1 = optionalBoy.orElse(new Boy(new Girl("张三三")));
Girl girl = boy1.getGirl();
Optional<Girl> girlOptional = Optional.ofNullable(girl);
//此时girl1中的数据一定为空
Girl girl1 = girlOptional.orElse(new Girl("张四四"));
return girl1.getName();
}
@Test
public void test4(){
Boy boy = null;//张三三
boy = new Boy();//张四四
String girlName2 = getGirlName2(boy);
System.out.println(girlName2);
}