Лучшее решение - не поддерживать текущую воспроизводимую песню, соответственно. следующая песня для воспроизведения через Iterator
. Вместо этого вы можете создать специализированный список, который знает, как адаптировать этот указатель к изменениям.
Такой класс может выглядеть так:
class SongList extends AbstractList<Song> implements RandomAccess {
final List<Song> backend = new ArrayList<>();
int currentSong = -1;
SongList() {}
SongList(Collection<? extends Song> c) {
backend.addAll(c);
}
// mandatory query methods
@Override public int size() {
return backend.size();
}
@Override public Song get(int index) {
return backend.get(index);
}
// the "iterator"
public Song nextSong() {
if(++currentSong < size()) {
return get(currentSong);
}
currentSong = -1;
return null;
}
// modifying methods, which will adapt the pointer
@Override public void add(int index, Song element) {
backend.add(index, element);
if(index <= currentSong) currentSong++;
}
@Override public Song remove(int index) {
final Song removed = backend.remove(index);
if(index <= currentSong) currentSong--;
return removed;
}
@Override
public boolean addAll(int index, Collection<? extends Song> c) {
int old = size();
backend.addAll(index, c);
if(index <= currentSong) currentSong += size() - old;
return true;
}
@Override protected void removeRange(int fromIndex, int toIndex) {
backend.subList(fromIndex, toIndex).clear();
if(fromIndex <= currentSong)
currentSong = Math.max(fromIndex - 1, currentSong - toIndex + fromIndex);
}
// this will not change the pointer
@Override public Song set(int index, Song element) {
return backend.set(index, element);
}
// query methods overridden for performance
@Override public boolean contains(Object o) {
return backend.contains(o);
}
@Override public int indexOf(Object o) {
return backend.indexOf(o);
}
@Override public Spliterator<Song> spliterator() {
return backend.spliterator();
}
@Override public void forEach(Consumer<? super Song> action) {
backend.forEach(action);
}
@Override public Object[] toArray() {
return backend.toArray();
}
@Override public <T> T[] toArray(T[] a) {
return backend.toArray(a);
}
@Override public String toString() {
return backend.toString();
}
}
AbstractList
специально разработан для обеспечения операций сбора Поверх нескольких методов, поэтому нам нужно только реализовать size()
и get(int)
, чтобы иметь читаемый список, и, предоставив add(int, Song)
, remove(int)
и set(int, Song)
, мы уже сделали все необходимое для поддержки всех операций модификации. Другие методы предоставляются только для улучшения производительности, унаследованные методы также будут работать.
Список поддерживает один указатель на текущую позицию воспроизведения, который можно повторять с помощью nextSong()
. При достижении конца он вернет null
и сбросит указатель, так что следующий запрос начнется снова. Методы add
и remove
адаптируют указатель так, что уже проигранная песня не будет воспроизводиться снова (если только не будет перезапущен весь список). Модификации, основанные на
set
, не адаптируют указатель, это означает, что ничего значительного не произойдет, когда вы sort
список, некоторые политики можно себе представить, но по крайней мере, когда список имеет дубликаты, идеального поведения не существует. При сравнении с другим программным обеспечением плеера никто не ожидает идеального поведения, когда список переворачивается во время игры. По крайней мере, никогда не будет исключения.