为了尽量避免空指针在编码中给我们带来的问题,JAVA8提供了一个包装类Optional来解决空指针异常的问题,该类中包含了许多的方法,一起看看
Optional.of(T t)
该方法用于创建一个Optional实例,T为我们想要创建的类型,比如我们想创建一个Student类型的对象,可以这样写:

Optional<Student> optional=Optional.of(new Student());

在Optional的泛型中放入我们想要新建的对象,用于接收,这样我们就新建了由Optional包装起来的Student类,当我们想取出该student对象时,调用.get()方法:

@Test
    public void test1(){
        Optional<Student> optional=Optional.of(new Student());
        Student student=optional.get();
        System.out.println(student);
    }

这里我们创建的是一个没有任何属性的student对象,运行结果如下:

java接口与方法_默认方法


Optional.empty()

该方法用于创建一个空的Optional实例

@Test
    public void test2(){
        Optional<String > optional = Optional.empty();
        System.out.println(optional.get());
    }

而运行后,不再会报空指针异常,而是如下信息:

java接口与方法_空指针_02


信息告诉我们get方法没有获取到值,也就是optional包装的String没有值,这样我们就可以很快的定位到报空的位置,而不用像以前一样一级一级进行断点调试

Optional.ofNullable(T t):若t不为null,创建Optional实例,否则创建空实例,我们可以将它理解为.of()与.empty()方法的综合

isPresent():判断是否包含值
该方法的逻辑应该在平时编码中会经常用到,比如我们要判断一个对象是否有值,有值才会对其进行操作

Optional<Student> optional = Optional.ofNullable(new Student());
    if (optional.isPresent()){
            System.out.println(optional.get());
        }

orElse(T t):如果调用对象包含值,返回该值,否则返回t
在上一步的基础上,我们继续这个方法,如果该optional对象有值时,我们就返回,否则返回我们指定的一个值:

Optional<Student> optional = Optional.ofNullable(new Student());
    Student student=optional.orElse(new Student(001,"张三",18,183.2));
    System.out.println(student);

运行结果:

java接口与方法_java接口与方法_03


由于我们声明了一个无参的student,该对象有默认值,直接输出打印

接下来我们传入一个空对象

Optional<Student> optional = Optional.ofNullable(null);
    Student student=optional.orElse(new Student(001,"张三",18,183.2));
    System.out.println(student);

运行结果:

java接口与方法_默认方法_04


通过使用替代值的方式,我们就能很好的避免空指针的发生

orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回S获得的值
该方法与orElse方法类似,但它传入的是一个函数式接口,也就是意味着,在orElse方法的基础上,我们还可以通过lambda表达式对替代的值做一些处理。
比方有一个student集合,数据如下:

List<Student> stus= Arrays.asList(
            new Student("张三",16,168.25, Student.Status.FREE),
            new Student("李四",48,178.25,Student.Status.VOCATION),
            new Student("王五",36,148.45,Student.Status.BUSY),
            new Student("赵六",56,180.68,Student.Status.FREE),
            new Student("田七",18,180.68,Student.Status.VOCATION)

    );

现在我们要对集合中的数据进行一次判断,如果没有身高大于181的学生,则返回我们指定的数据,否则返回空对象,利用orElse方法我们可以这样写:

Optional<Student> optional = Optional.ofNullable(null);
        Student student=optional.orElseGet(() ->{
           boolean b = stus.stream().anyMatch((e) ->e.getHeight()>181);
            System.out.println(b);
           if (b){
               return new Student();
           }else {
               return new Student(001,"张三",18,183.2);
           }
        });

        System.out.println(student);

map(Function f)、 flatMap(Function mapper):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
这个方法之前在streamAPI中我们提到过,这里就不多说

接下来我们说一个比较常见的空指针情况,我们有一个班级类MyClass,以及一个学生类MyStudent,班级中有学生,但不一定有某个名叫A的学生,但名叫A的学生是一定存在的。我们要做的是得到该班级中包含的学生姓名,两个实体类如下:

java接口与方法_java接口与方法_05


java接口与方法_System_06


在传统方法中,为了避免空指针,我们会这样写:

public String getStudentName(MyClass myClass){
        if (myClass!=null){
            MyStudent student=myClass.getMyStudent();
            if (student!=null){
                return student.getName();
            }
        }
        return "学生";
    }

然后写下一个测试方法调用该方法得到我们想要的值:

@Test
    public void test5(){
     MyClass myclass=new MyClass();
     String name=getStudentName(myclass);
     System.out.println(name);
    }

先对MyClass对象进行非空判断,再对student对象进行非空判断,利用Optional类,我们可以这样写:

java接口与方法_System_07


放入一个类型为MyStudent类型的空optional类,而获取名字的方法则可以写成这样:

public String getStudentName2(Optional<MyClass> myClass){
       return myClass.orElse(new MyClass()).getOptional().orElse(new MyStudent("学生")).getName();
    }

为了防止MyClass为空,我们将传入的MyClass使用Optional包装起来,在返回时使用orElse方法进行避免,而后再调用其中的get方法得到其中的Optional属性,再对该属性进行一次orElse避免空指针

接下来再说一说接口默认方法:在JAVA8中,允许接口中含有实现的方法(默认方法),使用default关键字修饰即可:

public interface MyFun {
    default String getName(){
        return "aaa";
    }
}

在这种情况下,我们也许会碰到一个冲突的问题,比如我们现在有一个类,也含有同样的方法:

public class TestClass {
    public String getName(){
        return "bbb";
    }
}

有一个类既实现了MyFun接口,又继承了TestClass类:

java接口与方法_System_08


那么当我们调用其中的getName方法时,会调用哪个方法呢?

java接口与方法_默认方法_09


查看运行结果:

java接口与方法_默认方法_10


最终打印的是bbb,也就是调用了父类中的方法,这就说明:当接口中定义了默认方法,而另外一个父类中又定义了一个同名的方法时,会选择父类中的方法。

另外,还会有一个接口冲突的情况出现,假设我们有两个含有同样默认方法的接口,这是第二个:

java接口与方法_java接口与方法_11


而有一个实现类实现了这两个接口

java接口与方法_空指针_12


而这时因为我们没有重写方法导致类名报错,此时因为两个接口的方法相同,若如果我们想实现其中一个,比如我们想实现MyFun中的方法,就需要这么写:

@Override
    public String getName() {
        return MyFun.super.getName();
    }

运行结果:

java接口与方法_java接口与方法_13


同样地,若我们想实现MyDefault中的方法,则把类名更换即可