java - 我可以编写一个遍历集合和数组的 for 循环吗?

标签 java arrays collections

是否有可能检查一个对象是数组还是带有一个子句的集合?我想要达到的目标:

假设数组实现 Iterable,并且假设 Object foo 可以是数组或集合,我想使用这样的代码片段:

if (foo instanceof Iterable) {
  for (Object f : (Iterable) foo) {
    // do something with f
  }
}

不幸的是,数组不能转换为 Iterable。它也没有实现 Collection。是否有任何其他可能性可以像上面那样在一个循环中处理两者?而不是 - 当然 - 使用 if-else if-clause 和两个循环(这不太好)。

编辑:针对这些答案。我知道 isArray() 方法,但在这种情况下是强制转换

...
for (Object f : (Iterable) foo) {
...

会失败。这是一个遗憾和代码冗余,因为我必须使用两个循环,尽管 foreach 循环适用于集合和数组。

最佳答案

关于检查 foo 是集合还是数组的条件:

Class#isAssignableFrom可能会派上用场。

Class<?> fooClass = foo.getClass();
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
                              Object[].class.isAssignableFrom(fooClass);

我有理由假设你不会在原始数组上测试它,因为你有只适用于包装类的集合。

我猜你可以放心地将 Object[].class.isAssignableFrom(fooClass) 替换为 fooClass.isArray()

boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
                              fooClass.isArray();

它也适用于原始数组类。


我已经运行了一个小“测试”

class Test {
    public static void main(String[] args) {
        Predicate<Class<?>> p = c -> Collection.class.isAssignableFrom(c) || 
                                     c.isArray();

        System.out.println(p.test(new int[0].getClass()));
        System.out.println(p.test(new Integer[0].getClass()));
        System.out.println(p.test(Collections.emptyList().getClass()));
        System.out.println(p.test(Collections.emptySet().getClass()));

        System.out.println(p.test(Collections.emptyMap().getClass()));
    }
}

其中results in

true
true
true
true
false

关于将在数组和数组上运行的通用循环 合集:

你只是不能编写一个准确的结构来处理这个问题:Collection(或Iterable)和Object[] 几乎没有共同点(Object 作为一个共同的父级,其方法还不够)。

我认为构建自己的抽象以同样的方式处理集合和数组是明智的。没有特定的上下文,我可以想出两个子类的简单想法,每个子类都定义了它的 source(集合或数组)应该如何迭代。然后,对接口(interface)进行编程将有助于平等地管理它们。

一个非常简单的例子是:

interface Abstraction<T> {
    void iterate(Consumer<? super T> action);

    static <T> Abstraction<T> of(Collection<T> collection) {
        return new CollectionAbstraction<>(collection);
    }
    static <T> Abstraction<T> of(T[] array) {
        return new ArrayAbstraction<>(array);
    }
    static IntArrayAbstraction of(int[] array) {
        return new IntArrayAbstraction(array);
    }
}

class CollectionAbstraction<T> implements Abstraction<T> {
    Collection<T> source;

    public CollectionAbstraction(Collection<T> source) {
        this.source = source;
    }

    @Override
    public void iterate(Consumer<? super T> action) {
        source.forEach(action);
    }
}

class ArrayAbstraction<T> implements Abstraction<T> {
    T[] source;

    public ArrayAbstraction(T[] source) {
        this.source = source;
    }

    @Override
    public void iterate(Consumer<? super T> action) {
        for (T t : source) {
            action.accept(t);
        }
    }
}

class IntArrayAbstraction implements Abstraction<Integer> {
    int[] source;

    public IntArrayAbstraction(int[] source) {
        this.source = source;
    }

    @Override
    public void iterate(Consumer<? super Integer> action) {
        for (int t : source) {
            action.accept(t);
        }
    }
}

class Test {
    public static void main(String[] args) {
        Abstraction.of(new Integer[] {1, 2, 3}).iterate(System.out::println);
        Abstraction.of(Arrays.asList(1, 2, 3)).iterate(System.out::println);
        Abstraction.of(new int[] {1, 2, 3}).iterate(System.out::println);
    }
}

我相信上述方法非常通用。您不依赖于某个源的迭代方式,您可以选择性地修改它们。

关于java - 我可以编写一个遍历集合和数组的 for 循环吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55588278/

相关文章:

arrays - 如何扩展特定类型数组的数组功能?

java - 关于数组并打印出新排序的数组?

java - 映射以下数据的键值对?

java - JQuery Ajax 调用 : How to fetch JsonArray?

java - 使用 Spring Integration 使 ssl-context-support 有条件地使用 tcp-connection-factory

java - 从 Java/Windows 创建新邮件(默认客户端)

java - 从 RichFaces 中的 xhtml 访问 bean 对象方法

c - 如何交换(或交换)数组中的两个数字?

java - Java 中的 clear() 方法

java : TreeSet Collection and Comparable interface