Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Java Java Data Structures Efficiency! Custom Serialization

Sara Worth
Sara Worth
5,225 Points

I would like to fix the Karaoke program so that if a user enters an incorrect selection won't crash

I am working on my own to fix the Karaoke program so that if a user enters an incorrect selection, the program responds with " Please make a valid selection" and lets the user try again, instead of crashing the program and editing. I am not getting very far. Any suggestions on how to do this efficiently?

The user is supposed to enter a number of one of the options on the screen. Any letter entered, or combination of letters and numbers, or nothing, or a number that is higher than the amount of options results in an IOException and the program crashes.

This is my attempt so far:. I am trying to check against anything but numbers being entered, nothing being entered, or a number that is higher than the options available. However this does not work and the program still exits if one of these invalid selections is made.

private int promptForIndex(List<String> options) throws IOException {
        int counter = 1;
        int choice;

        for (String option : options) {
            System.out.printf("%d.) %s %n", counter, option);
            counter ++;
        }

        String optionAsString = mReader.readLine();
        while (optionAsString.matches("\\D") || 
                           optionAsString == null || 
                           integer.parseInt(optionAsString.trim()) > options.length)
                {
            System.out.println("Please make valid selection... ");
            optionAsString = mReader.readline();
        }
        choice = Integer.parseInt(optionAsString.trim());
        return choice -1;

    }

Here is the full file:

package com.teamtreehouse;
import com.teamtreehouse.model.Song;
import com.teamtreehouse.model.SongBook;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;


public class KaraokeMachine {
  private SongBook mSongBook;
  private BufferedReader mReader;
  private Queue<Song> mSongQueue;
  private Map<String, String> mMenu;

  public KaraokeMachine(SongBook songBook) {
    mSongBook = songBook;
    mReader = new BufferedReader(new InputStreamReader(System.in));
    mSongQueue = new ArrayDeque<Song>();
    mMenu = new HashMap<String, String>();
    mMenu.put("add", "Add a new song to the song book");
    mMenu.put("play", "Play next song in the queue");
    mMenu.put("choose", "choose a song to sing!");
    mMenu.put("quit", "Give up. Exit the program");
  }

  private String promptAction() throws IOException {
   System.out.printf("There are %d songs available and %d in the queue.  Your options are: %n",
                     mSongBook.getSongCount(), 
                     mSongQueue.size());
    for (Map.Entry<String, String> option : mMenu.entrySet()) {
      System.out.printf("%s - %s %n",
                        option.getKey(),
                        option.getValue());
    }
    System.out.print("What do you want to do: ");
    String choice = mReader.readLine();
    return choice.trim().toLowerCase();
  }

  public void run() {
    String choice = "";
    do {
      try {
        choice = promptAction();
        switch(choice) {
          case "add":
            Song song = promptNewSong();
            mSongBook.addSong(song);
            System.out.printf("%s added!  %n%n%n", song);
            break;
          case "play":
            playNext();
            break;
          case "choose":
            String artist = promptArtist();
          Song artistSong = promptSongForArtist(artist);
          mSongQueue.add(artistSong);
          System.out.printf("%s %n", artistSong);
          break;
          case "quit":
            System.out.println("Thanks for playing!");
            break;
          default:
            System.out.printf("Unknown choice: '%s'. Try again.  %n%n%n%n",
                              choice);
        }
      } catch(IOException ioe) {
        System.out.println("Problem with input");
        ioe.printStackTrace();
      } 
    } while(!choice.equals("quit"));    

  }

  private Song promptNewSong() throws IOException {
    System.out.print("Enter the artist's name:  ");
    String artist = mReader.readLine();
    System.out.print("Enter the title:  ");
    String title = mReader.readLine();
    System.out.print("Enter the video URL:  ");
    String videoUrl = mReader.readLine();
    return new Song(artist, title, videoUrl);

  }

  private String promptArtist() throws IOException {
    System.out.println("Available artists: ");
    List<String> artist = new ArrayList<>(mSongBook.getArtists());
    int index = promptForIndex(artist);
    return artist.get(index);
  }

