Java ListIterator在开始/结束时有不同的行为

Java ListIterator在开始/结束时有不同的行为,java,list,linked-list,iterator,listiterator,Java,List,Linked List,Iterator,Listiterator,我写了一个非常简单的获取程序,以更新我在LinkedList上的技能,以备需要。 现在,我无意中发现了出乎意料的行为。当我到达列表的末尾/开头并前进/后退时,同一元素将显示两次 以下是我的想法: List = [<Pointer>E1, E2, E3] List=[E1、E2、E3] 在next()调用之后: List=[E1、E2、E3] 在next()调用之后: List=[E1、E2、E3] 在上一次()调用之后: List=[E1、E2、E3] 但是很明显,我必

我写了一个非常简单的获取程序,以更新我在LinkedList上的技能,以备需要。 现在,我无意中发现了出乎意料的行为。当我到达列表的末尾/开头并前进/后退时,同一元素将显示两次

以下是我的想法:

List =   [<Pointer>E1, E2, E3]
List=[E1、E2、E3]
在next()调用之后:

List=[E1、E2、E3]
在next()调用之后:

List=[E1、E2、E3]
在上一次()调用之后:

List=[E1、E2、E3]
但是很明显,我必须调用它两次才能使指针返回一次。这是为什么?我如何改变这种行为

