Programs become interactive when they read input. Scanner in = new Scanner(System.in) reads from the keyboard (or from a file piped into the program). Create one Scanner for the whole program. Reading whole lines with nextLine() and converting them yourself is the most predictable approach: mixing nextInt() with nextLine() leaves the end of the line behind and causes confusing skipped inputs.
People type anything, so never trust input. Integer.parseInt throws NumberFormatException for text like "4x": catch it and ask again. A helper method such as askInt(in, prompt, min, max) that loops until the value is valid keeps main readable. hasNextLine() returns false when the input ends (Ctrl+D, or the end of a piped file), so check it instead of crashing.
System.out.printf formats output: %d for whole numbers, %.1f for one decimal place, %s for text, %-15s to left-align in 15 characters, %,d for thousands separators and %n for a new line. Testing with piped input (printf '...' | java Scores.java) lets you try many cases quickly without typing them each time.
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Scores {
public static void main(String[] args) {
// One Scanner for System.in, for the whole program
Scanner in = new Scanner(System.in);
List<String> names = new ArrayList<>();
List<Integer> scores = new ArrayList<>();
System.out.println("Enter name and score per line, e.g. 'Amina 88'. Empty line to finish.");
while (in.hasNextLine()) {
String line = in.nextLine().trim();
if (line.isEmpty()) break;
int space = line.lastIndexOf(' ');
if (space < 1) {
System.out.println(" Please type a name, a space and a score.");
continue;
}
String name = line.substring(0, space).trim();
String scoreText = line.substring(space + 1);
try {
int score = Integer.parseInt(scoreText);
if (score < 0 || score > 100) {
System.out.println(" Score must be 0-100.");
continue;
}
names.add(name);
scores.add(score);
} catch (NumberFormatException e) {
System.out.println(" '" + scoreText + "' is not a whole number.");
}
}
if (scores.isEmpty()) {
System.out.println("No scores entered.");
return;
}
int best = 0;
double total = 0;
for (int i = 0; i < scores.size(); i++) {
total += scores.get(i);
if (scores.get(i) > scores.get(best)) best = i;
}
System.out.printf("%d students, average %.1f, top: %s (%d)%n",
scores.size(), total / scores.size(), names.get(best), scores.get(best));
}
}import java.util.Scanner;
public class Ages {
// Keep asking until the user types a valid whole number in range.
static int askInt(Scanner in, String prompt, int min, int max) {
while (true) {
System.out.print(prompt);
if (!in.hasNextLine()) throw new IllegalStateException("no more input");
String text = in.nextLine().trim();
try {
int value = Integer.parseInt(text);
if (value >= min && value <= max) return value;
} catch (NumberFormatException ignored) {
// fall through to the message below
}
System.out.printf("Please enter a number from %d to %d.%n", min, max);
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Your name: ");
String name = in.nextLine().trim();
int year = askInt(in, "Year you were born: ", 1900, 2026);
System.out.printf("Hello %s, you turn %d in 2026.%n", name, 2026 - year);
}
}java Scores.java # type lines, then an empty line
# Or feed a file of test input instead of typing:
printf 'Amina Hassan 88\nJuma 4x\nNeema Kimaro 71\n\n' | java Scores.javaKey points
- One
ScanneronSystem.in; read lines withnextLine()and convert them yourself. - Catch
NumberFormatException, check ranges, and loop until the input is valid. - Format output with
printf(%d,%.1f,%-15s,%,d,%n).
Exercise
Build a menu program: 1) add a student (name and score, re-asking until valid), 2) list all students in neat columns, 3) show the count, average, highest and lowest score, 4) quit. It must not crash on bad input or when the input ends.
Show solution
Try the exercise yourself first — then compare your approach with this one.
askLine returns null when the input ends, and askInt loops until it gets a whole number in range, so main only has to handle valid values. Each menu choice is one case of an arrow switch; break inside a case block leaves the switch early (for example, when the name is too short). The statistics are a single loop over the scores.
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Menu {
static final Scanner IN = new Scanner(System.in);
// Returns null when the input has ended (Ctrl+D, or the end of a piped file).
static String askLine(String prompt) {
System.out.print(prompt);
if (!IN.hasNextLine()) return null;
return IN.nextLine().trim();
}
static Integer askInt(String prompt, int min, int max) {
while (true) {
String text = askLine(prompt);
if (text == null) return null;
try {
int value = Integer.parseInt(text);
if (value >= min && value <= max) return value;
} catch (NumberFormatException ignored) {
// not a number: fall through to the message
}
System.out.printf(" Please enter a number from %d to %d.%n", min, max);
}
}
public static void main(String[] args) {
List<String> names = new ArrayList<>();
List<Integer> scores = new ArrayList<>();
while (true) {
System.out.println();
System.out.println("1) Add student 2) List 3) Statistics 4) Quit");
Integer choice = askInt("Choose: ", 1, 4);
if (choice == null || choice == 4) break;
switch (choice) {
case 1 -> {
String name = askLine(" Name: ");
if (name == null || name.length() < 2) {
System.out.println(" Name must have at least 2 letters.");
break;
}
Integer score = askInt(" Score: ", 0, 100);
if (score == null) break;
names.add(name);
scores.add(score);
System.out.println(" Added " + name + ".");
}
case 2 -> {
for (int i = 0; i < names.size(); i++) {
System.out.printf(" %-15s %3d%n", names.get(i), scores.get(i));
}
}
case 3 -> {
if (scores.isEmpty()) {
System.out.println(" No students yet.");
break;
}
int highest = scores.get(0);
int lowest = scores.get(0);
int total = 0;
for (int score : scores) {
highest = Math.max(highest, score);
lowest = Math.min(lowest, score);
total += score;
}
System.out.printf(" %d students, average %.1f, highest %d, lowest %d%n",
scores.size(), (double) total / scores.size(), highest, lowest);
}
default -> System.out.println(" Unknown choice.");
}
}
System.out.println("Goodbye!");
}
}