Java 让我不爽的地方

Where Java Sucks

Posted by John Mactavish on August 13, 2020

Set 不提供获取元素的操作

讲老实话,我到今天才知道原来 Set 没有 get 方法:大概是以前确实没有这个需求。 咋一看好像没有什么问题,如果你知道要的元素是什么,还要获取 Set 里面相等的 元素干什么。但是 Set 通过对象的 equals 方法判断元素是否相等,而 equals 方法 可以只选择感兴趣的字段作比较。

Set<Foo> set = ...;
...
Foo foo = new Foo(1, 2, 3);
Foo bar = set.get(foo);   // get the Foo element from the Set that equals foo

我们不管是用迭代器还是 filter 来搜索都是 O(n) 的时间复杂度,这肯定不是我们想要的。 那么临时的补救方法可以是用 Map<E,E> 代替 Set<E>,键和值都是自己。当然, 这样的空间复杂度翻了一倍,所以在需要经常使用时,最靠谱的方法应该是使用 Map 自己实现 一个满足要求的 Set。原生的 Set 就是用 Map 实现的,参考这个

subList 共享底层 list 而 subString 却不

ArrayList.subList 方法返回的是其内部类 SubList 的实例(原始列表的一个视图),所以既不能 强制转换为 ArrayList 类型,分别使用两个引用进行修改也会影响到彼此,具体是:

  1. 对 sourceList 和 subList 做的非结构性修改(non-structural changes),都彼此可见;
  2. 对 subList 做结构性修改(structural changes),同样会影响到 sourceList 上;
  3. 对 sourceList 做结构性修改,最后都会触发 fail-fast 机制,导致异常 ConcurrentModificationException。

只能说一开始 API 设计得就有问题,为什么一个 mutable 的数据结构取 subList 不是拷贝一个 切片(slice)返回,而是要返回一个共享底层 list 的视图?

与之相反的是,String.subString 返回的确是一个拷贝(自从 JDK 7 update 6),话说 String 不是不变的吗!? 这样实现的原因什么的不讨论(讨论看),这个 API 设计的最严重的 后果是 subString 变成了一个不易察觉的 O(n) 操作。


最后附上 GitHub:https://github.com/gonearewe