对于 Java 参数传入 null 判断思考 您所在的位置:网站首页 判断object不为空 对于 Java 参数传入 null 判断思考

对于 Java 参数传入 null 判断思考

2023-08-01 04:36| 来源: 网络整理| 查看: 265

版权声明:本文章原创于 RamboPan ,未经允许,请勿转载。

对于 Java 参数传入 null 判断思考

最近重温了《Effective Java》之后,在日常工作中写代码时感觉也会慢一点,多一点思考这样是不是比较合理。

在一个常见的情况下迟疑了下:在定义方法时,经常需要传入非基本类型的参数。

//定义一个简单的类 class Hello{ public void say(){ System.out.print("Hello"); } } //类似这种情况,需要传入一个对象进行它的操作 public void test01(Hello hello) { hello.say(); }

按理说我们会在这里进行一个判断,判断是否是空,以防我们在后续使用它的方法时出现空指针。就像这样进行一次判断。

//类似这样的情况,传一个简单的参数 //对字符进行判断一下,如果无效就不进行下一步操作 public void test01(Hello hello) { if(hello == null){ …… return; } hello.say(); }

一:按照一些编程书中的意见,我们最好不要做这些容错机制,如果是第一次调用该方法时,参数传入错误就直接报错,而不是后面发现没有输出 “Hello” 这个字符的时候再来寻找哪里的问题,这样就减少了调试的成本。

二:但是这样一想,要是这段代码自己测着没什么问题,其他懂代码的同事用了之后肯定也会懂。但如果这段代码在你自己的程序里,其他应用传入错误参数时,让你的程序崩溃了,虽然是别人的问题,但是你说是你慌一点还是别人慌一点 …… 🙃

所以感觉这还是要区分场景的,比如在前一种情况下,就是需要直接把问题暴露出来,而在后一种情况,类似于需要保证程序的健壮性,那么还是需要做容错的处理。

在写一个工具类的时候想到有些 Java 框架,在内部使用时,就进行了非空判断的操作。 比如 RxJava 中有个判断工具。

//如果不为空则直接返回该对象 public static T checkNull(T t){ if(t == null) throw new NullPointerException("空指针啦,亲"); return t; } //这样写也是可以的,只是在没法嵌套在其他函数参数中。 public static void checkNull(T t){ if(t == null) throw new NullPointerException("空指针啦,亲"); } //======================= 示范 =================== //定义一个简单的类 class Hello{ public void say(){ System.out.print("Hello"); } } //类似这种情况,需要传入一个对象进行它的操作 public void test01(Hello hello) { hello.say(); } //这种是使用带返回的 checkNull ,可以进行嵌套使用 public void checkNull01(){ Hello hello = new Hello(); test01(checkNull(hello)); } //这种是不带返回的 checkNull ,不能进行嵌套使用,就是多了一行 …… public void checkNull02(){ Hello hello = new Hello(); checkNull(hello); test01(hello); }

其实这种的好处就是在调试期间,如果出错的话,肯定会第一时间找到出错位置,就是类似上面说的第一种情况。

既然要做这种判断非空的工具,那就做一个通用的方法,再做几个简单封装的方法,是常规思路嘛。比如这里我们可以加入需要的 Exception 类型,出错的 String 提示,大概就要这样调用效果。

//定义一个简单的类 class Hello{ public void say(){ System.out.print("Hello"); } } //测试 public void test01() { Hello hello = new Hello(); hello = checkNull(hello,NullPointerException.class,"空指针啦,亲"); }

第一个是需要检测的对象,第二个是异常的类型,第三个就是提示语。 虽然我们这里是只检测是否为空,按理说就应该抛空指针,你还要抛什么其他的花样 ?好奇的你肯定会问。

虽然直观上是空指针,但是如果你在一个方法中对成员变量进行判断,可能这个对象已经完成使命,执行了一些释放的操作,成员变量已经被置空,那么此时如果抛出 IllegalStateException 加上说明,比如 “ xx 已经被释放了,请检查状态 ” 是不是更合适一点 ?所以还是灵活一点好。(毕竟泛型帅嘛,啊哈哈哈)

//通用的接口 public static T checkNull(T t,Class eClazz,String msg){ if(t == null){ try { Constructor eCons = eClazz.getDeclaredConstructor(String.class); eCons.setAccessible(true); throw eCons.newInstance(msg); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } return t; }

第一个参数是对于对象的判断,第二个参数是采用泛型限定了 Exception 类及其子类,第三个参数针对错误的提示。

因为前面的一些限定,所以后续的四个 Exception 中没有再次抛出(比如大部分 Exception 子类,都有单个 String 的构造函数;虽然都是 public,此处也加上了访问权限设置 ,所以忽略了这些情况)

编译器没有提示错误,仿佛没有什么不对,于是编译跑起来试试,毕竟看着对和跑得起来是两回事 …… 果然,编译的途中出错了(男人的直觉 😂)。

错误: 未报告的异常错误CAP#1; 必须对其进行捕获或声明以便抛出 其中, CAP#1是新类型变量: CAP#1从? extends Exception的捕获扩展Exception

说实话这个真的有点摸不着的头脑,感觉逻辑上也没错啊,这究竟是怎么肥事 …… 🤔

直接搜这个错误,还没什么参考,于是把几个关键字都试了一下,看了别人的意见有点启发。

Exception 分为 编译期的错误 与 运行时的错误 ,像 NullPointerException 这种就属于运行时的错误,如果是 Exception 、 IOException 这种一定是需要自己处理了之后才能通过编译的。

处理的方式就是两种,正如报错的提示:必须对其进行捕捉或者声明以便抛出。

//声明:当其他方法调用此方法时需要它处理异常 public void say() throws Exception { …… } //捕捉:这个方法内部已经处理了,其他方法调用时不需要处理 public void say(){ try{ …… }catch(Exception e){ …… } }

现在我们来做个试验,测试下是不是正如我们猜想的那种:这里需要抛出一个 RuntimeException ,而不是 Exception。

public void test01(){ throw new Expcetion("试一试,好像不行"); }

提示: Unhandled Exception: java.lang.Exception

如果我们按照两种处理异常的方式处理一下,那么就没有问题了,也能顺利通过编译。

当然,这不是我们要的结果,此处我们想要的就是在运行时,遇到问题直接抛出(就是这么刚)。

那我们把泛型限定条件改一下: Class



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有