Относительно условия, чтобы проверить, является ли 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()));
}
}
, что приводит к
true
true
true
true
false
Относительно универсального цикла, который будет работать над обоими массивами и
коллекции:
Вы просто не можете написать точную конструкцию, чтобы справиться с этим: Collection
(или Iterable
) и Object[]
имеют мало общего (Object
как общий родительский элемент и его методы) не достаточно).
Я думаю, что имеет смысл создать собственную абстракцию, которая бы одинаково относилась к коллекциям и массивам. Не имея конкретного контекста, я могу придумать простую идею о двух подклассах, каждый из которых определяет, как должен повторяться его источник (либо коллекция, либо массив). Затем программирование интерфейса поможет управлять ими одинаково.
Очень упрощенный пример:
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);
}
}
Я полагаю, что приведенный выше подход довольно универсален. Вы не зависите от того, как определенный источник повторяется, вы можете выборочно изменять их.