【问题标题】:Detect non-null reference in an array检测数组中的非空引用
【发布时间】:2011-01-18 22:43:54
【问题描述】:

我刚问过a similar question,但后来我意识到我实际上需要别的东西。由于该问题已经有两个答案,我不想编辑我的问题。所以这就是我真正需要的:


我想检测数组的子范围是否包含仅空引用。有点像这样:

public static <T> boolean nullReferencesOnly
(T[] array, int fromInclusive, int toExclusive)
{
    for (int i = fromInclusive; i < toExclusive; ++i)
    {
        if (array[i] != null) return false;
    }
    return true;
}

Java 库中是否有这样的方法,所以我不必手动循环遍历数组?

【问题讨论】:

  • (注意,方法不需要是泛型的。)
  • @Tom:对,数组协方差。 Java 类型系统中的丑陋漏洞 :(

标签: java arrays algorithm null


【解决方案1】:
Collections.frequency(Arrays.asList(array), null) == array.length

对于一个范围,SLaks 已经在他的回答中建议了.subList(from, to)

【讨论】:

  • 虽然,为了清晰起见,我仍然会考虑辅助方法。
  • 我不会使用.frequency,因为它会遍历整个数组。你想早点失败,对吧?
  • @Jochen 这也太冗长了。然而,OP 想要一些“快速技巧”,而且标准库似乎没有提供更好的东西:) 但是,我同意应该考虑使用它。
  • 在下面查看我的答案:Collections.indexOfSubList(Arrays.asList(test), Collections.singletonList(null)) == -1;
  • 这效率不高,尤其是在数组很大的情况下。
【解决方案2】:

您可以使用像 Guava (http://code.google.com/p/guava-libraries/) 这样的函数式编程库。你可以这样做:


import com.google.common.base.Predicate;

public class NotNull implements Predicate
{

    @Override
    public boolean apply(String arg0)
    {
        return arg0 != null;
    }

}

还有一个测试驱动程序,看看它是如何使用的:


import static org.junit.Assert.*;

import java.util.Arrays;
import java.util.List;

import org.junit.Test;

import com.google.common.collect.Iterables;

public class Driver
{
    @Test
    public void testNotNull()
    {
        List l = Arrays.asList(new String[] {null, null, null});

        String s = Iterables.find(l, new NotNull(), null);

        assertNull(s);
    }

    @Test
    public void testNotNull2()
    {
        List l = Arrays.asList(new String[] {null, "1", null});

        String s = Iterables.find(l, new NotNull(), null);

        assertNotNull(s);
    }
}

有了这个,您只需调用 Iterables.find() 并查看它是否可以找到任何不为空的内容。只要它不返回任何内容(null),您就知道列表中没有任何内容不为 null。

【讨论】:

  • +1 这看起来很有趣,但我认为就我而言,这有点矫枉过正。
  • 我当然会使用 Nikita 的方法——它很好地使用了频率方法。函数库非常适合抽象算法,但在 Java 支持闭包之前,它们将继续显得笨拙。
【解决方案3】:

我认为最好的解决方案是获取您已经获得的代码,将数组类型更改为Object[]并将方法放入“帮助器”类中。

  1. AFAIK,标准 Java 库中没有任何方法可以直接执行您想要的操作。
  2. AFAIK,Apache Commons 或 Google Collections / Guava 中没有任何方法可以直接满足您的需求。
  3. 涉及Collection.contains 的解决方案将失败,因为该方法基于equals,如果您测试null,则会给出NPE。
  4. 涉及通用frequency 方法的解决方案在找到null 时不会短路。
  5. 涉及应用 Predicate 对象的解决方案成本高昂,并且比您的解决方案需要更多的代码。

您的解决方案易于阅读,并且比任何建议的替代方案都更有效。它涉及显式循环的事实不应该让您担心。毕竟,这是您正在编写的 Java 代码……而不是 FP 语言。


除此之外 - 如果问题是测试是否存在 null 元素(而不是非 null 元素),那么另一种选择是 org.springframework.util.Assert.noNullElements

http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/util/Assert.html#noNullElements(java.lang.Object[]))

但是,这会引发异常,而不是返回 truefalse,这可能会使其成为一个糟糕的解决方案……除非您本来打算引发异常。

【讨论】:

    【解决方案4】:

    嗯,效率不高,但您可以使用 Set 来提供帮助,就像在这个例子中一样:

      String[] test = {null, null, null, null};
      Set<String> set = new HashSet<String>(Arrays.asList(test));
      System.out.println(set.size() == 0 || (set.size() == 1 && set.contains(null)));
    

    这样,如果全部为null,则只有一个元素,而那个元素为null。 如果您只需要一个范围,您可以在Arrays.asList(test) 上使用 subList。

    效率不高,但使用可以在核心 Java 库中找到的类。

    希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      使用 Java 8(或更高版本)是直截了当的并且使用短路;这意味着它一旦检测到非空元素就会立即返回:

      public static boolean hasAtLeastOneElementNotNull(final Object[] array) {
      
          return Arrays.stream(array)
                  .anyMatch(Objects::nonNull);
      }
      

      来自“anyMatch”的文档:

      返回此流的任何元素是否与提供的谓词匹配。 如果不是确定结果所必需的,则可能不会评估所有元素的谓词。如果流为空,则返回 false 并且不评估谓词。 这是一个短路终端操作。

      【讨论】:

        猜你喜欢
        • 2011-06-11
        • 1970-01-01
        • 1970-01-01
        • 2011-07-08
        • 1970-01-01
        • 1970-01-01
        • 2019-01-28
        • 1970-01-01
        • 2017-10-22
        相关资源
        最近更新 更多