(一)、Optional
1.Optional的概念
java.util.Optional 是java8中引进的一个新的类,它可以对可能缺失的值进行建模,而不是直接将null赋值给变量。
它是用来规范我们开发的API,使其语义更加的明确,使用Optional修饰的对象,表示该对象可能为null。在一定程度上避免了空指针的问题。
为什么要用Optional?
java中非常讨厌的一点就是nullpoint,碰到空指针就会出错抛Exception,然后需要逐行检查是哪个对象为空,带来大量的不必要精力损耗,抛出NPE错误不是用户操作的错误,而是开发人员的错误,应该被避免,那么只能在每个方法中加入非空检查,阅读性和维护性都比较差。
2.Optional类用法
Optional类的Javadoc描述如下:这是一个可以为null的容器对象。
如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
如果值不存在则isPresent()方法会返回false,调用get()方法会NPE。
创建Optional类对象的方法:
- Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
- Optional.empty() : 创建一个空的 Optional 实例
- Optional.ofNullable(T t):t可以为null
1、创建一个空的
//使用Optional.empty()方法创建一个空的Car类型的Optional对象。 Optional<Student> optionalCar = Optional.empty();
2、创建一个非空值的Optional,如果car为null的话,直接抛出空指针异常(参考上面的图片)。
Car car = new Car(); Optional<Car> car1 = Optional.of(car);
3、创建一个可以为null的Optional,该方法支持car为null,但是会在用到car的地方抛出异常,但不是空指针异常。
Car car = new Car(); Optional<Car> car2 = Optional.ofNullable(car);
判断Optional容器中是否包含对象:
- boolean isPresent() : 判断是否包含对象
- void ifPresent(Consumer<? super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
获取Optional容器的对象:
- T get(): 如果调用对象包含值,返回该值,否则抛异常
- T orElse(T other) :如果有值则将其返回,否则返回指定的other对象。
- T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
- T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
过滤:
- Optional filter(Predicate<? super predicate):如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
映射
- Optional map(Function<? super T,? extends U> mapper):如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
- Optional flatMap(Function<? super T, Optional> mapper):如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象
3.创建Optional类
@Test public void testOption() { // 1.声明一个空Option Optional<Object> empty = Optional.empty(); // 2. 根据一个非空值创建Optional Student student = new Student(); Optional<Object> of = Optional.of(student); // 3. 根据可接受的null 进行创建 Student student1=null; Optional<Student> student11 = Optional.ofNullable(student1); }
4.判断Optional容器中是否包含对象
isPresent不带参数,判断是否为空,ifPresent可以选择带一个消费函数的实例。(isPresent和ifPresent一个是 is 一个是 if 注意一下哈
)
@Test public void testOption() { // 1. isPresent是否有值 Student student = new Student("吉士先生",21,90); Optional<Student> student1 = Optional.ofNullable(student); if (student1.isPresent()){ System.out.println(student.getName()); } // 2. ifPresent有一个Customer匿名内部类 student1.ifPresent(new Consumer<Student>() { @Override public void accept(Student student) { System.out.println(student.getName()); } }); // 3. 匿名内部类,进行lambda处理 student1.ifPresent(s-> System.out.println(s.getName())); }
5.获取Optional容器的对象
@Test public void testOption() throws Exception { Student student = null; Optional<Student> student1 = Optional.ofNullable(student); // 使用get一定要注意,假如student对象为空,get是会报错的 // java.util.NoSuchElementException: No value present Student student3 = student1.get(); // 当student为空的时候,返回我们新建的这个对象,有点像三目运算的感觉 Student student2 = student1.orElse(new Student("李明", 20, 16)); // orElseGet就是当student为空的时候,返回通过Supplier供应商匿名内部类 创建的对象 student1.orElseGet(new Supplier<Student>() { @Override public Student get() { return new Student("李明2", 21, 17); } }); //利用Lambda 实现供应商匿名内部类 {}和return 可以被省略 student1.orElseGet(()->new Student("李明3", 20, 16)); // orElseThrow就是当student为空的时候,可以抛出我们指定的异常 student1.orElseThrow(()->new Exception("抛出我们指定的异常")); }
6.过滤
@Test public void testOption() throws Exception { Student student = new Student("吉士先生",3,20); Optional<Student> os1 = Optional.ofNullable(student); os1.filter(new Predicate<Student>() { // 进行过滤 @Override public boolean test(Student student) { return student.getName().equals("吉士先生"); } }).ifPresent(new Consumer<Student>() { //假如说存在值 @Override public void accept(Student student) { System.out.println("Ok"); } }); os1.filter((s)->s.getName().equals("吉士先生")).ifPresent(d-> System.out.println("OK")); }
7. 映射
Map 源码信息
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)); } }
@Test public void testOption() throws Exception { Student student = new Student("吉士先生",3,20); Optional<Student> os1 = Optional.ofNullable(student); os1.map(new Function<Student, Object>() { //如果不为空,那么就+1岁 @Override public Object apply(Student student) { student.setAge(student.getAge()+1); return student; } }); System.out.println(student); os1.map(s->{s.setAge(s.getAge()+1);return s;}); System.out.println(student); }
这块的map说实话对lambda不是很熟练的 理解起来是很绕脑子的。
这里的map实际上就是用的Function函数,Function函数是有两个参数的,第一个是入参数据类型,第二个是返回数据类型。Function函数作用就是传入一个对象,然后返回一个对象,返回的对象类型可以自己设置。
T 就是代表实例的泛型数据类型,就是谁调用的 入参 必须跟调用者泛型的数据类型一样。
U 就是自己说了算,调用完map之后返回什么数据类型,那么U就设置什么
源码
public static Optional<Integer> stringToInt(String s) { try { return Optional.of(Integer.parseInt(s)); } catch (NumberFormatException e) { e.printStackTrace(); return Optional.empty(); } }
Optional.ofNullable(props.getProperty(name)) .flatMap(OptionalUtils::stringToInt) .filter(i -> i>0) .orElse(0);
(二)、匿名内部类
1.什么是匿名内部类?
我们都知道 Lambda 是一个匿名函数,使用Lambda可以帮我们简化匿名内部类的使用,而匿名内部类在实际开发当中并不怎么用,很多人对他的印象其实并不深,所以我们有必要先了解清楚匿名内部类。
什么是匿名内部类。
匿名内部类,就是没有名字的一种嵌套类。它是Java对类的定义方式之一。
为什么要使用匿名内部类?
在实际开发中,我们常常遇到这样的情况:一个接口/类的方法的某个实现方式在程序中只会执行一次,但为了使用它,我们需要创建它的实现类/子类去实现/重写。此时可以使用匿名内部类的方式,可以无需创建新的类,减少代码冗余。
匿名内部类只可以使用在接口上吗
不是的。匿名内部类可以用在具体类、抽象类、接口上,且对方法个数没有要求。
2.自定义匿名内部类实现
假设当前有一个接口,接口中只有一个方法:
package com.example.springboot01hello.dao; public interface interface1 { void show(); }
为了使用该接口的show方法,我们需要去创建一个实现类,同时书写show方法的具体实现方式
package com.example.springboot01hello.dao; public class interfaceImpl implements interface1{ @Override public void show() { System.out.println("我是实现类"); } }
如果实现类InterfaceImpl全程只使用一次,那么为了这一次的使用去创建一个类,未免太过麻烦。我们需要一个方式来帮助我们摆脱这个困境。匿名内部类则可以很好的解决这个问题。
我们使用匿名内部类
@Test public void test3(){ interface1 interface1 = new interface1() { //实列化一个接口 @Override public void show() { System.out.println("这里是一个匿名内部类"); } }; interface1.show(); }
注意:匿名内部类不能有普通的静态变量声明,只能有静态常量。