前14篇文章,分享了JDK中值得学习和借鉴的编码和设计方法。
每个硬币都是有两面的。Every coin has two sides。
当然,JDK中也有很多值得改进或者说富有争议的设计。
本篇,就来详细吐槽下JDK中的10个富有争议的设计。
网友指出
1.求和抛异常,错误提示不合理。
在OpenJDK源码研究笔记(一)-参数检查&抛出带关键错误提示信息的异常 这篇文章中,有个网友指出:“第三个if的提示信息有点问题。前两个if说明了position和size都不可能为负,求和通常不可能为负,只有一种情况是 求和 溢出了吧,此时异常信息再这样抛,反而是信息不明确”
protected FileLock(AsynchronousFileChannel channel, long position,
long size, boolean shared) {
if (position < 0)
throw new IllegalArgumentException("Negative position");
if (size < 0)
throw new IllegalArgumentException("Negative size");
if (position + size < 0)
throw new IllegalArgumentException("Negative position + size");
this.channel = channel;
this.position = position;
this.size = size;
this.shared = shared;
}
2.标记接口可以用注解替代。
在OpenJDK源码研究笔记(三)-RandomAccess等标记接口的作用 这篇文章中,有个网友指出:“空接口,比如 Serializable 之类的,都只是一个记号, 其实用annotation 更合适。”
比如ArrayList的定义是 class ArrayList implements Serialiable{}。
可以修改为@Serialize
class ArrayList{}
几个观点
a.注解是JDK1.5才有的。之前的API当然还是应该支持。
注解的话,我觉得也是可以的。可能看起来不够简洁。
实现一个空的接口,用instanceof挺方便的。
b.实现接口也好,用注解也好。最终,都是一种设计的2种不同实现。
实现接口用Instance of,用注解 调用方法。
用接口能够更好地兼容以前的代码。
c.从兼容的角度看,确实是的。
但是从设计目的来看,注解更好。
而且不影响对象继承结构,就是加了个标记。
方法定义
3.重复定义方法。
public interface List<E> extends Collection<E>{
int size();
boolean isEmpty();
}
既然继承了父接口Collection,为何还要 重复去定义父类中已经存在的接口??
public interface Set<E> extends Collection<E>等接口的定义 也是如此。
4.双端队列同一种操作有2种类似的实现。
java.util.Deque<E>
/**
* 查询队列中的第1个元素。
* 当队列为空时,返回null。
*/
E peekFirst();
/**
* 查询队列中的第1个元素。
* 与peekFirst方法不同的是,当队列为空时,抛出异常。
* @throws NoSuchElementException if this deque is empty
*/
E getFirst();
为什么要定义2套API呢?显得有些重复,容易让人产生疑惑。
5.集合接口Set的返回值不同。
java.util.Set
public abstract E get(int index);
public E set(int index, E element);
public boolean add(E e);
为什么就这个方法没有返回值呢?
public void add(int index, E element);
上面的3个方法都是有返回值的,同样是add(E e)也是有boolean返回值。
设计问题
6.List生成子列表后,就不能再操作原列表。
List<E> subList(int fromIndex, int toIndex);
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
List<String> subList = list.subList(0,2);
subList.add("C");
以上代码会抛出java.util.ConcurrentModificationException
有的时候,我们确实有这个需求。
既然JDK这样设计,我们只能尽可能避开上述用法。
7.不可变集合的实现方式。
java.util.Collections.unmodifiableList(list);
这种方法的实现,其实返回一个“不可变”的List实现。
static class UnmodifiableList<E> extends UnmodifiableCollection<E>
implements List<E> {
private static final long serialVersionUID = -283967356065247728L;
final List<? extends E> list;
UnmodifiableList(List<? extends E> list) {
super(list);
this.list = list;
}
public E get(int index) {
return list.get(index);
}
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
}
把那些会修改List的方法,以抛出异常的方式实现。
在看源码之前,我总觉得有其它方法实现。
看到源码是这种方式实现的,我有点失望。
看来是我想多了。
8.参数检查不合理。
java.util.logging.Handler.setFormatter(Formatter)
public void setFormatter(Formatter newFormatter) throws SecurityException {
checkAccess();
// Check for a null pointer:
newFormatter.getClass();
formatter = newFormatter;
}
就是简单地调用一个类的方法newFormatter.getClass();来检查该类是否为null。
这种方式是否更好呢?
if(newFormatter==null){
throw new NullPointerException("");
}
编码习惯
9.一条If语句的括号问题。
大部分的只有一条语句的if语句是这么写的。
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
我比较习惯以下写法,防止“看走眼”。
if (f == null){
throw new NoSuchElementException();
}
另外,我经常会写下面这样的注释,
if (f == null)
//抛出异常,或者加一条打印语句
throw new NoSuchElementException();
这种写法,很容易看错。
这种类似的代码有很多,如果if语句再嵌套一层,就更容易看错了。
public ScriptEngineManager() {
ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
if (canCallerAccessLoader(ctxtLoader)) {
if (DEBUG)
System.out.println("using " + ctxtLoader);
init(ctxtLoader);
} else {
if (DEBUG)
System.out.println("using bootstrap loader");
init(null);
}
}
10.没有用的变量。
java.util.logging.LogManager中有如下变量定义。
private final static Handler[] emptyHandlers = {};
上面的代码是没有用到的。
Eclipse会有警告,黄色的感叹号还是比较烦人的。
相关阅读
我的CSDN博客专栏 OpenJDK源码研究笔记
OpenJDK源码研究过程中整理的学习笔记。 OpenJDK是GPL许可(GPL-licensed)的Java平台的开源实现。
原文参见:http://FansUnion.cn/articles/3174(小雷网-FansUnion.cn)
分享到:
相关推荐
所以自己构建了一个。 1. 自定义构建镜像的Dockerfile ``` FROM openjdk:8-jdk-alpine # 安装字体库 RUN apk add --update --no-cache ttf-dejavu fontconfig && rm -rf /var/cache/apk/* ``` 2. 执行构建命令:`...
openjdk8源码,适合深入学习jdk源码的同学
自己准备的JAVA8 完整源码(包含Sun包源码),120M大小的,jdk自带src.zip大小为20M,包括sum.misc.*包内的源码。这个用7z打包后13.3M大小。 源码源自:https://github.com/openjdk-mirror/jdk.git的jdk8u/jdk8u/...
openjdk源码1
openjdk jdk源码,在研究JAVA本地方法源码时,这个是必须的。
openjdk-17源码(openjdk-17+35_src.zip)
欢迎使用JDK! 有关构建说明,请参阅或以下文件之一: (html版本) (降价版) 有关OpenJDK社区和JDK的更多信息,请参见 。
java jdk1.7源码包,用于centos7使用jdk1.7编译openjdk1.8的 1.7版本
java openJDK 源码, Hotspot, 未编译, 原始代码, 直接zip压缩包, java openJDK 源码, Hotspot, 未编译, 原始代码, 直接zip压缩包, java openJDK 源码, Hotspot, 未编译, 原始代码, 直接zip压缩包
jdk源码,jvm源码
jdk8u源码,挂tz下载,分享给大家,官网下载实在是太慢了。包含linux、windows、等多个平台的源码,原地址http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/4db0e91b95c8/src/windows/,欢迎下载
openjdk可以在商业上使用,而jdk只允许个人研究使用。 总的来说,openjdk是jdk的开源版本,两者在功能上略有差异。 Red Hat版本的OpenJDK是OpenJDK的发行版,由Red Hat提供和维护。它主要用于Red Hat企业版Linux...
openjdk-18 GA源码(jdk18-jdk-18-ga.tar.gz)
openjdk8-for-study:为阅读jdk8源码方便直接在源码上做笔记而用。版本:1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11
openjdk-18 GA源码(jdk18-jdk-18-ga.zip)
OpenJdk源码包,
安装步骤:1、将deb文件上传到/var/cache/apt/archives目录 2、sudo apt-get install openjdk-8-jdk
openJdk17
jdk1.7 自带源码,并补充缺少sun包下的源码,补充源码来自1.7 openjdk
/jdk文件夹下生成一个src.zip,此文件夹对应rt.jar中的java源码,但细心研究后发现rt.jar中sun包下的文件不存在,也就是说sun包下的java源码并没有打包到src.zip中,可以到http://download.java.net/openjdk/jdk7/该...