【问题标题】:ListIterator has different behaviour at start/EndListIterator 在开始/结束时有不同的行为
【发布时间】:2018-08-05 01:26:04
【问题描述】:

我编写了一个非常简单的获取程序,以更新我在 LinkedLists 上的技能,以备不时之需。 现在,我偶然发现了我没想到的行为。当我到达列表的末尾/开头并前进/后退时,相同的元素会显示两次。

这是我认为的工作方式:

List =   [<Pointer>E1, E2, E3]

在 next() 调用之后:

List =   [E1, <Pointer>E2, E3]

在 next() 调用之后:

List =   [E1, E2, <Pointer>E3]

previous() 调用之后:

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");
}

}

【问题讨论】:

    标签: java list linked-list iterator listiterator


    【解决方案1】:

    documentation 明确表示

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

    您在开始时(使用指针)绘制的图片是正确的,您可能只是将它们解释错了。 next() 方法返回指针右侧的元素,previous() 方法返回指针左侧的元素。

    也许多加一个逗号会使图片看起来更容易理解:

    // 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
    

    【讨论】:

    • 所以我需要实现我自己的方法来检查我是否已经到达开始/结束,如果是,它会调用 next() / previous() 两次?
    • @InDaPond 这取决于您想要达到的目标。如果您只想返回最后一个元素一次,那么您当然必须自己处理它。或者您可能只是接受next()/previous() 的逻辑并更改程序的预期行为:)
    【解决方案2】:

    来自docs

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

    下一个()

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

    上一个()

    返回列表中的前一个元素并移动光标位置 倒退。

    您的插图和实际行为之间的区别在于光标位于元素之间,它不是指向元素的指针。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-24
      • 2019-04-28
      • 1970-01-01
      • 2019-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多