【问题标题】:Why does the do-while loop not run as expected in this Java program?为什么在这个 Java 程序中 do-while 循环没有按预期运行?
【发布时间】:2016-03-29 02:01:41
【问题描述】:

我一直在编写一个程序,它将获取音乐文件名称的数组并播放它们。我成功地做到了,但是,我想润色一些东西,让它变得更好一点。我试图让音乐以随机顺序播放,但在播放整个列表之前不重复任何歌曲。我几乎可以做到,但我认为我的 do-while 循环有问题。该程序按预期运行大约八首歌曲,但随后停止播放音乐,JVM 继续运行。我正在使用 BlueJ,因为我仍然是 AP Comp Sci 学生,所以我意识到我可能无法完成这项任务,但任何帮助将不胜感激。我有一个驱动程序“MusicDriver”,它与其他两个类“具有”关系:“MP3”和“Music”。

我的 MP3 课:

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import javazoom.jl.player.Player;

public class MP3 {
    String filename;
    Player player; 

    public void stopMP3() { if (player != null) player.close(); }

    // play the MP3 file to the sound card
    public void playMP3(String filename) {
    try {
        FileInputStream fis = new FileInputStream(filename);
        BufferedInputStream bis = new BufferedInputStream(fis);
        player = new Player(bis);
    }
    catch (Exception e) {
        System.out.println("Problem playing file " + filename);
        System.out.println(e);
    }

    // run in new thread to play in background
    new Thread() {
        public void run() {
            try { player.play(); }
            catch (Exception e) { System.out.println(e); }
        }
    }.start();
}  
}

我的音乐课:

import java.util.*;

public class Music{
private ArrayList<String> music;

public Music(){music = new ArrayList<String>();}

public int size(){return music.size();}

public void addSong(String song){music.add(song);}

public String getSong(){return music.get(music.size());}

public String getSong(int num){return music.get(num);}

public void removeSong(String song){
    for(int i = 0; i < music.size(); i++){
        if(music.get(i).equals(song)) {music.remove(i); return;}
    }
}

public String toString(){
    String s = "";
    for(int i = 0; i < music.size(); i++){
        s += music.get(i);
    }
    return s;
}
}

我的 MusicDriver 类:

import java.util.*;
import java.io.*;
import javazoom.jl.player.Player;
import java.util.Random;
import java.util.Scanner;
import java.io.FileNotFoundException;

public class MusicDriver{
public static void main(String[] args) throws FileNotFoundException{
    Random r = new Random();
    Scanner s = new Scanner(System.in);
    String line = "";
    int number;

    Music song = new Music();
    song.addSong("1-01-overture.mp3");
    song.addSong("1-03-fortune-teller-2.mp3");
    song.addSong("1-07-prayer.mp3");
    song.addSong("1-08-island-atlas.mp3");
    song.addSong("1-12-warren-report.mp3");
    song.addSong("1-13-avilla-hanya.mp3");
    song.addSong("1-20-war-situation.mp3");
    song.addSong("2-10-fog-of-phantom.mp3");
    song.addSong("2-12-religious-precepts.mp3");
    song.addSong("2-14-box-of-sentiment.mp3");
    song.addSong("3-02-light-everlasting.mp3");
    song.addSong("3-09-viking-spirits.mp3");
    song.addSong("3-12-unsealed.mp3");
    song.addSong("3-16-notice-of-death-reprise-.mp3");
    //14 songs

    ArrayList<Integer> songNums = new ArrayList<Integer>();
    MP3 mp3 = new MP3();
    do{
        if(songNums.size() == song.size()) songNums.clear();

        number = r.nextInt(song.size());
        boolean done = false;
        int counter = 0;
        while(!done){
            for(int i = 0; i < songNums.size(); i++){
                if(number == songNums.get(i).intValue()) {number = r.nextInt(song.size()); counter++;}
            }
            if(counter == 0) done = true;
            else done = false;
        }

        songNums.add(number);
        mp3.playMP3(song.getSong(number));
        System.out.println("Now Playing " + song.getSong(number));
        System.out.println("Enter \"Stop\" to stop playing the song");
        System.out.println("Enter \"n\" to play the next song");
        line = s.nextLine();
        mp3.stopMP3();
    }while(line.equals("n"));
    mp3.stopMP3();
}
}

我已经对为什么我的程序停止播放我的歌曲进行了大量研究,但我找不到任何东西。我做到了,如果您在有任何输出之前要求输入,则发现 BlueJ 程序不会打开终端窗口(当您执行“System.out.print()”时会出现这种情况)但我不认为这个程序考虑到了这一点。我还确保在我想播放下一首歌曲时输入了一个字符串“n”,对于前几首歌曲,它可以工作,但在第八首歌曲之后,它就停止了。我彻底糊涂了。

【问题讨论】:

  • 只需 Collections.shuffle() 列表并在 for-each 循环中一首歌曲播放
  • 是否必须在 do-while 循环结束之前调用 stopMP3?我怀疑那里过早停止的可能原因。
  • 您是否偶然遇到任何异常?
  • 并且您似乎需要某种同步(以便在歌曲完成后查询输入)。现在MP3#playMP3() 没有阻塞,所以它会在歌曲开始后立即返回(我想你什么时候不需要问“播放下一个?”)
  • @SendhilkumarAlalasundaram 我认为这里的主要问题是缺乏了解哪些方法应该阻塞,哪些方法不应该阻塞,它们如何在线程中运行以及如何正确同步所有这些东西

标签: java do-while


【解决方案1】:

我认为唯一的问题在于您用于洗牌列表的逻辑。

