Java 在添加到集合之前检查集合是否为null的不同方法的优缺点是什么?

Java 在添加到集合之前检查集合是否为null的不同方法的优缺点是什么?,java,api,exception,collections,Java,Api,Exception,Collections,这是对“”的后续问题。(感谢所有帮助回答问题的人) 因为Sun没有提供像OOTB这样简单的东西,所以实现这一点的方法似乎是使用包装器/代理。这似乎是直截了当的。我想知道的是,以下两种添加集合的方法的优缺点是什么,或者还有其他更好的方法吗 方法#1 public boolean addAll(Collection首先转换为数组,然后在数组中迭代,而不仅仅是迭代集合,这有什么意义?我会在不进行额外转换的情况下进行第二次转换 或者,也可以添加到临时集合: public boolean addAll(

这是对“”的后续问题。(感谢所有帮助回答问题的人)

因为Sun没有提供像OOTB这样简单的东西,所以实现这一点的方法似乎是使用包装器/代理。这似乎是直截了当的。我想知道的是,以下两种添加集合的方法的优缺点是什么,或者还有其他更好的方法吗

方法#1


public boolean addAll(Collection首先转换为数组,然后在数组中迭代,而不仅仅是迭代集合,这有什么意义?我会在不进行额外转换的情况下进行第二次转换

或者,也可以添加到临时集合:

public boolean addAll( Collection<? extends E> c) {
    if ( null == c ) {
        throw new NullPointerException( "c cannot be null" );
    }

    Set<E> tempSet = new HashSet<E>();

     /*
     * We have to iterate through the entire collection to check for
     * a null. This won't take advantage of any optimizations that
     * c.contains may be using.
     *

     */
     for ( E e : c) {
         if (null == e) {
              throw new NullPointerException("c cannot contain nulls");
         }
         tempSet.add(e);
     }

     this.wrapperSet = tempSet;
}

public boolean addAll(Collection首先转换为数组,然后在数组中迭代,而不仅仅是迭代集合,这有什么意义?我会在不进行额外转换的情况下进行第二次转换

或者,也可以添加到临时集合:

public boolean addAll( Collection<? extends E> c) {
    if ( null == c ) {
        throw new NullPointerException( "c cannot be null" );
    }

    Set<E> tempSet = new HashSet<E>();

     /*
     * We have to iterate through the entire collection to check for
     * a null. This won't take advantage of any optimizations that
     * c.contains may be using.
     *

     */
     for ( E e : c) {
         if (null == e) {
              throw new NullPointerException("c cannot contain nulls");
         }
         tempSet.add(e);
     }

     this.wrapperSet = tempSet;
}

public boolean addAll(Collection第二种方法更好。永远不要隐藏异常-您依赖的假设是c.contains(null)仅在集合中存在null的情况下才会引发NullPointerException。但是,如果由于equals方法的问题而引发NullPointerException,则代码中会出现错误,并且会将其隐藏

编辑:

如果指定的元素为null,并且此集合不允许null元素(可选),则从contains的JavaDoc中抛出NullPointerException


如果这是一个可选方法,那么您可能会抛出一个不支持的操作异常,而不是NullPointerExcepion(除了在equals中隐藏错误之外)。

第二种方法更好。永远不要隐藏异常-您依赖的假设是c.contains(null)仅在集合中存在null的情况下才会引发NullPointerException。但是,如果由于equals方法的问题而引发NullPointerException,则代码中会出现错误,并且会将其隐藏

编辑:

如果指定的元素为null,并且此集合不允许null元素(可选),则从contains的JavaDoc中抛出NullPointerException


如果它是一种可选方法,则可能会引发UnsupportedOperationException而不是NullPointerExcepion(除了在equals中隐藏错误之外)。

在数组中复制参数集合更安全。集合参数可能会同时更改(可能是并发集合)(或可能恶意书写)

此外,捕获运行时异常也不是一种很好的方法


您可能希望使用
Object[]
而不是
E[]
,并将不安全强制转换移动到以后。您还需要一个
Arrays.asList(a)
或类似文件。

在数组中复制参数集合更安全。集合参数可能会同时更改(可能是并发集合)(或可能恶意书写)

此外,捕获运行时异常也不是一种很好的方法


您可能希望使用
Object[]
而不是
E[]
并将不安全强制转换移动到以后。您还需要一个
Arrays.asList(a)
或类似内容。

如果要添加的集合是非NullCollection父类的子类,则还可以添加a短路以不测试Null。

如果要添加的集合是非NullCollection父类的子类,则还可以添加a短路以不测试Null。

因此,这两个方法似乎都是b我发布这个答案只是为了把信息整合到一个帖子中

TofuBeer指出了方法1的逻辑中被忽略的缺陷,其中存在其他可能抛出但无法捕获的异常。因此,一般来说,尝试捕获非异常条件下的异常总是不好的

Paul指出,我认为是安全强制转换的事实并非如此。我希望在输出强制转换上强制执行集合泛型,但它将返回对象[]。正如他指出的,我可以在搜索null时使用临时集存储数据

此外,正如Tom所确认的,collection参数可能会同时更改,因此将防御副本复制到新对象是一个好主意)

因此,我想理想的方法是:

public boolean addAll( Collection<? extends E> c ) {
    if ( null == c ) {
        throw new NullPointerException( "c cannot be null" );
    }

     // Create a defensive copy to prevent concurrent modifications of c
     Set<E> tmpSet = new HashSet<E>( c );

     /*
      * We have to iterate through the entire collection to check for
      * a null. This won't take advantage of any optimizations that
      * c.contains may be using.
      */
     for ( E e : tmpSet ) {
         if ( null == e ) {
              throw new NullPointerException( "c cannot contain nulls" );
         }
     }

     return this.wrapperSet.addAll( tmpSet );
}

public boolean addAll(Collection所以这两种方法似乎都不好。我发布这个答案只是为了将信息整合到一篇文章中

TofuBeer指出了方法1的逻辑中被忽略的缺陷,其中存在其他可能抛出但无法捕获的异常。因此,一般来说,尝试捕获非异常条件下的异常总是不好的

Paul指出,我认为是安全强制转换的事实并非如此。我希望在输出强制转换上强制执行集合泛型,但它将返回对象[]。正如他指出的,我可以在搜索null时使用临时集存储数据

此外,正如Tom所确认的,collection参数可能会同时更改,因此将防御副本复制到新对象是一个好主意)

因此,我想理想的方法是:

public boolean addAll( Collection<? extends E> c ) {
    if ( null == c ) {
        throw new NullPointerException( "c cannot be null" );
    }

     // Create a defensive copy to prevent concurrent modifications of c
     Set<E> tmpSet = new HashSet<E>( c );

     /*
      * We have to iterate through the entire collection to check for
      * a null. This won't take advantage of any optimizations that
      * c.contains may be using.
      */
     for ( E e : tmpSet ) {
         if ( null == e ) {
              throw new NullPointerException( "c cannot contain nulls" );
         }
     }

     return this.wrapperSet.addAll( tmpSet );
}

public boolean addAll(CollectionToArray的预期好处是,一旦创建了阵列的本地副本,如果在检查或随后调用addAll期间修改了原始集合,则不会出现问题。toArray的预期好处是,一旦创建了阵列的本地副本,如果修改了原始集合,则d在检查或随后调用addAll期间,都不会出现问题。“在数组中复制参数集合更安全。”也许我误读了它?(eith)