`
deepinmind
  • 浏览: 452333 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:41682
社区版块
存档分类
最新评论

空指针的救星

阅读更多

没人会喜欢空指针异常!有什么方法可以避免它们吗?或许吧。。

本文将讨论到以下几种技术

  • Optional类型(Java 8中新引入的)
  • Objects类(Java 7中原有的)

Java 8中的Optional类

它是什么?

  • Java 8中新引入的类型
  • 它是作为某个指定类型的对象的包装器或者用于那些不存在对象(null)的场景

简单来说,它是处理空值的一个更好的替代品(警告:乍一看可能并没有那么明显)

基本用法

它是一种类型(一个类)——那么,怎么才能创建一个这个类型的实例?
使用下它的三个静态方法就可以了


public static Optional<String> stringOptional(String input) {
    return Optional.of(input);
}

简单明了——创建一个包含这个值的Optional包装器。记住——如果这个值是null的话,它会抛出NPE!


public static Optional<String> stringNullableOptional(String input) {
if (!new Random().nextBoolean()) {
input = null;
}
return Optional.ofNullable(input);
}


我个人认为是要更好一点。这样就不会有NPE的风险了——如果输入为null的话,会返回一个空的Optional。


public static Optional<String> emptyOptional() {
return Optional.empty();
}


如果你真的就是希望返回一个”空"值的话。“空”值并不意味着null。

好吧,那如何去消费/使用Optional呢?



public static void consumingOptional() {
Optional<String> wrapped = Optional.of("aString");
if (wrapped.isPresent()) {
System.out.println("Got string - " + wrapped.get());
}
else {
System.out.println("Gotcha !");
}
}

简单的方法就是检查Optional包装器是否真的有值(使用isPresent方法)——你会怀疑这和使用if(myObj != null)相比有什么好处。别担心,这个我会解释清楚的


public static void consumingNullableOptional() {
String input = null;
if (new Random().nextBoolean()) {
input = "iCanBeNull";
}
Optional<String> wrapped = Optional.ofNullable(input);
System.out.println(wrapped.orElse("default"));
}


你可以使用orElse方法,这样万一封装的确实是一个null值的话可以用它来返回一个默认值——它的好处显而易见。在提取出真实值的时候可以避免调用ifPresent方法这样明显多余的方式了。


public static void consumingEmptyOptional() {
String input = null;
if (new Random().nextBoolean()) {
input = "iCanBeNull";
}
Optional<String> wrapped = Optional.ofNullable(input);
System.out.println(wrapped.orElseGet(
() -> {
return "defaultBySupplier";
}
 
));
}


这个我就有点搞不清楚了。为什么有两个同样目的的不同方法?orElse和orElseGet明明可以重载的(同名但不同参数)。

不论如何,这两个方法明显的区别就在于它们的参数——你可以选择使用lambda表达式而不是Supplier<T>的实例来完成这个(一个函数式接口)

为什么使用Optional要比常见的null检查强?

  • 使用Optional最大的好处就是可以更明白地表述你的意图——返回null值的话会让消费者感到疑惑(当真的出现NPE的时候)这是不是故意返回的,因此还得查看javadoc来进一步定位。而使用Optional就相当明了了。
  • 有了Optional你就可以彻底避免NPE了——如上所提,使用Optional.ofNullable,orElse以及orElseGet可以让我们远离NPE。

另一个救星!

看下这个代码片段

package com.abhirockzz.wordpress.npesaviors;
 
import java.util.Map;
import java.util.Objects;
 
public class UsingObjects {
 
String getVal(Map<String, String> aMap, String key) {
return aMap.containsKey(key) ? aMap.get(key) : null;
}
 
public static void main(String[] args) {
UsingObjects obj = new UsingObjects();
obj.getVal(null, "dummy");
}
}





哪个可能会为空?

  • Map对象
  • 进行搜索使用的key
  • 方法调用的这个实例

如果抛出NPE的话,我们怎么能确定到底是哪个是null的?


package com.abhirockzz.wordpress.npesaviors;
 
import java.util.Map;
import java.util.Objects;
 
public class UsingObjects {
String getValSafe(Map<String, String> aMap, String key) {
Map<String, String> safeMap = Objects.requireNonNull(aMap,
"Map is null");
String safeKey = Objects.requireNonNull(key, "Key is null");
 
return safeMap.containsKey(safeKey) ? safeMap.get(safeKey) : null;
}
 
public static void main(String[] args) {
UsingObjects obj = new UsingObjects();
obj.getValSafe(null, "dummy");
}
}

requireNonNull方法

  • 如果对象不为null的话就返回它本身
  • 如果值为null的话,返回的NPE会带有指定的消息

为什么比if(myObj!=null)要好?

你所看到的栈跟踪信息会很清楚地看见Objects.requireNonNull的方法调用。这个再配合你自己的错误日志,可以让你更快地定位问题。。。至少在我看来是更快。

你还可以自己自义校验器,比如说实现一个简单的校验器来确保没有空值


import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
 
public class RandomGist {
 
    public static <T> T requireNonEmpty(T object, Predicate<T> predicate, String msgToCaller){
        Objects.requireNonNull(object);
        Objects.requireNonNull(predicate);
        if (predicate.test(object)){
            throw new IllegalArgumentException(msgToCaller);
        }
        return object;
    }
 
    public static void main(String[] args) {
        
    //Usage 1: an empty string (intentional)
 
    String s = "";
    System.out.println(requireNonEmpty(Objects.requireNonNull(s), (s1) -> s1.isEmpty() , "My String is Empty!"));
 
    //Usage 2: an empty List (intentional)
    List list =  Collections.emptyList();
    System.out.println(requireNonEmpty(Objects.requireNonNull(list), (l) -> l.isEmpty(), "List is Empty!").size());
 
    //Usage 3: an empty User (intentional)
    User user = new User("");
    System.out.println(requireNonEmpty(Objects.requireNonNull(user), (u) -> u.getName().isEmpty(), "User is Empty!"));
}
 
    private static class User {
        private String name;
 
        public User(String name){
            this.name = name;
        }
 
        public String getName(){
            return name;
        }
    }
}


不要让NPE在错误的地方成为痛苦。我们有许多工具能更好地处理NPE,甚至彻底地根除它们!

 


更多文章请稳步我的个人博客:Java译站

原创文章转载请注明出处:http://it.deepinmind.com


英文原文链接

 

2
0
分享到:
评论

相关推荐

    内存救星内存救星.rar

    内存救星是一款针对计算机内存管理优化的工具,其主要功能是帮助用户提升电脑运行效率,尤其是在内存资源紧张时,能够有效提升系统响应速度。在深入理解这个软件之前,我们需要先了解一些基本的内存管理概念。 内存...

    内存救星内存救星

    内存救星是一款针对计算机内存管理优化的工具,其主要功能是帮助用户提高电脑运行效率,减少因内存资源耗尽导致的系统卡顿、延迟等问题。内存救星通过智能管理和释放内存,可以有效地提升计算机的整体性能。 内存...

    内存救星MemorySaviourV1.0

    "内存救星"会把那些"不常用",但是"必须运行的程序"的内存使用量降到最低,这和传统的"内存整理"是完全不同的!您会有更多空闲内存来运行其它程序,速度会更快。 白名单(仅支持正式版):常用程序,内存救星不干涉此...

    Facefilter相片救星

    《Facefilter相片救星:修复照片的神奇工具》 在我们的数字生活中,照片占据了重要的地位,它们记录了我们珍贵的回忆。然而,由于各种原因,如存储设备故障、文件损坏或病毒攻击,照片可能会变得无法打开或者显示...

    按键救星最新专业版+密钥!

    按键救星最新专业版+密钥!

    键盘救星,键盘按钮坏了可以更改(运行一次就可以了)

    标题中的“键盘救星,键盘按钮坏了可以更改”是指一种软件解决方案,用于处理键盘上某些键位损坏或无法正常工作的问题。在日常使用中,如果遇到键盘上的按键失效,这可能会严重影响到我们的输入效率和工作流程。在...

    内存救星让电脑飞起来!!!

    内存救星是一款针对计算机内存管理的优化工具,其主要功能是清理系统中无用的DLL动态链接库文件,从而释放内存资源,提升电脑运行速度。标题中的“让电脑飞起来”意味着这款软件声称能显著提高计算机的运行效率,...

    相片救星. 单文件

    ( 相片救星. 单文件

    相片救星(可是修补照片

    标题中的“相片救星”是一款专门用于修复破损或损坏照片的软件,它能帮助用户恢复因各种原因导致的照片质量下降或无法正常显示的问题。在描述中提到,“如果不小心经过打包或其他操作破坏了照片”,这可能指的是在...

    内存救星1600%提速内存救星1600%提速内存救星1600%提速

    "内存救星1600%提速"这个标题和描述反复强调了提升内存性能的效果,暗示可能是一种优化工具或者技术,旨在显著改善计算机的运行效率。 内存优化工具通常通过几种方式来提升系统性能: 1. **内存整理**:当内存中的...

    电池救星高级版

    电池救星高级版 GreenPower Premium v9.18.2直装专业版

    内存救星MemorySaviour_1_0

    MemorySaviour内存救星下载介绍:由飞翔下载推荐下载的MemorySaviour内存救星V1.0绿色正式版Windows为每个应用程序平等的分配内存,但这样并不合理。例如:你在玩游戏时,一些内存被IE或QQ占用,你并不想关掉他们,这...

    内存救星(最好的内存整理工具) V1.0

    内存救星是一款被誉为最佳内存整理工具的软件,其V1.0版本的发布,为用户提供了高效、便捷的系统性能优化方案。内存管理是计算机操作系统中的核心任务之一,尤其是在资源需求日益增长的今天,合理利用和优化内存对于...

    内存救星(最有效的内存管理软件,帮你最好的节约内存)

    "内存救星"是一款旨在优化和节省内存使用的软件,它可以帮助用户提高计算机的运行效率。 内存管理软件的主要目标是有效地分配和回收内存资源,防止内存泄漏并确保系统的稳定运行。内存救星通过智能算法监控和调整...

    内存救星,亲测试用,非常棒!

    "内存救星"会把那些"不常用",但是"必须运行的程序"的内存使用量降到最低,这和传统的"内存整理"是完全不同的!您会有更多空闲内存来运行其它程序,速度会更快。 传统内存整理软件的弊端…… 传统的内存整理软件...

    通达信指标公式源码 散户救星副图指标.doc

    "通达信指标公式源码 散户救星副图指标.doc"是一个专门为散户设计的股票分析工具,通过编写特定的指标公式,帮助投资者判断市场趋势和买卖时机。 在这个文档中,我们看到了几个关键的计算指标: 1. **买线和卖线**...

    键盘救星 替换坏的按键

    标题中的“键盘救星 替换坏的按键”指的是在计算机使用过程中,如果键盘上的某个键因为磨损或损坏无法正常工作,我们可以采取一种方法来替代它,使得键盘能继续正常使用。这种技术通常被称为键盘按键映射或者重映射...

    安卓手机系统 按键救星

    【安卓手机系统 按键救星】 在智能手机领域,安卓操作系统占据了主导地位,而作为用户,我们常常会遇到各种各样的问题,其中就包括硬件按键的故障或失效。"按键救星"是一款专为安卓手机设计的应用程序,旨在解决...

    相片救星 FaceFilter 1.0

    《相片救星 FaceFilter 1.0:照片恢复与编辑的强大工具》 在数字化时代,照片已经成为我们记录生活、回忆过去的珍贵载体。然而,由于误操作或设备故障,珍贵的照片可能会丢失,这对于很多人来说是无法接受的。幸运...

    按键救星android

    按键救星android 按键救星android 按键救星android 按键救星android 按键救星android

Global site tag (gtag.js) - Google Analytics