【jdk源码2】Objects源码学习
在学习上一个类TreeMap的时候,提到了这个类,这个类是jdk1.7新增的,里面有很多实用的方法。就是一个工具类,熟悉以后,如果里面有已经实现的方法,那么就不要再去实现了,省时省力省测试。
一、简单理解
这是一个工具类,介绍相对会简单些,基本都是方法的介绍。
1.1 类名的命名
Objects是一个主要针对对象的工具类,所以它的命名只是在后面加上一个s,就像Arrays是操作数组的工具类一样。这就涉及到一种设计理念,那就是工具方法应该放在哪:
- 放在使用的类里
- 按操作属性进行归类,如StringUtils,FileUtils,MapUtils等等
- 全部放到一个类里,Utils
第一种不太建议,既然都是一个工具类,那么就应该拿出来给别人用,或者自己以后用。
第二种和第三种我比较不出来,我用的是第三种,建立一个大而全的Utils类,当然它们之间还是可以比较的:
- 多个工具类:使用的时候需要想在哪个里面,优点就是可以按照方法所操作进行分组,但是有时候有的工具类就是不知道怎么分组
- 一个工具类:一个缺点就是方法命名一定要好,毕竟方法多了不好找,优点就是工具类好找,而且方法可以重载,比如判断是否为空,就可以重载Map、Collection、String等。
1.2 工具类的特性
先看下面一部分代码:
public final class Objects {
private Objects() {
throw new AssertionError("No java.util.Objects instances for you!");
}
}
因为是工具类加上final不让别人继承,还有就是构造方法加上私有并抛异常。
说实话我觉得没有必要这么做,或许他们考虑的比较多,但是这么做也没什么坏处,以后我写工具类也这样,显得高大上一些。
1.3 对象equals比较
Objects里面提供两种比较方式:
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
public static boolean deepEquals(Object a, Object b) {
if (a == b)
return true;
else if (a == null || b == null)
return false;
else
return Arrays.deepEquals0(a, b);
}
其中我们普遍使用的就是equals,然后我看deepEquals的源码的时候,发现了一个之前忽略的事然后我做了测试:
int[] a1=new int[]{1};
int[] a2=new int[]{1};
System.out.println(a1.equals(a2));
结果是false,也就是说因为数组(以数字为下标,不代表里面的内容是数字)的equals都是false,除非它们是同一个对象。也就是说我们以后如果要做两个对象的相等判断,如果比较的是两个数组那么记得使用Objects的deepEquals方法。
1.4 对null值的简单包装
大家都知道在null值对象上调用任何方法都会报空指针异常,在一些需要判断对象是否是null的情况下,抛异常是有必要的,但是当可以允许null值的时候,很多Object常用的方法就需要额外的处理,而Objects就帮我们做了:
public static String toString(Object o) {
return String.valueOf(o);
}
public static int hash(Object... values) {
return Arrays.hashCode(values);
}
public static String toString(Object o, String nullDefault) {
return (o != null) ? o.toString() : nullDefault;
}
所以使用起来很方便,但是一定要注意使用场景,保证null值是有效值的时候使用。
1.5 null值检查需要自己做吗
很多时候,我们需要保证入参的正确性,最简单的就是传入的不能是null,如果说上层需要将错误原因展示给用户看,我们就需要主动检查是否为null,并且主动返回null值所代表的信息(比如说用户名不能为空啦,邮箱不能为空啦),而不是抛异常。
但是当不需要给用户看的时候,那就可以直接将异常抛出来就可以了,这就有两种策略:
- 主动检查是否为null,并抛异常
- 被动检查,等待程序调用null上面的方法时抛异常
现在大多数人都很少主动去检查null值,我觉得这是不好的编程习惯,我认为应该在方法入口的时候主动检查null值并抛异常,原因如下:
- 早点抛异常,在查看堆栈信息的时候,能更快速的定位异常原因
- 早点抛异常还能够,不再执行额外的代码,避免执行大部分代码以后才抛出异常
所以建议以后写代码的时候多多主动检查,使用
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
public static <T> T requireNonNull(T obj, String message) {
if (obj == null)
throw new NullPointerException(message);
return obj;
}
上面说的好处你会慢慢体会到的。
1.6 延迟消息的好处
现在先看下面两个方法,同样是判断null值的:
public static <T> T requireNonNull(T obj, String message) {
if (obj == null)
throw new NullPointerException(message);
return obj;
}
public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
if (obj == null)
throw new NullPointerException(messageSupplier.get());
return obj;
}
传入的message是在当参数是null值的时候传入给异常使用的,但是为什么会有两个方法呢,而且第二个看起来远远比第一个麻烦,我们先看怎么使用:
public void test1(String param){
Objects.requireNonNull(param, "param can not be null");
//do something about param
}
上面是方法一调用的方式,很简洁明了,下面是方法二的调用方式:
public void test2(String param){
Objects.requireNonNull(param, new Supplier<String>() {
@Override
public String get() {
return "param can not be null";
}
});
//do something about param
}
public void test3(String param){
Objects.requireNonNull(param, ()->"param can not be null");
//do something about param
}
有两种方式,第二种是jdk8的lambada表达式,如果不了解的话,希望抽时间学习一下还是有必要的。
可以看到延迟消息的调用要比普通消息复杂,但是为什么还要推荐这种方式呢?再举一个例子,以前我看过如下记录日志的方式:
if(log.isDebugEnabled()){
log.debug("read file sucess, read info is :"+properties);
}
当时我对这种代码嗤之以鼻,我觉得明明log.debug在里面已经判断日志级别了,为什么在外面还要在判断一次,现在想想当时还是太年轻。如果你仔细想想或许能发现,如果我们提前判断日志级别那么,当不符合日志级别的时候我们就不需要拼接字符串,而如果我们直接用:
log.debug("read file sucess, read info is :"+properties);
用上面代码的话,我们就需要每次都要拼接完字符串后再进行判断,而debug日志基本上量都特别大,而且基本不会打印,这也就造成了字符串拼接过多,而字符串会放到常量池里。
所以简单总结下延迟消息的好处,那就是在需要的时候才进行拼接,这个在log4j2中已经提供相应的支持,但是这个好处到底有多少,我现在还不清楚。
二、问题及总结
这个类是一个工具类,很多方法用起来都很方便,如果用的好的话,应该能解决程序中出现的大部分NullPointerException,所以呢以后对常用的方法要做到封装复用。
2.1 遗留问题
大致看来遗留一个未深入研究的问题
2.1.1 延迟消息能高效在哪
上面1.6讲解了延迟消息,我只知道延迟消息有好处,虽然jdk注释中也明说了:
the costs of creating the message supplier are less than the cost of just creating the string message directly
创建延迟消息要比直接创建字符串高效,但是能高效多少呢,这是一个疑问,当然这也牵扯到jvm对字符串的处理。我会抽时间做如下深入测试和研究:
- jvm中的常量池
- jvm对常量池如何回收
- 字符串是否会导致内存泄漏
当然研究和测试只是为了验证论点,这不能成为不用这个技术的理由,以后的使用场景我还是会使用延迟消息的。
【jdk源码2】Objects源码学习的更多相关文章
- 如何查看JDK以及JAVA框架的源码
如何查看JDK以及JAVA框架的源码 设置步骤如下: 1.点 “window”-> "Preferences" -> "Java" -> &q ...
- 如何定位jdk中的native方法源码?
前提条件:已下载openjdk的源码. 以System类的arraycopy为例: 1. 根据关键字定位文件:grep -rn '"arraycopy"' ./openjdk关键字 ...
- [转帖]cocos2D-X源码分析之从cocos2D-X学习OpenGL(3)----BATCH_COMMAND
原贴: cocos2D-X源码分析之从cocos2D-X学习OpenGL(3)----BATCH_COMMAND 上一篇介绍了QUAD_COMMAND渲染命令,顺带介绍了VAO和VBO,这一篇介绍批处 ...
- [转帖]cocos2D-X源码分析之从cocos2D-X学习OpenGL(2)----QUAD_COMMAND
原文:cocos2D-X源码分析之从cocos2D-X学习OpenGL(2)----QUAD_COMMAND 上一篇文章介绍了cocos2d-x的基本渲染结构,这篇顺着之前的渲染结构介绍渲染命令QUA ...
- 如何阅读jdk及开源框架的源码?
1.熟悉设计模式 可以边读源码 ,边熟悉设计模式,理解编程思想. jdk中对应的设计模式见:http://blog.csdn.net/gtuu0123/article/details/6114197 ...
- JDK中String类的源码分析(二)
1.startsWith(String prefix, int toffset)方法 包括startsWith(*),endsWith(*)方法,都是调用上述一个方法 public boolean s ...
- 【JDK命令行 一】手动编译Java源码与执行字节码命令合集(含外部依赖引用)
写作目标 记录常见的使用javac手动编译Java源码和java手动执行字节码的命令,一方面用于应对 Maven 和 Gradle 暂时无法使用的情况,临时生成class文件(使用自己的jar包):另 ...
- ArrayDeque(JDK双端队列)源码深度剖析
ArrayDeque(JDK双端队列)源码深度剖析 前言 在本篇文章当中主要跟大家介绍JDK给我们提供的一种用数组实现的双端队列,在之前的文章LinkedList源码剖析当中我们已经介绍了一种双端队列 ...
- JAVA源码分析-HashMap源码分析(一)
一直以来,HashMap就是Java面试过程中的常客,不管是刚毕业的,还是工作了好多年的同学,在Java面试过程中,经常会被问到HashMap相关的一些问题,而且每次面试都被问到一些自己平时没有注意的 ...
- spring源码解析——spring源码导入eclipse
一.前言 众所周知,spring的强大之处.几乎所有的企业级开发中,都使用了spring了.在日常的开发中,我们是否只知道spring的配置,以及简单的使用场景.对其实现的代码没有进行深入的了 ...
随机推荐
- (转)Python 日志处理(三) 日志状态码分析、浏览器分析
原文:https://www.cnblogs.com/i-honey/p/7791564.html 在企业中,从日志中提取数据进行分析,可以帮助企业更加了解用户行为,用户最感兴趣的产品或者内容,分析得 ...
- 整理学习ASP.NET MVC的资源
网站 http://www.asp.net/mvc http://stackoverflow.com/questions/tagged/asp.net-mvc+asp.net-mvc-4?sort=n ...
- redisTemplate实现轻量级消息队列, 异步处理excel并实现腾讯云cos文件上传下载
背景 公司项目有个需求, 前端上传excel文件, 后端读取数据.处理数据.返回错误数据, 最简单的方式同步处理, 客户端上传文件后一直阻塞等待响应, 但用户体验无疑很差, 处理数据可能十分耗时, 没 ...
- 高可用Hadoop平台-答疑篇
1.概述 这篇博客不涉及到具体的编码,只是解答最近一些朋友心中的疑惑.最近,一些朋友和网友纷纷私密我,我总结了一下,疑问大致包含以下几点: 我学 Hadoop 后能从事什么岗位? 在遇到问题,我该如何 ...
- Linux-(rcp,scp)
rcp命令 1.命令格式: rcp [参数] [源文件] [目标文件] 2.命令功能: rcp命令用在远端复制文件或目录,如同时指定两个以上的文件或目录,且最后的目的地是一个已经存在的目录,则它会把前 ...
- xtrabackup 详解
xtrabackup是Percona公司CTO Vadim参与开发的一款基于InnoDB的在线热备工具,具有开源,免费,支持在线热备,备份恢复速度快,占用磁盘空间小等特点,并且支持不同情况下的多种备份 ...
- markdown简单入门
1.斜体和加粗: 使用下划线"_"或"*"括起来 _内容_ or *内容* 1个_ 或 * 都是斜体,2个则是加粗: 3个既斜体 又加粗,4个以上则没什么变化 ...
- MySQL问答整理
1.Mysql中有哪些不同的表格? MyISAM: 基于IASM代码.可以被压缩,支持全文搜索,事务不安全,而且也不支持外键.如果事务回滚将会造成不完全回滚,从而不具备原子性.所以假如忽略事务以及访问 ...
- Html.DropDownListFor练习(2)
下午有做了练习<Html.DropDownListFor练习>http://www.cnblogs.com/insus/p/3382575.html 在实现过程中,需要创建一个List&l ...
- C#读取“我的文档”等特殊系统路径及环境变量
返回“我的文档”路径字符串 Environment.GetFolderPath(Environment.SpecialFolder.Personal) 本技巧使用GetFolderPath方法来获取指 ...