涉及到对象操作 object.xxxx(),如果对象为null则会抛异常,如果每次都if(o !=null) 代码很丑陋
一种做法是创建对象或者方法返回对象时都new一个对象而不是返回null
不过这样有时也不太好,比如结果为空的时候返回null更合理一点
有更好的建议么 ?
涉及到对象操作 object.xxxx(),如果对象为null则会抛异常,如果每次都if(o !=null) 代码很丑陋
一种做法是创建对象或者方法返回对象时都new一个对象而不是返回null
不过这样有时也不太好,比如结果为空的时候返回null更合理一点
有更好的建议么 ?
有一种模式叫NullObject,意思就是建立一个专用的空对象,以此来代表结果为空。比如这样:
public interface MyObj { public String someOp(); } public class NullObj implements MyObj { public String someOp() { return "It's a content of NullObj"; // 或者抛出一个特定异常,又或者打印出一条警告信息 } } public class NormalObj implements MyObj { public String someOp() { String result = null; // 执行一些正常的代码 return result; } }
用法:
1、建立全局常量:
public enum Constants { //这种写单例的方式在《Effective Java》中被推荐过,非常好的实现方式。 ONE; public final MyObj NULL_OBJ = new NullObj(); //如果用enum写单例的话这里就不用static修饰符了。 }
2、被调用的代码在条件符合的时候返回NullObj:
public class Server { ... public MyObj receive(String param) { if (param == null) { System.out.println("..."); //记录一些log return Constants.ONE.NULL_OBJ; } MyObj result = null; ... return result; } ... }
3、在调用方:
public class Client { public result send(String content) { Server server = null; String result = null; try { ... //初始化server MyObj myObj = server.receive(content); result = myObj.someOp(); //如果你前面选择的是抛出特定异常,则这行代码就必须放在try-catch语句块中了 // 后续的操作就非常灵活了,或比对结果字符串或catch特定异常,取决于你的NullObj是怎么实现的 ... } catch (Exception e) { ... } } }
当然,通过捕获异常来进行流程控制的方式是不被推荐的。NullObject很灵活,可以做出很多扩展性很强的实现方案。
2013年了, 考虑一下 java7的Objects.requireNonNull()方法? http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#requireNonNull%28T%29
1. 如果被调用方法返回可能为null的话,建议每次使用 if(null == o){ //异常分支处理 } 然后再进行正常分支的逻辑代码编写,这样就不会使代码多层条件判断嵌套;代码会美观一些。
2. 一般对于复杂的调用建议返回结果对象,这样可以封装被调用方法需要返回的各种异常状态等信息,便于调用端精细化处理。
在Java的工程实践中,需要经常判断对象是否为null是一个常见都困扰,根据个人经验,我通常不做任何的判断,任其抛出NullPointerException。因为方法或者构造函数中允许参数为null通常并不是一个好的工程设计。或许有人会以为了增加系统的容错性,所以允许null参数来反驳,这也有一定的道理,不过这还是取决于你的类设计。我的经验是,通常要将你所设计的类划分职责,越是倾向于底层逻辑、基础数据操作的类,可以适当的容忍null参数;越是倾向于重要业务逻辑的类,通常不容忍null参数。在处理NullPointerException或者其他RuntimeException的时候,应该有一个统一的错误处理策略。就像Spring中对于Exception的策略一样,所有的方法都抛出RuntimeException。
多说一句,这个话题其实涉及到如何设计你的系统中的错误处理机制。这个绝对是见仁见智的事情,不会有一个绝对正确的答案。
public boolean isNullObject(){
boolean isNull=true;//默认为空
Field[] at = this.getClass().getDeclaredFields();
for (Field field : at) {
field.setAccessible(true);
try {
if (field.get(this) != null){
isNull=false;//只要有一个属性非空,那就认为非空了
break;
}
} catch (Exception e) {
}
}
return isNull;
}
这是是工程设计上常见的问题,一般的解决方案就是 @特价萝卜 所说的NullObject模式。本来想投 @特价萝卜 的答案赞成票,但纠结良久还是觉得说得有些复杂了。
简单来说就是有一个NullObject与原有业务对象实现相同的接口(或继承同一个父类),让客户端调用时可以无感知(也不必判定null)。
有一个很好的例子就是著名JSON解析框架Jackson。以下代码是Jackson从一段JSON中获取其一级子节点lv1下的二级子节点lv2的内容:
以上代码很可能遇到lv1不存在的情况,因此第一个get()就会返回null,那么第二个get()执行时自然就抛出NullPointerException了。为了解决这个问题,作者提供了path方法来替代get方法:
当lv1不存在时,path()返回一个JsonNode的子类叫做MissingNode(但客户端暂时无需知道),MissingNode的path方法则继续返回MissingNode,这样无论这个链式调用写多长都不会抛出任何异常。
直到最后客户端调用完成后检查返回结果是否为MissingNode: