当前位置: 首页 > 科技观察

Java中NullPointerException的完美解决方法

时间:2023-03-12 00:15:55 科技观察

null在Java中带来的麻烦。相信所有Java程序员都一定遇到过NullPointerException。空指针是Java程序中最常见和最烦人的;我们很多程序员都有一种根深蒂固的感觉,凡是可能产生空指针的地方,都要加上if-else检查,但这给我们带来了很多麻烦。Java本身是强类型的,但是null打破了这个规则,它可以赋值给任何对象Java的设计目的是让程序员意识不到指针,但是空指针是个例外,它会让代码非常臃肿,充满了if-else空检查,甚至多层嵌套,代码的可读性降低。Null本身是没有意义的,不能代表什么。前两点不需要特别解释。最后两点用一个例子来说明:如果一个人拥有一部手机,每部手机都有一个制造商,每个制造商都会有一个名字,用类表示:publicclassPerson{privatePhonephone;publicPhonegetPhone(){returnphone;}}publicclassPhone{privateProducerproducer;publicProducergetProducer(){returnproducer;}}publicclassProducer{privateStringname;publicStringgetName(){returnname;}}本例中如果我们需要获取手机厂商名称publicStringgetPhoneProducerName(Personperson){returnperson.getPhone().getProducer().getName();}因为不一定每个人都会有手机,所以在调用getProducer()时可能会出现NullPointerException。设计语言最初是用来描述世界的。在这个例子中,有些人有手机,有些人可能没有手机。所以调用person.getPhone()返回的值应该包括yes和no两种情况,现在通过返回null表示什么都没有,但是在调用getProducer()时会抛出异常,这不符合现实逻辑;所以用null表示什么都不合适是不合适的。这种情况下,通常的做法是做Null检查,甚至检查每个地方可能出现的空指针。publicStringgetPhoneProducerName(Personperson){if(person.getPhone()==null){返回“无姓名”;}if(person.getPhone().getProducer()==null){返回“无姓名”;}returnperson.getPhone().getProducer().getName();}在这里,我尝试降低代码的级别。如果使用if-else,代码的层次会更深,代码的可读性会下降。Optional的简单介绍已经抱怨了很多关于现状的不好的事情,现在我们可以提供我们对Optional的解决方案;叫了半天,还半掩着琵琶。那么什么是Optional,下面我们一步步来揭开它的面纱。Optional本身只是对象的简单包装器。如果对象为空,则构造一个空的Optional;这样Optional就包含了存在和不存在两种情况。接下来就可以看到上面修改后的例子了。publicclassPerson{privateOptionalphone;publicOptionalgetPhone(){returnphone;}}publicclassPhone{privateProducerproducer;publicProducergetProducer(){returnproducer;}}publicclassProducer{privateStringname;publicStringgetName(){returnname;}}因为有些人可能没有手机,有的人都有,所以Phone需要打包Optional;手机本身必须有制造商,制造商必须有名称,所以这两个不需要与Optional一起包装。这里我们会发现,使用Optional会丰富代码的语义,让代码更符合实际。当我们调用phone.getProducer().getName()时,我们不需要检查空指针。如果这里出现了NullPointerException,说明数据本身有问题,不符合实际,应该把问题暴露出来。出来,而不是像上面的代码那样掩盖问题。Optional常用方法使用1.Optional创建方法Optionalempty=Optional.empty();//声明一个空的OptionalOptionalperson=Optional.of(newPerson());//wrapPersonOptionalperson2=Optional.of(null);//不允许操作,传入null会抛出空指针异常OptionaloptionalPerson=Optional.ofNullable(null);//允许传入null,返回空Optional2map,flatMap首先,让我们重新定义Phone类。除了制造商,还有型号;publicclassPhone{privateStringmodel;privateProducerproducer;publicProducergetProducer(){returnproducer;}publicStringgetModel(){returnmodel;}}当我们需要获取手机的型号时,可以这样做:OptionaloptionalPhone=Optional.of(newPhone());可选model=optionalPhone.map(Phone::getModel);当我们需要通过Person对象获取Phone的模型时,你会想到:OptionaloptionalPerson=Optional.of(newPerson());optionalPerson.map(Person::getPhone).map(Phone::获取模型);当我们写出来的时候,发现编译器不能通过。是因为Person::getPhone返回的是一个Optional,而调用optionalPerson.map(Person::getPhone)返回的是一个Optional>,所以通过.map是获取不到手机型号的,那怎么办呢?返回结果不是Optional>,而是Optional?这里需要另一种方法flatMap。flatMap和map的区别,刚开始学习的时候看到网上各种解释很乱,看得头晕目眩。最后直接打开源码,发现实现非常简单易懂。让我们看一下源代码:returnOptional.ofNullable(mapper.apply(value));}}publicOptionalflatMap(Function>mapper){Objects.requireNonNull(mapper);if(!isPresent())returnempty();else{returnObjects.requireNonNull(mapper.apply(value));}}map方法返回时会包裹一层Optional;flatMap在返回的时候直接返回函数的返回值,函数的结果必须是Optional;那么在前面的例子中,直接调用flatMap返回的结果就是OptionalOptionaloptionalPerson=Optional.of(newPerson());optionalPerson.flatMap(Person::getPhone).map(Phone::获取模型);取出OptionalValue对象:get,orElse,orElseGet,orElseThrow,ifPresentget():当知道Optional中有值时,可以直接调用这个方法。当Optional中没有值时,该方法会抛出异常NoSuchElementException;所以当if有value为空的时候,建议不要调用这个方法,因为和做nullcheck没有区别orElse(Tother):提供一个默认值,当value为空时返回这个默认值不存在orElseGet(Supplierother):当值不存在时,调用supper函数。如果返回默认值的逻辑比较多,那么调用这个方法比较合适;orElseThrow(SupplierexceptionSupplier):当值为空时,会抛出自定义异常ifPresent(Consumerconsumer):当值不为空时,会调用消费者函数。如果值为空,那么这个方法什么都不做)));OptionaloptionalPerson=Optional.of(person);optionalPerson.flatMap(Person::getPhone).filter(phone->"IOS".equals(phone.getModel())).map(Phone::getModel).ifPresent(System.out::println);我们讨论了Java程序中的null问题。在Java8中引入了Optional来表示存在和不存在的情况以及初始化的方式。Optional中经常使用的方法如下所示。