По сути, предположим, что MobileSuit и Pilot должны быть разделены.
Это нормально, но здесь вы пытаетесь рассматривать их как единое целое, поэтому структурируйте свой код таким образом. В приведенных выше предложениях используется класс Pair
или Map.Entry
, но гораздо лучше предоставить объект с четким именем, представляющий MobileSuit
с Pilot
, например ::
public class OccupiedSuit {
private final MobileSuit suit;
private final Pilot pilot;
public OccupiedSuit(MobileSuit suit, Pilot pilot) {
this.suit = checkNotNull(suit);
this.pilot = checkNotNull(pilot);
}
// getters, equals, hashCode, toString
// or just use @AutoValue: https://github.com/google/auto/tree/master/value
}
Затем, вместо создания пользовательского Iterator
/ Iterable
, просто напишите вспомогательную функцию, которая объединяет два списка . Например:
public static List<OccupiedSuit> assignPilots(
Iterable<MobileSuit> suits, Iterable<Pilot> pilots) {
Iterator<MobileSuit> suitsIter = suits.iterator();
Iterator<Pilot> pilotsIter = pilots.iterator();
ImmutableList.Builder<OccupiedSuit> builder = ImmutableList.builder();
while (suitsIter.hasNext() && pilotsIter.hasNext()) {
builder.add(new OccupiedSuit(suitsIter.next(), pilotsIter.next()));
}
// Most of the existing solutions fail to enforce that the lists are the same
// size. That is a *classic* source of bugs. Always enforce your invariants!
checkArgument(!suitsIter.hasNext(),
"Unexpected extra suits: %s", ImmutableList.copyOf(suitsIter));
checkArgument(!pilotsIter.hasNext(),
"Unexpected extra pilots: %s", ImmutableList.copyOf(pilotsIter));
return builder.build();
}
Теперь вам не нужно поддерживать сложную пользовательскую реализацию Iterator
- просто положитесь на уже существующую!
Мы также можем обобщить assignPilots()
в универсальную утилиту, которая работает для любых двух входных данных, например так:
public static <L,R,M> List<M> zipLists(
BiFunction<L,R,M> factory, Iterable<L> left, Iterable<R> right) {
Iterator<L> lIter = left.iterator();
Iterator<R> rIter = right.iterator();
ImmutableList.Builder<M> builder = ImmutableList.builder();
while (lIter.hasNext() && rIter.hasNext()) {
builder.add(factory.apply(lIter.next(), rIter.next()));
}
checkArgument(!lIter.hasNext(),
"Unexpected extra left elements: %s", ImmutableList.copyOf(lIter));
checkArgument(!rIter.hasNext(),
"Unexpected extra right elements: %s", ImmutableList.copyOf(rIter));
return builder.build();
}
Который вы бы тогда вызывали так:
List<OccupiedSuit> occupiedSuits = zipLists(OccupiedSuit::new, suits, pilots);
В примере кода используются Guava * Preconditions
и ImmutableList
- если вы не используете Guava, достаточно просто встроить и переключиться на ArrayList
, но просто используйте Guava: )