null object java_java1.8--Null Object模式
整理这篇博客是因为现在在整理java8中的optional,所以觉得很有必要整理下Null Object模式。java.lang.NullPointerException,只要敢自称Java程序员,那对这个异常就再熟悉不过了。为了防止抛出这个异常,我们经常会写出这样的代码:Person person = people.find("LinkinPark...");
if (person != null)
{
person.doSomething();
}
遗憾的是,在绝大多数Java代码里,我们常常忘记了判断空引用,所以,NullPointerException便也随之而来了。“Null Sucks.”,这就是Doug Lea对空的评价。作为一个Java程序员,如果你还不知道Doug Lea是谁,那赶紧补课,没有他的贡献,我们还只能用着Java最原始的装备处理多线程。"I call it my billion-dollar mistake.",有资格说这话是空引用的发明者,Sir C. A. R. Hoare。你可以不知道Doug Lea,但你一定要知道这位老人家,否则,你便没资格使用快速排序。
OK,现在我们就开始整理下Null Object模式。
在整理Null Object模式之前,我们先来了解下多态的另外一个好处。多态的最根本好处在于,你不必再向对象询问“你是什么类型”而后根据得到的答案调用对象的某个行为,你只管调用该行为就是了,其他的一切多态机制会为你安排妥当。当某个字段内容是null时,多态可扮演另一个较不直观,也较不为人所知的用途。就是设定一种可能某种状态是null的对象,然后在原来对象有可能出现null状态判断的时候不用直接在这个对象上控制,而是用现在这个null
object来取代原来的对象。具体的我们来举一个例子来研究下:
下面是原始代码:package com.linkin.maven.mavenTest;
public class Test
{
private String customerName;//模拟一个顾客名字
//下面方法模拟业务逻辑处理代码
public void test(Site site)
{
if (site.getCustomer() == null)
{
customerName = "这里是可能出现null值的情况";
}
else
{
customerName = site.getCustomer().getName();
}
System.out.println(customerName);
}
public String getCustomerName()
{
return customerName;
}
public static void main(String[] args)
{
Test test = new Test();
Site site = new Site();
//先模拟可能出现null值的情况
test.test(site);
//模拟正常的情况
site.setCustomer(new Customer());
test.test(site);
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: 模拟一个场所类,里面有一个顾客属性表示顾客。
*/
class Site
{
private Customer customer;
public Customer getCustomer()
{
return customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: 模拟一个顾客类
*/
class Customer
{
public String getName()
{
return "这里是正常情况的返回值";
}
}
上面的代码我们看到了,里面有一个null值判断,如果是null处理null值情况,如果非null那么处理正常逻辑。现在我们用Null Object模式来将上面出现的null的情况的逻辑代码抽离到null object对象里面。现在我们在原来的基础上修改,代码如下:
package com.linkin.maven.mavenTest;
public class Test
{
private String customerName;//模拟一个顾客名字
//下面方法模拟业务逻辑处理代码
public void test(Site site)
{
Customer customer = site.getCustomer();
if (customer.isNull())
{
customerName = "这里是可能出现null值的情况";
}
else
{
customerName = customer.getName();
}
System.out.println(customerName);
}
public String getCustomerName()
{
return customerName;
}
public static void main(String[] args)
{
Test test = new Test();
Site site = new Site();
//先模拟可能出现null值的情况
test.test(site);
//模拟正常的情况
site.setCustomer(new Customer());
test.test(site);
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: 模拟一个场所类,里面有一个顾客属性表示顾客。
*/
class Site
{
private Customer customer;
public Customer getCustomer()
{
return customer == null ? Customer.newNull() : customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: 模拟一个顾客类
*/
class Customer implements Nullable
{
public String getName()
{
return "这里是正常情况的返回值";
}
//个人建议创建一个工厂函数,专门用来创建NullCustomer()对象,这样子外部就不知道这个空对象的存在了。
static Customer newNull()
{
return new NullCustomer();
}
@Override
public boolean isNull()
{
return false;
}
}
class NullCustomer extends Customer implements Nullable
{
@Override
public boolean isNull()
{
return true;
}
}
interface Nullable
{
boolean isNull();
}
OK,现在我们重新定义了一个NullCustomer的对象用来做Null Object对象,但是我们的控制分支还在,现在我们继续重构,将上面的null值情况的业务处理代码搬入到null Object对象中,就可以去掉null分支判断了,我们在上面的基础上继续重构,代码如下:
package com.linkin.maven.mavenTest;
public class Test
{
private String customerName;//模拟一个顾客名字
//下面方法模拟业务逻辑处理代码
public void test(Site site)
{
Customer customer = site.getCustomer();
//将原来的控制分支利用java多态,分别移入到了2个对象中,这里就不存在分支了
customerName = customer.getName();
System.out.println(customerName);
}
public String getCustomerName()
{
return customerName;
}
public static void main(String[] args)
{
Test test = new Test();
Site site = new Site();
//先模拟可能出现null值的情况
test.test(site);
//模拟正常的情况
site.setCustomer(new Customer());
test.test(site);
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: 模拟一个场所类,里面有一个顾客属性表示顾客。
*/
class Site
{
private Customer customer;
public Customer getCustomer()
{
return customer == null ? Customer.newNull() : customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: 模拟一个顾客类
*/
class Customer implements Nullable
{
@Override
public boolean isNull()
{
return false;
}
//正常分支不变,还是处理原来的逻辑
public String getName()
{
return "这里是正常情况的返回值";
}
//个人建议创建一个工厂函数,专门用来创建NullCustomer()对象,这样子外部就不知道这个空对象的存在了。
static Customer newNull()
{
return new NullCustomer();
}
}
class NullCustomer extends Customer implements Nullable
{
@Override
public boolean isNull()
{
return true;
}
//原始业务代码逻辑中的控制分支中,出现Null值情况的分支移入到Null Object对象中了
public String getName()
{
return "这里是可能出现null值的情况";
}
}
interface Nullable
{
boolean isNull();
}
OK了,现在代码写完了,完美的去掉了null值判断,关于null值可能出现的情况的业务处理代码我们都放到了Null Object里面了去。
关于Null Object记住一点,空对象一定是常量,它们的任何成分都不会发生变化。因此我们应该使用单例模式,这样子就不管什么时候,我们获得的Null Object对象都是同一个唯一实例了。
下面的代码是最终代码:
package com.linkin.maven.mavenTest;
public class Test
{
private String customerName;//模拟一个顾客名字
//下面方法模拟业务逻辑处理代码
public void test(Site site)
{
Customer customer = site.getCustomer();
//将原来的控制分支利用java多态,分别移入到了2个对象中,这里就不存在分支了
customerName = customer.getName();
System.out.println(customerName);
}
public String getCustomerName()
{
return customerName;
}
public static void main(String[] args)
{
Test test = new Test();
Site site = new Site();
//先模拟可能出现null值的情况
test.test(site);
//模拟正常的情况
site.setCustomer(new Customer());
test.test(site);
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: 模拟一个场所类,里面有一个顾客属性表示顾客。
*/
class Site
{
private Customer customer;
public Customer getCustomer()
{
return customer == null ? Customer.newNull() : customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: 模拟一个顾客类
*/
class Customer implements Nullable
{
@Override
public boolean isNull()
{
return false;
}
//正常分支不变,还是处理原来的逻辑
public String getName()
{
return "这里是正常情况的返回值";
}
//个人建议创建一个工厂函数,专门用来创建NullCustomer()对象,这样子外部就不知道这个空对象的存在了。
static Customer newNull()
{
return NullCustomer.getInstance();
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: Null Object对象,使用单例模式,继承正常业务对象,实现null值判断接口
*/
class NullCustomer extends Customer implements Nullable
{
private static NullCustomer nullCustomer;
private NullCustomer()
{
}
public static NullCustomer getInstance()
{
if (nullCustomer == null)
{
return new NullCustomer();
}
else
{
return nullCustomer;
}
}
@Override
public boolean isNull()
{
return true;
}
//原始业务代码逻辑中的控制分支中,出现Null值情况的分支移入到Null Object对象中了
public String getName()
{
return "这里是可能出现null值的情况";
}
}
/**
* @创建作者: LinkinPark
* @创建时间: 2015年10月30日
* @功能描述: Null值判断接口,正常业务对象和Null值对象都应该实现的接口
*/
interface Nullable
{
boolean isNull();
}
关于上面的重构,以后我会有专门的博客来整理重构的,这里说的就是要一遍重构,一遍测试。上面4个代码的测试结果都一样,也就是表示重构的没问题。下面我贴出上面的控制台输出:
总结:
在Java世界里,解决空引用问题常见的一种办法是,使用Null Object模式。这样的话,在“没有什么”的情况下,就返回Null Object,客户端代码就不用判断是否为空了。但是,这种做法也有一些问题。首先,我们肯定要为Null Object编写代码,而且,如果我们想大规模应用这个模式,我们要为几乎每个类编写Null Object。然后,有的时候业务处理稍微复杂一点,比如一个类包含了多个业务对象属性,这个时候的Null Object对象就会有好几个,编码量也大大的增加了。我们有必要了解这种合理的绕开null值判断的情况,但是如果实际编码这样子写Null
Object类的话,也是一件很恶心的事情。java1.8中引入了Optional类,使用这个类我们可以很方便的实现上面的功能而且不用写很多代码的,这也就是我下篇博客要整理的。
null object java_java1.8--Null Object模式相关推荐
- Introduce Null Object(引入Null对象)
Introduce Null Object(引入Null对象) 你需要再三检查某对象是否为null. 将null值替换为null对象. if (customer == null) plan = Bil ...
- 关于出现org.hibernate.TransientObjectException: The given object has a null identifier: 错误的解决方法
关于出现org.hibernate.TransientObjectException: The given object has a null identifier: 错误的解决方法 参考文章: (1 ...
- org.hibernate.transientobjectexception:The given object has a null identifier: com.gxuwz.check.entit
错误信息: org.hibernate.TransientObjectException: The given object has a null identifier: com.gxuwz.chec ...
- java object 是否为null,java – 为什么cast(Object)null结果为null?
我使用java 7,并创建了一个varargs方法 public class JavaApplicationTest { /** * @param args the command line argu ...
- org.hibernate.TransientObjectException:The given object has a null identifier
1.错误描述 org.hibernate.TransientObjectException:The given object has a null identifier:com.you.model.U ...
- org.springframework.dao.InvalidDataAccessApiUsageException:The given object has a null identifi的解决方案
异常信息: org.springframework.dao.InvalidDataAccessApiUsageException: The given object has a null identi ...
- typescript 提示 Object is possibly null
Object is possibly null: 对象可能是null 分析:localStorage.getItem("SET_HISTORY_KEY") 这个值有可能为空,所以再 ...
- Angular: Object is possibly ‘null‘
Angular开发,提示 Object is possibly 'null' 恼人的提示,谁有那时间写出完美的代码呢,有null是正常的.这提示该关闭.网上找到了关闭的方法: tsconfig.jso ...
- typescript 提示 Object is possibly ‘null‘ 的N种解决方法
document.querySelector('.main-table').setAttribute('height', '300px'); 如上,我要设置某元素的高度,但typescript提示 O ...
- Databinding:setTag(java.lang.Object)‘ on a null object reference 问题处理。
当自定义view使用databinding来赋值时,运行发现在BindingImpl类中报错:view.setTag(java.lang.Object)' on a null object refer ...
最新文章
- matlab练习程序(图像区域分裂)
- 如何在Git中更改多次提交的作者和提交者名称以及电子邮件?
- a为数组名。sizeof(a)和sizeof(a)有什么区别?结果是?
- JQUERY输入改变事件change
- 在Junit上使用Kafka
- envi反演水质参数_基于大气校正法的Landsat 8 TIRS地表温度反演
- SAS Base备考
- JAVA:实现Lucas Series卢卡斯系列算法(附完整源码)
- java.util.Map——Map集合的常用方法
- 6款程序员必备的免费在线画图工具,贼好用!
- Stduino学习(二十四)敲击传感器模块
- Jquery入门指南教程
- 第三代搜索技术展望(转)
- 华为手机疑似鸿蒙,疑似华为自研手机系统现身:名字叫鸿蒙?
- 牛皮癣的肠-脑-皮轴
- 在传染病中,肠道微生物-免疫力-营养在优化治疗策略中的作用
- 谷歌翻译插件imtranslator安装使用步骤
- Android RIL学习
- 关于SVN安装目录下,没有svn.exe程序的解决
- mybatis启动报错Result Maps collection already contains value for xxx
热门文章
- 服务器虚拟机声卡无法加载,Esxi虚拟机添加声卡
- 微表情测试软件排行榜,微表情心理测试分析系统:以“微”见智,识情绪辨人心...
- 三国群雄传ol服务器 修改,三国群英传ol 单机版,如何修改国战、暴率、经验等问题?...
- 围棋知名AI-KataGo 下载分享
- 一个清华学子写的关于directshow的学习心得
- visual basic_什么是Visual Basic?
- 脚本病毒---实验十二:脚本病毒
- PROTEL 99 使用之添加库
- Linux----Ubuntu系统官网下载iso镜像文件
- 下载站源码 php,thinkphp开发素材资源源码下载站整站源代码