小编Pet*_*Pro的帖子

Guava为什么不提供ImmutableCollections接口?

Guava的ImmutableCollection子类ImmutableList是(不可扩展的)抽象类,而不是接口。该文件说,这是为了防止外部亚型。另一方面,文档还说

应该被认为是每个重要意义上的接口

但是,在外部进行子类型化的功能不是一种重要的界面含义吗?例如,如果ImmutableList是一个接口,我可以有一个方法签名,例如

public ImmutableList<String> getNames();
Run Code Online (Sandbox Code Playgroud)

(就像Guava的建议一样),然后可以灵活地ImmutableList将来交换自定义实现。但是,由于实际上它是一个抽象类,所以我没有这种灵活性,因此必须绑定到Guava的实现。因此,如果我想保持这种灵活性,就不得不使用更通用的return类型List,该类型不再向调用者传达有关不变性的有用信息:

public List<String> getNames();
Run Code Online (Sandbox Code Playgroud)

那么为什么不从外部进行子类型化很重要?一个答案可能是Guava设计者不信任外部实现者来适当地支持所需的语义,但List实际上它本身具有相当广泛的约定,而且没人阻止这种定制实现。还是还有其他原因?

java immutability guava

9
推荐指数
1
解决办法
177
查看次数

为什么Java Concurrency In Practice清单5.18不能用锁定原子方式完成?

在Java Concurrency in Practice中,第106页,它说" Memoizer3容易受到问题的影响[两个线程看到null并开始昂贵的计算]",因为在后备映射上执行了复合操作(如果不存在),这些操作无法成为原子使用锁定." 我不明白他们为什么说使用锁定不能成为原子.这是原始代码:

package net.jcip.examples;

import java.util.*;
import java.util.concurrent.*;

/**
 * Memoizer3
 * <p/>
 * Memoizing wrapper using FutureTask
 *
 * @author Brian Goetz and Tim Peierls
 */
public class Memoizer3 <A, V> implements Computable<A, V> {
    private final Map<A, Future<V>> cache
        = new ConcurrentHashMap<A, Future<V>>();
    private final Computable<A, V> c;

    public Memoizer3(Computable<A, V> c) {
        this.c = c;
    }

    public V compute(final A arg) throws InterruptedException {
        Future<V> f = cache.get(arg);
        if (f == null) …
Run Code Online (Sandbox Code Playgroud)

java concurrency

7
推荐指数
1
解决办法
196
查看次数

应该始终使用Java中的接口声明变量吗?

人们常常看到变量应该用某个接口声明的建议,而不是实现类.例如:

List<Integer> list = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)

但是,假设我使用此列表来实际依赖于ArrayList(例如Fisher-Yates shuffling)的O(1)随机访问的算法.在这种情况下,ArrayList代表我的关键抽象是它的数组性质,而不仅仅是它的List性质.换句话说,如果某人出现并更改list为a LinkedList,即使代码可以编译,也会出现问题.在这种情况下,声明是否可以使用实现类型?,例如:

ArrayList<Integer> list = new ArrayList<>(); 
Run Code Online (Sandbox Code Playgroud)

java declaration list

7
推荐指数
1
解决办法
136
查看次数

为什么在这种情况下没有使用LinkedList迭代器的ConcurrentModificationException?

请考虑以下代码段:

List<String> list = new LinkedList<>();
list.add("Hello");
list.add("My");
list.add("Son");

for (String s: list){
    if (s.equals("My")) list.remove(s);
    System.out.printf("s=%s, list=%s\n",s,list.toString());
}
Run Code Online (Sandbox Code Playgroud)

这导致输出:

s = Hello,list = [Hello,My,Son]
s = My,list = [Hello,Son]

很明显,循环只输入两次,第三个元素"Son"永远不会被访问.从底层的库代码中,看起来发生的是hasNext()迭代器中的方法不检查并发修改,只检查下一个索引的大小.由于remove()调用后大小减少了1 ,因此循环不会再次输入,但不会抛出ConcurrentModificationException.

这似乎与迭代器的契约相矛盾:

list-iterator是快速失败的:如果在创建Iterator之后的任何时候对列表进行结构修改,除了通过list-iterator自己的removeadd方法之外,list-iterator将抛出一个ConcurrentModificationException.因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险.

这是一个错误吗?同样,迭代器的契约在这里看起来肯定是不服从的 - 列表的结构在迭代过程中由迭代器之外的其他东西进行结构修改.

java linked-list

5
推荐指数
1
解决办法
326
查看次数

为什么列表层次结构中没有RandomAccess?

RandomAccess是Java中的标记接口,用于List表示它们可以快速随机访问其元素.由于它是专门为List实现而设计的,为什么不在List层次结构中呢?例如,请考虑以下方法,该方法需要RandomAccess列表作为输入并返回随机元素:

public <E, L extends List<E> & RandomAccess> E getRandomElement(L list) {...}
Run Code Online (Sandbox Code Playgroud)

我必须将此方法传递给匿名列表或具有声明类型的列表ArrayList<E>,具体类,而不是使用某些接口声明的列表List<E>.但是,如果RandomAccess参数化和扩展List<E>,那么我的方法可能如下所示:

public <E, L extends RandomAccess<E>> E getRandomElement(L list) {...}
Run Code Online (Sandbox Code Playgroud)

我可以传递一个声明类型的列表RandomAccess<E>,这是一个接口,而不是具体的类.ArrayList<E>然后才会实施RandomAccess<E>,而不是List<E>.

java inheritance list

5
推荐指数
1
解决办法
226
查看次数