  private Song promptSongForArtist(String artist) throws IOException {
    System.out.printf("Available songs by %s %n", artist);
    List<Song> songs = mSongBook.getSongsForArtist(artist);
    List<String> songTitles = new ArrayList<>();
    for (Song song : songs) {
      songTitles.add(song.getTitle()); 
    }
    int index = promptForIndex(songTitles);
    return songs.get(index);
  }

    private int promptForIndex(List<String> options) throws IOException {
        int counter = 1;
        int choice;

        for (String option : options) {
            System.out.printf("%d.) %s %n", counter, option);
            counter ++;
        }

        String optionAsString = mReader.readLine();
        while (optionAsString.matches("\\D") || 
                    optionAsString == null ||
                    integer.parseint(optionAsString.trim()) > options.length)

                    {
            System.out.println("Please make valid selection... ");
            optionAsString = mReader.readline();
        }
        choice = Integer.parseInt(optionAsString.trim());
        return choice -1;

    }


// The following is the code that we learned to write in the lessons, and it is the block I am trying to fix

/*  
  private int promptForIndex(List<String> options) throws IOException {
    int counter = 1;
    int choice;

    for (String option : options) {
      System.out.printf("%d.)  %s %n", counter, option);
      counter ++;
    }
        String optionAsString = mReader.readLine();
        choice = Integer.parseInt(optionAsString.trim());
        return choice - 1; 
    }                
  }

  */

  public void playNext() {
    Song song = mSongQueue.poll();
    if (song == null) {
      System.out.println("Sorry there are no songs in the queue. " + 
                         "Use *choose* from the menu to add more songs.");
    } else {
      System.out.printf("%n%n%n Open %s to hear %s by %s %n%n%n",
                        song.getVideoUrl(),
                        song.getTitle(),
                        song.getArtist());
    }
  }

}

1 Answer

What part of the program prompts for a letter and not a number? i.e. what part are you trying to fix?

EDIT:

private int promptForIndex(List<String> options) {
    int choice = 0;
    boolean success = false;

    //loop through message until it is a success
    while (success == false) {
        int counter = 0; //<--------started at 0 to account for moving of counter
        for (String option : options) {
            counter++; //<---------------moved in front of display
            System.out.printf("%d.)  %s %n", counter, option);
        }
        System.out.print("Your choice:   ");

        // try catch to see if answer is an int. If it is then it goes through if-statement to confirm it is within range
        try {
            String optionAsString = mReader.readLine();
            choice = Integer.parseInt(optionAsString.trim());

            // if choice is larger than selesction then spit out error message
            if (choice > counter || choice < 0) {
                System.out.println("Invalid selection. Try again.");      
            } else {
                success = true;
            }
        } catch (Exception k) {
            System.out.println("Invalid selection. Try again.");
        } 
    }
    return choice - 1;
}

The out of bounds exception was from another part of the code. This was because a large number was valid, but returning the large number caused errors elsewhere. I added the if-statement to account for this.

I used a generic exception to catch everything else.

Sara Worth
Sara Worth
5,225 Points

I have added my code so it is easier to see what I am trying to do.

Updated my answer. Let me know what I missed.

Sara Worth
Sara Worth
5,225 Points

No, it needs a number input only, and not a number that is higher than the number of options provided.

Thank you for the code. I will try it out and let you know if it works in my situation.

Sara Worth
Sara Worth
5,225 Points

//UPDATE

OK that seems to work GREAT for most wrong inputs. The only exception is if there is only one option and I type in "2", it crashes the program. strange...

That was because the counter would increment after displaying the last option. I moved it in front of the display so it wouldn't increment after displaying all the options.

Sara Worth
Sara Worth
5,225 Points

That works! The only thing I changed was the line

if (choice > counter || choice <= 0) {

to account for someone entering 0 which led to a crash in the program.

Thank you so much for following through with this and solving the problem!! :)

No worries. Be sure to mark my answers as 'best answer' as they give me more points and really help. I just realized I have answered most of your questions recently haha.