如何测试Java集合是否支持添加操作?

huangapple go评论65阅读模式
英文:

How can I test whether a Java collection supports the add operation?

问题

在Java中,一个Collection是否支持add取决于具体的类。比如我有如下代码:

List<String> otherNames = getOthers();
names.add(myName);

如果底层的List不支持这个操作,第二行会抛出UnsupportedOperationException,一个常见的例子是Collections.emptyList()

当然,我们可以创建一个新的列表来保存内容,但我想知道是否有一种方法可以测试列表?

英文:

In Java, whether a Collection support add depends on the concrete class.
Say I have code like:

List&lt;String&gt; otherNames = getOthers();
names.add(myName);

The second line will raise UnsupportedOperationException if the underlying List don't support this, one common example is Collections.emptyList().

Of course, we can create a new list to hold the content, but I wonder is there is way to test the list?

答案1

得分: 2

add 方法的实现是存在的。只是该实现会抛出异常。这意味着唯一的判断方式是尝试捕获该异常。EmptyList.add 的实现如下:

public void add(E var1) {
  throw new UnsupportedOperationException();
}

使用反射来判断是否存在 add 方法并不能得到你想要的信息,因为这是一个完全有效的方法。相反,你需要调用它并捕获异常,就像这样:

try {
  otherNames.add(myName);
} catch (UnsupportedOperationException e) {
  // 在这种情况下可以进行任何操作(例如将内容复制到 Vector 中等)
  overflowList.add(myName);
}

例如,你可以有一个 Vector(在我给出的示例中称为 overflowList),将任何无法添加到实际列表的内容添加到其中,并在最后处理这些内容。

英文:

The implementation of add exists. It's just that its implementation throws the exception. That means the only way to know is to try and catch that exception. The implementation of EmptyList.add is this:

public void add(E var1) {
  throw new UnsupportedOperationException();
}

Using reflection to see if an add method exists will not tell you what you want to know because it's a perfectly valid method. Instead you need to call it and catch the exception like this:

try {
  otherNames.add(myName);
} catch (UnsupportedOperationException e) {
  // whatever you want in this case (create a copy into a Vector, etc)
  overflowList.add(myName);
}

For example you could have a Vector (called overflowList in my example) that you add any things you couldn't add to the actual list and deal with them at the end.

答案2

得分: 1

如果您想确保它是可变的,您总是可以进行防御性地复制列表。

List<String> otherNames = new ArrayList<>(getOthers());
names.add(myName);

如果您的列表非常大,或者是紧密循环的一部分,那么您可以编写一个方法,在承诺复制之前检查列表的类型,以便在不必要地复制已经是可变列表的情况下节省资源。

static <T> List<T> copyIfMaybeImmutable(List<T> list) {
    // 根据需要扩展条件,例如 CopyOnWriteArrayList
    if (!(list instanceof ArrayList) && !(list instanceof LinkedList)) {
        return new ArrayList<>(list);
    }
    return list;
}

(由于许多方法将使用匿名或私有的 List 实现,无法涵盖所有情况,但仍然可以通过支持常见情况来提高性能)

使用方式:

List<String> otherNames = copyIfMaybeImmutable(getOthers());
英文:

If you want to make sure it's mutable, you can always just defensively copy the list.

List&lt;String&gt; otherNames = new ArrayList&lt;&gt;(getOthers());
names.add(myName);

If your lists are really big, or are part of a tight loop, then you could write a method which checks the type of the list before committing to a copy, so that you don't copy an already mutable list unnecessarily.

static &lt;T&gt; List&lt;T&gt; copyIfMaybeImmutable(List&lt;T&gt; list) {
    //expand condition as required, e.g. CopyOnWriteArrayList
    if (!(otherNames instanceof ArrayList) &amp;&amp; !(otherNames instanceof LinkedList)) {
        return new ArrayList&lt;&gt;(list);
    }
    return list;
}

(It's not possible to be comprehensive, since many methods will use anonymous or private List implementations, but there is still performance to be gained by supporting the common cases)

Use like

List&lt;String&gt; otherNames = copyIfMaybeImmutable(getOthers());

huangapple
  • 本文由 发表于 2020年5月19日 18:21:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/61888668.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定