number = r.nextInt(song.size());
boolean done = false;
int counter = 0;
while(!done){
    for(int i = 0; i < songNums.size(); i++){
        if(number == songNums.get(i).intValue()) {number = r.nextInt(song.size()); counter++;}
    }
    if(counter == 0) done = true;
    else done = false;
}

当生成的随机数已经存在于 songNums 列表中时,您正在生成一个新的随机数。这个新的随机数不会与所有歌曲编号列表的编号一起检查。以下更改应该可以解决您的问题。

    boolean done = false;
    while(!done){
        number = r.nextInt(song.size());
        if(!songNum.contains(number)) done = true;
    }

或者,您可以在 cmets 中使用 Sasha 的建议来对列表进行洗牌(Collections.shuffle())。

【讨论】:

    【解决方案2】:

    您现有算法的实际问题是,当您发现一首已播放的歌曲时,您没有重置counter。所以一旦你重复,你就会陷入无限循环 - done 永远不会是真的。

    (实际上,它不会是无限的——一旦counter 到达Integer.MAX_VALUE 它会环绕到Integer.MIN_VALUE 并最终再次到达0,所以如果你离开它足够长的时间它最终会播放另一首歌曲)

    这里已经有一些关于改进代码的有用建议,我不会在这里重复它们,但可以解决您所拥有的问题的最小更改是将 counter 的初始化移动到循环内的 0

    boolean done = false;
    
    while(!done){
        int counter = 0; // reset counter every time
    
        for(int i = 0; i < songNums.size(); i++){
            if(number == songNums.get(i).intValue()) {number = r.nextInt(song.size()); counter++;}
        }
    
        if(counter == 0) done = true;
        else done = false;
    }
    

    【讨论】:

      【解决方案3】:

      Sasha 在 cmets 中说过:使用 Collections.shuffle()。在实践中,这看起来有点像这样:

      在 Music 类中有一个获取所有歌曲的方法:

      public List<String> getSongs() {return music;}
      

      MusicDriver 中的循环如下:

      List<String> songs = song.getSongs();
      do{
          Collections.shuffle(songs);
          for (String songToPly: songs) {
              mp3.playMP3(song.getSong(number));
              System.out.println("Now Playing " + song.getSong(number));
              System.out.println("Enter \"Stop\" to stop playing the song");
              System.out.println("Enter \"n\" to play the next song");
              mp3.stopMP3();
              line = s.nextLine();
              if (!line.equals("n")) break;
          }
      }while(line.equals("n"));
      

      在变量命名说明中,将 Music 类的实例命名为“歌曲”(单数)有点令人困惑。或许可以称它为“音乐”或至少是“歌曲”。

      【讨论】:

        【解决方案4】:

        我会做的是:

        public class MainClass() {
        
            public static void main(String[] args) {
                PlayerWrapper player = new PlayerWrapper();
            }
        }
        
        public class PlayerWrapper() {
            private List<MP3> playlist;
            private Scanner userInputReader;
            private String currentUserInput;
        
            public PlayerWrapper() {
                userInputReader = new Scanner(System.in());
                System.out.println("Filepath to playlist?");
                String playlistFileName = userInputReader.nextLine();
                playlist = PlayListExtractor.extractPlaylist(playlistFileName);
                start();
            }
        
            public void start() {
                playlistCopy = new ArrayList<MP3>(playlist);
                shufflePlayList(playlistCopy);
                Iterator<MP3> songIterator = playlistCopy.iterator();
                while (songIterator.hasNext()) {
                    MP3 song = songIterator.next();
                    songIterator.remove();
                    player = new Player(song.toStream());
                    player.play();
                    displayCurrentSongAndCommands(song);
                    currentUserInput = userInputReader.nextLine();
                    if ("Stop".equals(currentUserInput )) {
                        player.close();
                        break;
                    } else if ("n".equals(currentUserInput )) {
                        player.close();
                        continue;
                    }
                }
        
                if("Stop".equals(currentUserInput)) {
                    System.out.println("Playlist stopped. Press q to quit or c to continue");
                    currentUserInput = userInputReader.nextLine();
                    if ("q".equals(currentUserInput)) {
                        System.exit(0);
                    } else if ("c".equals(currentUserInput)) {
                        start();
                    }
                }
                start();
            }
        
            private void shufflePlayList(final List<MP3> playlistToBeShuffled) {
                long seed = System.nanoTime();
                Collections.shuffle(playlistToBeShuffled, new Random(seed));               
            }
        
            private void displayCurrentSongAndCommands(final MP3 currentSong) {
                System.out.println("Now Playing " + currentSong.toString());
                System.out.println("Enter \"Stop\" to stop playing the song");
                System.out.println("Enter \"n\" to play the next song");
            }
        }
        
        public static class PlayListExtractor() {
            private PlayListExtractor();
        
            public static List<MP3> extractPlayList(final String playListFileName) {
                List<MP3> result = new ArrayList<>();
                try (BufferedReader br = new BufferedReader(new FileReader(file))) {
                    String line;
                    while ((line = br.readLine()) != null) {
                        result.add(new MP3(line));
                    }
                    return result;
                } catch (IOException e) {
                    System.out.println("Problem parsing playlist");
                }
            }
        }
        
        public class MP3 {
            private String filename;
        
            public MP3(final String filename) {
                this.filename = filename;
            }
        
            public BufferedInputStream toStream() {
                try {
                    FileInputStream fis = new FileInputStream(filename);
                    return new BufferedInputStream(fis);                  
                }
                catch (Exception e) {
                    System.out.println("Problem playing file " + filename);
                    System.out.println(e);
                } 
            }
        
            public String toString() {
                return filename;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-09-13
          • 1970-01-01
          • 2016-05-26
          • 1970-01-01
          • 2013-01-19
          • 2013-09-28
          • 2018-12-12
          • 2016-07-14
          相关资源
          最近更新 更多