public class Playlist {

private LinkedList<Song> playList;
private ArrayList<Album> albums;
private Song currentSong;

Playlist() {
    this.playList = new LinkedList<>();
    this.albums = new ArrayList<>();
}

Playlist(ArrayList<Album> albums) {
    this.playList = new LinkedList<>();
    this.albums = albums;
}

void addAlbum(Album album) {
    albums.add(album);
}

void addSong(Song s) {
    if (albums.contains(s)) {
        playList.add(s);
    } else {
        System.err.println("Song unknown");
    }
}


public static void main(String[] args) {
    Song s1 = new Song("song1", 111);
    Song s2 = new Song("song2", 222);
    Song s3 = new Song("song3", 333);
    Song s4 = new Song("song4", 444);
    Song s5 = new Song("song5", 555);

    ArrayList<Song> songList1 = new ArrayList<>();
    songList1.add(s1);
    songList1.add(s2);
    songList1.add(s3);
    Album a1 = new Album(songList1);

    ArrayList<Song> songList2 = new ArrayList<>();
    songList2.add(s4);
    songList2.add(s5);
    Album a2 = new Album(songList2);

    Playlist p1 = new Playlist();
    p1.addAlbum(a1);
    p1.addAlbum(a2);
    for(Album a : p1.albums){
        for(Song s : a.getSongs()){
            p1.playList.add(s);
        }
    }

    ListIterator<Song> listIterator = p1.playList.listIterator();

    p1.currentSong = p1.playList.getFirst();
    Scanner scanner = new Scanner(System.in);
    p1.showMenu();
    String input = scanner.nextLine();
    ;

    while (!input.equals("q")) {
        switch (input) {
            case "s":
                if ((listIterator.hasNext())) {
                    p1.currentSong = listIterator.next();
                    System.out.println("Current song: " + p1.currentSong);
                } else {
                    System.out.println("End of playlist reached");
                }
                break;
            case "p":
                if (listIterator.hasPrevious()) {
                    p1.currentSong = listIterator.previous();
                } else {
                    System.out.println("Start of playlist reached");
                }
                break;
            default:
                System.out.println("Invalid input.");
                break;

        }
        p1.showMenu();
        input = scanner.nextLine();
    }
    System.out.println("Goodbye");
    scanner.close();
}

private void showMenu() {
    System.out.print("This is the menu.\n Your options: (s) - skip the current song.\n (p) - play previous song. \n (q) - Quit.\n +" +
            " Current Song playing: " + currentSong + "\n");
}
公共类播放列表{
私人链接列表播放列表;
私人ArrayList专辑;
私人歌曲;
播放列表(){
this.playList=新建链接列表();
this.albums=新的ArrayList();
}
播放列表(ArrayList专辑){
this.playList=新建链接列表();
this.albums=相册;
}
void addAlbum(相册){
相册。添加(相册);
}
void addSong(歌曲s){
如果(相册包含){
播放列表。添加;
}否则{
System.err.println(“歌曲未知”);
}
}
公共静态void main(字符串[]args){
歌曲s1=新歌(“歌曲1”,111);
歌曲s2=新歌(“歌曲2”,222);
歌曲s3=新歌(“歌曲3”,333);
歌曲s4=新歌(“歌曲4”,444);
歌曲s5=新歌(“歌曲5”,555);
ArrayList songList1=新的ArrayList();
歌曲列表1.添加(s1);
歌曲列表1.添加(s2);
歌曲列表1.添加(s3);
专辑a1=新专辑(歌曲列表1);
ArrayList songList2=新的ArrayList();
歌曲列表2.添加(s4);
歌曲列表2.添加(s5);
专辑a2=新专辑(歌曲列表2);
播放列表p1=新播放列表();
p1.添加相册(a1);
p1.添加相册(a2);
用于(相册a:p1.相册){
对于(歌曲s:a.getSongs()){
p1.播放列表。添加;
}
}
ListIterator ListIterator=p1.playList.ListIterator();
p1.currentSong=p1.playList.getFirst();
扫描仪=新的扫描仪(System.in);
p1.showMenu();
字符串输入=scanner.nextLine();
;
而(!input.equals(“q”)){
开关(输入){
案例“s”:
if((listIterator.hasNext()){
p1.currentSong=listIterator.next();
System.out.println(“当前歌曲:+p1.currentSong”);
}否则{
System.out.println(“播放列表结束”);
}
打破
案例“p”:
if(listIterator.hasPrevious()){
p1.currentSong=listIterator.previous();
}否则{
System.out.println(“到达播放列表的开始”);
}
打破
违约:
System.out.println(“无效输入”);
打破
}
p1.showMenu();
输入=scanner.nextLine();
}
System.out.println(“再见”);
scanner.close();
}
私有void showMenu(){
System.out.print(“这是菜单。\n您的选项:(s)-跳过当前歌曲。\n(p)-播放上一首歌曲。\n(q)-退出。\n+”+
当前歌曲播放:“+currentSong+”\n”);
}
}

这本书明确地说

请注意,交替调用next和previous将重复返回相同的元素

你刚开始画的画(用指针)是正确的,你可能只是把它们解释错了。
next()
方法返回指针右侧的元素
previous()
方法返回指针左侧的元素

如果再加上一个逗号,这幅画可能会更容易理解:

//list=[,E1,E2,E3]--next=E1,previous=exception
assertEquals(E1,next());
//列表=[E1,E2,E3]--下一个=E2,上一个=E1
assertEquals(E2,next());
//列表=[E1,E2,E3]--下一个=E3,上一个=E2
assertEquals(E3,next());
//list=[E1,E2,E3,]--next=exception,previous=E3
assertEquals(E3,previous());
//列表=[E1,E2,E3]--下一个=E3,上一个=E2
assertEquals(E2,previous());
//列表=[E1,E2,E3]--下一个=E2,上一个=E1
assertEquals(E1,previous());
//列表=[,E1,E2,E3]--下一个=E1,上一个=exception
来自:

ListIterator没有当前元素;其光标位置始终位于调用previous()返回的元素和调用next()返回的元素之间

next()

返回列表中的下一个元素并前进光标位置

previous()

返回列表中的上一个元素并移动光标位置 向后

图示与实际行为之间的区别在于光标位于元素之间,而不是指向元素的指针


开始时,光标位于列表开始之前。调用next返回第一个元素,并向前移动光标。现在光标位于第一个和第二个元素之间。现在调用previous将再次返回第一个元素,因为那是光标之前的元素。

因此我需要实现自己的方法来检查我是否已到达开始/结束,如果已到达,它将调用next()/previous()两次?@InDaPond这取决于您想要到达的内容。如果您只想返回最后一个元素一次,那么当然您必须自己处理它。或者您可以只接受
next()
/
previous()
的逻辑,并更改程序的预期行为:)
List =   [E1, E2, <Pointer>E3]
List =   [E1, <Pointer>E2, E3]
public class Playlist {

private LinkedList<Song> playList;
private ArrayList<Album> albums;
private Song currentSong;

Playlist() {
    this.playList = new LinkedList<>();
    this.albums = new ArrayList<>();
}

Playlist(ArrayList<Album> albums) {
    this.playList = new LinkedList<>();
    this.albums = albums;
}

void addAlbum(Album album) {
    albums.add(album);
}

void addSong(Song s) {
    if (albums.contains(s)) {
        playList.add(s);
    } else {
        System.err.println("Song unknown");
    }
}


public static void main(String[] args) {
    Song s1 = new Song("song1", 111);
    Song s2 = new Song("song2", 222);
    Song s3 = new Song("song3", 333);
    Song s4 = new Song("song4", 444);
    Song s5 = new Song("song5", 555);

    ArrayList<Song> songList1 = new ArrayList<>();
    songList1.add(s1);
    songList1.add(s2);
    songList1.add(s3);
    Album a1 = new Album(songList1);

    ArrayList<Song> songList2 = new ArrayList<>();
    songList2.add(s4);
    songList2.add(s5);
    Album a2 = new Album(songList2);

    Playlist p1 = new Playlist();
    p1.addAlbum(a1);
    p1.addAlbum(a2);
    for(Album a : p1.albums){
        for(Song s : a.getSongs()){
            p1.playList.add(s);
        }
    }

    ListIterator<Song> listIterator = p1.playList.listIterator();

    p1.currentSong = p1.playList.getFirst();
    Scanner scanner = new Scanner(System.in);
    p1.showMenu();
    String input = scanner.nextLine();
    ;

    while (!input.equals("q")) {
        switch (input) {
            case "s":
                if ((listIterator.hasNext())) {
                    p1.currentSong = listIterator.next();
                    System.out.println("Current song: " + p1.currentSong);
                } else {
                    System.out.println("End of playlist reached");
                }
                break;
            case "p":
                if (listIterator.hasPrevious()) {
                    p1.currentSong = listIterator.previous();
                } else {
                    System.out.println("Start of playlist reached");
                }
                break;
            default:
                System.out.println("Invalid input.");
                break;

        }
        p1.showMenu();
        input = scanner.nextLine();
    }
    System.out.println("Goodbye");
    scanner.close();
}

private void showMenu() {
    System.out.print("This is the menu.\n Your options: (s) - skip the current song.\n (p) - play previous song. \n (q) - Quit.\n +" +
            " Current Song playing: " + currentSong + "\n");
}
// list = [<Pointer>, E1, E2, E3] -- next=E1, previous=exception
assertEquals(E1, next());
// list = [E1, <Pointer>, E2, E3] -- next=E2, previous=E1
assertEquals(E2, next());
// list = [E1, E2, <Pointer>, E3] -- next=E3, previous=E2
assertEquals(E3, next());
// list = [E1, E2, E3, <Pointer>] -- next=exception, previous=E3
assertEquals(E3, previous());
// list = [E1, E2, <Pointer>, E3] -- next=E3, previous=E2
assertEquals(E2, previous());
// list = [E1, <Pointer>, E2, E3] -- next=E2, previous=E1
assertEquals(E1, previous());
// list = [<Pointer>, E1, E2, E3] -- next=E1, previous=exception