Scanner, Constants, and Formatted Output

Where System.out actually comes from, how to read input from the keyboard with a Scanner, the vocabulary that makes compiler errors readable, naming magic numbers with final, and printf for output you control to the decimal place. Follows Think Java 2e, Chapter 3 (Input and Output), Sections 3.1-3.5, pp. 33-40, cross-referenced against Java SE 21 API — java.util.Scanner.

Subject: Java · 65 slides · code lesson

Open the interactive version of this deck

What this lesson covers

The lesson, slide by slide

1. Scanner, Constants, and Formatted Output

Title

Think Java 2e · Chapter 3 · Input and Output

Sections 3.1-3.5 · pp. 33-40

2. What you will be able to do

Objectives

This lesson follows Think Java 2e, Chapter 3 (Input and Output), Sections 3.1-3.5, pp. 33-40. Everything on these slides can be checked against those pages.

1. Explain what System, System.out and PrintStream are, and what a package is.

2. Import and create a Scanner, and read a line of input from the keyboard.

3. Name the elements of a Java program from package down to token, and use that vocabulary to read an error message.

4. Identify a magic number and replace it with a named constant declared final.

5. Use printf with a format string, and choose the right format specifier for an integer, a double or a string.

6. Say why the Java language and the Java library are different things.

3. Retrieve before you read

Warm-up

You have typed one phrase hundreds of times without asking what it means.

Discussion prompt

System.out.println("hi"); has three names in it separated by dots: System, out, and println. Guess what each one is — which is a class, which is a variable, which is a method?

Hint: Class names start with a capital letter. Variables and methods start lowercase.

Answer:

System is a class, out is a variable inside it, and println is a method belonging to whatever out holds. The capitalisation told you: System is capitalised like every class, out and println are not.

That reading — class, then variable, then method — is exactly what Section 3.1 confirms, and it is the first time the dots have meant anything rather than being part of a magic phrase.

4. The chapter that makes programs interactive

Concept

Every program so far has produced the same output every time it ran. This chapter adds input, so a program's behaviour depends on what a person types — and printf, so the output is formatted the way you want rather than the way Java defaults to.

Figure (svg): A pipeline showing keyboard input flowing into a Scanner, then a calculation, then printf, then formatted output

Downey & Mayfield, Think Java, 2nd edition (Green Tea Press / O'Reilly, 2020) — Think Java 2e, Chapter 3 (Input and Output), Sections 3.1-3.5, pp. 33-40 — Chapter 3 opens on printed page 33.

5. The System class

Section

Section 3.1

6. System.out is a value you can print

Concept

System is a class that provides methods related to the system, or environment, where programs run. It also provides System.out, a special value with additional methods — like println — for displaying output. You can prove it is a value by printing it.

System.out.println(System.out);
part of the outputwhat it tells you
java.io.PrintStreamSystem.out is a PrintStream, defined in the java.io package
@separates the type from the address
685d72cdthe address in memory, in hexadecimal — yours will differ

package — A collection of related classes. java.io contains classes for I/O, which stands for input and output.

address — The location of a value in the computer's memory, often shown as a hexadecimal number.

The result is something like java.io.PrintStream@685d72cd. If you run the same code you will very likely get a different address — it is a location in memory, not a name.

7. Reading System.out.println from left to right

Picture it

Three names, two dots, and each step goes one level inward. Once you can read this, every dotted expression in Java reads the same way.

Figure (svg): A banner breaking System.out.println into three parts labelled class, variable and method

System is defined in a file called System.java, and PrintStream in PrintStream.java. Both are part of the Java library — an extensive collection of classes you can use in your programs, whose source code usually ships with the compiler.

8. Working out what a dotted name means

Worked example

Apply the reading to an expression you have not been taught yet, and see how far the rule gets you.

System.out.println(System.out);
// java.io.PrintStream@685d72cd
stepwhat you are looking atconclusion
Systemcapitaliseda class
System.outlowercase, inside a classa variable belonging to that class
the printed typejava.io.PrintStreamthe variable holds a PrintStream
System.out.printlnlowercase, called with parenthesesa method belonging to the PrintStream

Split the expression at the dots.

Why: System, then out, then println — three names, read left to right.

Use capitalisation to classify each one.

Why: A capital first letter means a class; lowercase means a variable or a method.

Use parentheses to tell a method from a variable.

Why: println(...) is called, so it is a method. out is not, so it is a variable.

Read the whole thing as a sentence.

Why: In the class System, take the variable out, and call its println method.

Verify: Run System.out.println(System.out); and check the output names a PrintStream in java.io.

Why: If the address you get differs from the book's, that is correct — the address is where the value happens to live in your machine's memory this run.

9. Class, variable, or method?

Definition probe

Use capitalisation and parentheses to decide.

Sort into buckets

Sort each name from the expressions you have seen.

a class
System; PrintStream
a variable
out
a method
println; nextLine
cls
Capitalised first letter. Java's naming convention reserves that for class names, and the library follows it without exception.
var
Lowercase and used without parentheses — it names a stored value rather than an action.
mth
Lowercase and called with parentheses. The parentheses are what distinguish a method from a variable.

10. Packages: the drawer the class lives in

Concept

A package is a directory of classes that are related to each other. The full name of a class includes its package, which is why the output above says java.io.PrintStream rather than just PrintStream.

packagecontainsimported automatically?
java.langclasses fundamental to the language — System, Stringyes
java.ioinput and output — PrintStreamno
java.utilutility classes — Scannerno

The first row explains something you may have wondered about: why you can use System and String without importing anything. They are in java.lang, which Java imports for you. Everything else you have to ask for — which is the next section.

11. System.out is not a method

Trap

The trap

The assumption. System.out.println is one long name for one thing.

// if it were one name, this would be meaningless:
System.out.println(System.out);
if it were one name...but in fact...
System.out could not be printed on its ownit prints as java.io.PrintStream@...
there would be one method involvedthere is a class, a variable, and a method
you could never use out for anything elseyou can pass it around like any other value

Treating it as one magic phrase works for a while, and then stops — the first time you see System.err.println or store a PrintStream in a variable.

The fix

Three separate things, joined by dots that each mean 'inside'.

System.out.println(System.out);
// System   -> a class
// out      -> a variable holding a PrintStream
// println  -> a method of PrintStream
namekindhow you can tell
Systemclasscapitalised
outvariablelowercase, no parentheses
printlnmethodlowercase, called with parentheses

The same reading works for in.nextLine() on the next slides: in is a variable, nextLine is a method of whatever it holds. One rule, applied everywhere.

12. What does printing System.out show?

Prediction

You have seen the answer; make sure you know why each part is there.

Predict first

Which part of java.io.PrintStream@685d72cd will differ if you run the program again?

  • 685d72cd — the address in memory
  • java.io — the package
  • PrintStream — the type
  • None of it — the output is always identical

Correct: 685d72cd — the address in memory

Why: The package and the type are fixed properties of what System.out is, so they never change. The part after the @ is the address — where that value happens to be located in this run's memory — and it may differ every time you run the program and on different computers.

13. Match each class to its package

Matching

Three classes you have met or are about to meet.

Match the pairs

  • a. System
  • b. PrintStream
  • c. Scanner
  • r1. java.lang — imported automatically
  • r2. java.io — input and output classes
  • r3. java.util — utility classes

Why: System and String live in java.lang, which Java imports for you because those classes are fundamental to the language. PrintStream is in java.io and Scanner in java.util — and the fact that Scanner needs an import while System does not is entirely explained by which package each one is in.

14. Why does the address change between runs?

Socratic

A question about what an address actually is.

Discussion prompt

The number after the @ is described as the location of the value in the computer's memory. Why would that location not be the same every time the same program runs on the same computer?

Hint: What else is running on the machine?

Answer:

Because your program is not the only thing using memory. The operating system hands out whatever space is free when your program asks, and what is free depends on everything else running at that moment.

The useful consequence: an address is not an identity. It tells you where something is right now, not what it is. That distinction becomes important in Chapter 9, where two objects at different addresses can hold equal values — and comparing the addresses gives the wrong answer.

15. The Scanner class

Section

Section 3.2

16. Reading a line from the keyboard

Concept

The System class also provides System.in, an InputStream with methods for reading from the keyboard. Those methods are not convenient, so Java provides Scanner, a class with methods for inputting words, numbers and other data.

import java.util.Scanner;

public class Echo {
    public static void main(String[] args) {
        String line;
        Scanner in = new Scanner(System.in);

        System.out.print("Type something: ");
        line = in.nextLine();
        System.out.println("You said: " + line);
    }
}
linewhat it does
import java.util.Scanner;tells the compiler which Scanner you mean
Scanner in = new Scanner(System.in);creates a Scanner that reads from the keyboard
System.out.print("Type something: ");prompts, using print so the user types on the same line
line = in.nextLine();reads a line of input and returns it as a String
System.out.println("You said: " + line);echoes it back, using concatenation from Chapter 2

nextLine reads a line of input from the keyboard and returns a String — which is why line is declared as a String rather than anything else.

17. The three lines that set up any input program

Notation

Every program in the rest of this book that reads from the keyboard begins with these three lines. Learn them as a unit.

Annotate

  • The import goes at the top of the file, outside the class definition. Import statements cannot be inside a class; by convention they are at the beginning of the file.
  • Why import at all? It tells the compiler that when you write Scanner, you mean the one defined in java.util — there might be another class named Scanner in another package.
  • If you omit it you get a compiler error like cannot find symbol, which means the compiler does not know where to find the definition for Scanner.
  • new Scanner(System.in) creates a Scanner and tells it where to read from: System.in, the keyboard. The word new is doing real work here, and Chapter 10 explains it properly.
  • in is just a variable name. You could call it keyboard or sc. in is conventional because it reads well next to System.in.

Only the third line changes from program to program — and only to choose which next... method you call.

18. Reading two lines and echoing them

Worked example

The book's complete example. Trace what the user sees and what the program stores at each step.

Scanner in = new Scanner(System.in);
System.out.print("Type something: ");
String line = in.nextLine();
System.out.println("You said: " + line);
System.out.print("Type something else: ");
line = in.nextLine();
System.out.println("You also said: " + line);
stepon screenvalue of line
print the promptType something: —
nextLine waitsuser types: hello—
nextLine returns—"hello"
println the echoYou said: hello"hello"
second prompt and readuser types: again"again"
println the echoYou also said: again"again"

Use print, not println, for the prompt.

Why: So the user types on the same line as the question, which is what people expect.

Call in.nextLine() and store what it returns.

Why: The program stops and waits here until the user presses Enter.

Reuse the same variable for the second read.

Why: line = in.nextLine(); is an assignment, not a declaration — the variable already exists and its old value is replaced.

Verify: Run it, type two different phrases, and confirm each is echoed back under the right label.

Why: If the program does not wait for you, check that you called nextLine() with parentheses — without them you have named the method rather than calling it.

19. Order the lines of an input program

Ranking

Four lines, one correct order.

Put in order

  1. import java.util.Scanner;
  2. Scanner in = new Scanner(System.in);
  3. System.out.print("Type something: ");
  4. String line = in.nextLine();

Why: The import comes first and lives outside the class entirely. Inside main you must create the Scanner before using it, prompt before reading so the user knows what to type, and only then read. Prompting after reading is a real and confusing bug — the program appears to hang.

20. Why System does not need an import

Concept

You have been using System since Chapter 1 without importing anything, and now you have to import Scanner. The difference is which package each one lives in.

Figure (svg): A rule card stating that java.lang is imported automatically while every other package must be imported explicitly

According to the documentation, java.lang provides classes that are fundamental to the design of the Java programming language. The String class is part of it too — which is why you have been declaring String variables without importing anything.

21. Forgetting the import

Trap

The trap

The omission. The Scanner code is right; the file is missing one line at the top.

public class Echo {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String line = in.nextLine();
    }
}
what is missingthe messagewhat it means
import java.util.Scanner;cannot find symbolthe compiler does not know where Scanner is defined
—symbol: class Scannerit is telling you exactly which name it could not resolve

cannot find symbol is one of the most common compile errors you will meet, and a missing import is one of its two usual causes. The other is a misspelled variable name.

The fix

With the import, above the class definition.

import java.util.Scanner;

public class Echo {
    public static void main(String[] args) {
        String line;
        Scanner in = new Scanner(System.in);

        System.out.print("Type something: ");
        line = in.nextLine();
        System.out.println("You said: " + line);
    }
}
placementlegal?
above the class definitionyes — this is the convention
inside the classno — import statements cannot be inside a class definition
inside mainno — same reason

Note the second and third rows: this is not merely a style convention. An import inside a class is a compile error, so there is only one place it can go.

22. What is the type of what nextLine returns?

Prediction

The declaration on the left has to match.

Scanner in = new Scanner(System.in);
??? line = in.nextLine();
methodreturns
nextLine()a String — a whole line of text
nextInt()an int
nextDouble()a double

Predict first

What type must line be declared as?

  • String
  • int
  • char
  • Scanner

Correct: String

Why: nextLine reads a line of input and returns it as a String, so the variable receiving it must be a String. Even if the user types 42, nextLine hands back the two-character text "42" rather than the number — a distinction from Chapter 2 that matters a great deal here.

23. Set up a Scanner

Fill the middle

Complete the three lines that begin every interactive program.

Fill in the blanks

import java.util.Scanner;

public class Ask new} Scanner(System.in);
String answer = in.nextLine();
}
}

Why: import tells the compiler where Scanner is defined, new creates one, and nextLine reads a whole line and returns it as a String. Omitting the import gives 'cannot find symbol'; omitting new gives a different error, because Scanner is a class rather than a value you can assign directly.

24. What does the Scanner need to know?

Missing information

Look at what is passed to it.

Discussion prompt

new Scanner(System.in) passes System.in as an argument. What information is that giving the Scanner, and what would you pass instead if you wanted to read from somewhere other than the keyboard?

Hint: The Scanner reads characters. From where?

Answer:

It tells the Scanner where to read from. System.in is the keyboard, so new Scanner(System.in) means 'a Scanner that reads what the user types'.

A Scanner does not have to read the keyboard. Pass it a File and it reads that file; pass it a String and it reads the characters of that string. The class is one piece of machinery — reading words, numbers and lines out of a stream of characters — and the argument decides which stream.

That is a pattern worth noticing early: the same class, pointed at a different source. You will meet it repeatedly, and it is why learning Scanner properly is worth more than learning 'how to read the keyboard'.

25. The elements of a Java program

Section

Section 3.3

26. From package down to token

Concept

At this point you have seen nearly all of the organisational units that make up Java programs. They nest inside one another, largest to smallest — and knowing the names is what makes error messages readable.

Figure (svg): Six nested levels from package down to token, each labelled with an example

Comparing Java to English: statements are complete sentences, expressions are phrases, and tokens are individual words and punctuation marks.

27. One statement, taken apart

Notation

The book's own example. Count the tokens, find the expression, and notice what is not counted.

Annotate

  • Six tokens: hours, =, minutes, /, 60.0 and ;. Spaces are ignored by the compiler, so they are not tokens.
  • One expression: minutes / 60.0. An expression represents a single value to be computed — here, the result of the division.
  • The assignment is the statement, and it contains the expression. A statement performs a step; an expression produces a value.
  • Why this matters: error messages say things like not a statement, illegal start of expression, or unexpected token. Each of those names a level in this hierarchy, and knowing which level is being complained about narrows the search enormously.

An unexpected token error means the compiler found a word or symbol somewhere it cannot appear. Illegal start of expression means it expected something that computes a value and got something else.

28. Using the vocabulary to read an error

Worked example

A concrete payoff. Here is a broken line and the message it produces; use the hierarchy to locate the problem.

int x = ;
the messagewhich level it nameswhat to look for
illegal start of expressionexpressionsomething that should produce a value is missing
not a statementstatementa line that computes something but does not do anything with it
unexpected tokentokena symbol somewhere it cannot legally appear
cannot find symboltoken — a namea misspelled name, or a missing import

Read the message and identify which level it names.

Why: illegal start of expression names the expression level.

Look for the place an expression was expected.

Why: After = in an assignment, Java expects an expression. There is a semicolon instead.

Fix at that level.

Why: int x = 0; supplies the missing expression.

Note what the message did NOT say.

Why: It did not mention int or x, because the declaration part is fine. The message is narrower than it first appears.

Verify: Fix the line and recompile; the error disappears with no new one taking its place.

Why: The habit worth forming: read the message, name the level, then look only at that level. It turns a vague complaint into a specific search.

29. Order the elements from largest to smallest

Ranking

The nesting the book draws.

Put in order

  1. package
  2. class
  3. method
  4. statement
  5. expression
  6. token

Why: Packages contain classes, classes define methods, methods are sequences of statements, statements contain expressions, and expressions are built from tokens. The English analogy holds throughout: statements are sentences, expressions are phrases, and tokens are words and punctuation.

30. The Java language and the Java library are different

Concept

There is a big difference between the Java language, which defines the elements above, and the Java library, which provides the built-in classes you can import.

part of the languagepart of the library
public, class, static, void, intPrintStream, Scanner, String, System
the keywords, about 50 of themseveral thousand classes
defined by the language specificationwritten in Java, mostly
cannot be changed or replacedyou can write your own classes alongside them

The standard edition of Java comes with several thousand classes, which can be both exciting and intimidating. You can browse the whole library on Oracle's website — and interestingly, most of the Java library is itself written in Java.

31. Four error messages, four levels

Error analysis

Each of these names a different level of the hierarchy. Matching the message to the level is most of the diagnosis.

Annotate

  • cannot find symbol — a NAME the compiler cannot resolve. Either it is misspelled, or the class it names has not been imported. Here it is a missing import java.util.Scanner;.
  • illegal start of expression — the compiler reached a point where a value should be computed and found something that cannot start one. After = it needs an expression, and a semicolon is not one.
  • not a statement — x + 1; computes a value and then throws it away. That is a legal expression but not a legal statement, because a statement has to do something.
  • unexpected token — a symbol appearing where the grammar does not allow it. The extra closing parenthesis has no partner, so the compiler cannot fit it into the structure.
  • The method: name the level first, then search only at that level. Without the vocabulary, all four of these read as 'something is wrong somewhere'.

This slide is the reason Section 3.3 exists. It looks like a list of definitions and it is actually a decoder for the messages you will read hundreds of times.

32. Language or library?

Definition probe

One is defined by the specification; the other is a collection of classes someone wrote.

Sort into buckets

Sort each name.

the Java language
public; class; int
the Java library
Scanner; PrintStream
lang
A keyword defined by the language specification. There are about 50 of them and you cannot use them as names.
lib
A class someone wrote and shipped with Java. You could write your own class with a similar job — and most of the library is itself written in Java.

33. How many tokens?

Prediction

Remember what the compiler ignores.

int x = 5;
tokenkind
intkeyword
xvariable name
=operator
5number
;punctuation

Predict first

How many tokens are in int x = 5;?

  • 5
  • 4
  • 6
  • 3

Correct: 5

Why: The tokens are int, x, =, 5 and ; — five of them. Spaces are ignored by the compiler and are not tokens, which is the same fact that made publicclass illegal in Chapter 1: whitespace separates tokens but is not one.

34. Why does the vocabulary help?

Explain it to yourself

Make the case in your own words.

Discussion prompt

Section 3.3 is a list of definitions with no new code in it. Explain what it actually buys you, using one specific error message as your example.

Hint: Think about what you would do differently on seeing 'illegal start of expression'.

Answer:

It turns a vague complaint into a targeted search. Without the vocabulary, illegal start of expression means 'something is wrong'. With it, it means 'somewhere a value should be computed and is not' — so you look at the right-hand sides of assignments and the insides of parentheses, and nowhere else.

The general principle is worth more than the specific case: compiler messages are written in terms of the language's own structure. Learning that structure is what makes the messages readable, and it is why Think Java spends a section on vocabulary right after introducing a class you will misuse.

35. Literals, magic numbers, and constants

Section

Section 3.4

36. A magic number is a literal with no explanation

Concept

A value that appears in a program, like the number 2.54, is called a literal. There is nothing wrong with literals in general — but when a number appears in an expression with no explanation, it makes the code hard to read, and if the same value appears many times it makes the code hard to maintain.

int inch;
double cm;
Scanner in = new Scanner(System.in);

System.out.print("How many inches? ");
inch = in.nextInt();
cm = inch * 2.54;              // where does 2.54 come from?
versionreadable?maintainable?
cm = inch * 2.54;no — the reader must know the conversionno — the value could appear in many places
double cmPerInch = 2.54; cm = inch * cmPerInch;yes — the name explains itbetter — one place to change
final double CM_PER_INCH = 2.54;yesyes — and it cannot be reassigned by accident

literal — A value that appears directly in a program, such as 2.54 or "Hello".

magic number — A literal appearing in an expression with no explanation of where it came from.

The implication of the word magic is that being magic is not a good thing. A good practice is to assign such numbers to variables with meaningful names.

37. Three versions of the same line

Picture it

Each fixes one more problem than the last.

Figure (svg): Two panels comparing a bare magic number against a named final constant

The middle step — a plain variable with a good name — fixes readability but not correctness. Variables can vary, and the number of centimetres in an inch does not.

38. Turning a magic number into a constant

Worked example

Three refinements, each fixing something specific. Work through them in order and notice what each one adds.

// 1. magic number
cm = inch * 2.54;

// 2. named, but still a variable
double cmPerInch = 2.54;
cm = inch * cmPerInch;

// 3. named and fixed
final double CM_PER_INCH = 2.54;
cm = inch * CM_PER_INCH;
versionexplains itself?can be reassigned?naming style
2.54 inlinenon/a—
double cmPerInchyesyes — a risklowerCamelCase, like any variable
final double CM_PER_INCHyesno — the compiler forbids itALL_CAPS with underscores

Give the number a meaningful name.

Why: The reader no longer has to know that 2.54 is centimetres per inch — the code says so.

Notice the remaining problem.

Why: Variables can vary, hence the term. But the number of centimetres in an inch does not, and nothing so far prevents a later line from changing it.

Declare it final.

Why: Declaring that a variable is final means it cannot be reassigned once it has been initialised. If you try, the compiler gives an error.

Rename it in the constant style.

Why: By convention, names for constants are all uppercase with underscores between words: CM_PER_INCH.

Verify: Add the line CM_PER_INCH = 2.55; after the declaration and confirm the compiler refuses to build the program.

Why: That refusal is the whole point: final turns a rule you were relying on remembering into a rule the compiler enforces.

39. Magic number or acceptable literal?

Definition probe

Not every literal is a magic number. The test is whether a reader would have to ask where it came from.

Sort into buckets

Sort each literal by whether it should be replaced with a named constant.

name it
2.54 in cm = inch * 2.54; 12 in feet = inches / 12; 9.81 in force = mass * 9.81
leave it inline
0 in int count = 0;; 1 in x = x + 1
magic
The value encodes a fact about the world that the reader would otherwise have to know or look up — a conversion factor, a physical constant. Naming it turns the code into an explanation.
fine
The value is structural rather than factual: starting a count at zero or adding one to a counter needs no explanation, and naming it would add noise without adding meaning.

40. What final actually buys you

Concept

final is the first keyword you have met whose job is to forbid something. It is worth being clear about what it prevents and what it does not.

with finalwithout
can be readyesyes
can be initialised onceyesyes
can be reassigned laterno — compile erroryes
names an unchanging factsays so explicitlyleaves it to convention
naming conventionCM_PER_INCHcmPerInch

The third row is the enforced one; the fourth is the communicative one. Both matter — the compiler stops you making the mistake, and the ALL_CAPS name tells every future reader that this value is not going to move.

41. Naming a constant like a variable

Trap

The trap

Correct but misleading. The value is fixed; the name says otherwise.

final double cmPerInch = 2.54;
final int inPerFoot = 12;
what the compiler seeswhat a reader sees
a constant — reassignment is forbiddenan ordinary variable that might change
no errorno signal that this value is fixed

This compiles and behaves correctly. The cost is entirely to the reader, which makes it exactly the kind of problem that survives into production code.

The fix

Constant style: all uppercase, underscores between words.

final double CM_PER_INCH = 2.54;
final int IN_PER_FOOT = 12;
kind of nameconventionexample
classUpperCamelCaseScanner
variablelowerCamelCasecmPerInch
methodlowerCamelCasenextLine
constantALL_CAPS_WITH_UNDERSCORESCM_PER_INCH

Four naming conventions, and you have now met all of them. None is enforced by the compiler; all are followed throughout the Java library, so a reader relies on them.

42. What does the compiler say?

Prediction

A constant is reassigned.

final double CM_PER_INCH = 2.54;
CM_PER_INCH = 2.55;
linelegal?
final double CM_PER_INCH = 2.54;yes — the one permitted initialisation
CM_PER_INCH = 2.55;no — reassignment of a final variable

Predict first

What happens when you compile this?

  • A compile error — a final variable cannot be reassigned
  • It compiles, and the value becomes 2.55
  • It compiles, and the value stays 2.54
  • A run-time exception

Correct: A compile error — a final variable cannot be reassigned

Why: Declaring a variable final means it cannot be reassigned once it has been initialised, and the compiler enforces that rather than merely recommending it. Catching this at compile time rather than at run time is the point: the mistake can never reach a user.

43. Match the name to its convention

Matching

Four kinds of name, four styles.

Match the pairs

  • a. a class
  • b. a variable
  • c. a method
  • d. a constant
  • r1. UpperCamelCase — Scanner
  • r2. lowerCamelCase — cmPerInch
  • r3. lowerCamelCase — nextLine
  • r4. ALL_CAPS_WITH_UNDERSCORES — CM_PER_INCH

Why: Variables and methods share a style, distinguished in use by the parentheses that follow a method call. Classes are capitalised and constants shout. None of this is enforced by the compiler, but the entire Java library follows it, so a reader who sees ALL_CAPS correctly expects a value that will not change.

44. What if a constant depends on user input?

Constraint

Push on what final can and cannot express.

Discussion prompt

You want a constant for the number of students in a class, but the number is typed in by the user when the program starts. Can that be final? What exactly does final promise?

Hint: Read the promise carefully: it says 'cannot be reassigned once it has been initialised'.

Answer:

Yes, it can. final does not mean 'known when you write the program' — it means assigned exactly once. final int CLASS_SIZE = in.nextInt(); is perfectly legal, and any later attempt to change it is a compile error.

So final expresses this value will not change during the run, which is a weaker and more useful promise than this value is a known constant of the universe. The ALL_CAPS naming convention is conventionally reserved for the latter — for a value read at start-up, most programmers would write final int classSize and keep the ordinary style.

45. Formatting output with printf

Section

Section 3.5

46. printf gives you control of the format

Concept

When you output a double with print or println, it displays up to 16 decimal places — which might be more than you want. System.out provides another method, printf, that gives you more control. The f stands for formatted.

System.out.print(4.0 / 3.0);
// 1.3333333333333333

System.out.printf("Four thirds = %.3f", 4.0 / 3.0);
// Four thirds = 1.333
part of the callnamejob
"Four thirds = %.3f"the format stringspecifies how the output should be displayed
Four thirds = ordinary textprinted literally
%.3fa format specifierdisplay the next value as floating-point, to 3 decimal places
4.0 / 3.0the valuematched up with the specifier

format string — The first argument to printf: ordinary text with format specifiers embedded in it.

format specifier — A special sequence starting with a percent sign that says how one value should be displayed.

A format specifier always starts with a percent sign. Everything else in the format string is printed exactly as written.

47. The format specifiers worth knowing

Notation

Learning about format strings is like learning a sublanguage within Java. There are many options; these seven cover nearly everything you will need.

Annotate

  • %d is for integers — d stands for decimal, meaning base 10, not 'decimal point'. This trips people up: %d will not accept a double.
  • %f is for floating-point, and on its own it shows six decimal places. %.2f rounds to two, which is what you want for money.
  • %s is for strings, and it is the most forgiving — nearly anything can be displayed as a string.
  • The number between % and the letter controls width and padding. %08d pads with zeros to at least eight digits, which is how you line up columns.
  • Values are matched to specifiers in order, left to right. The first value fills the first specifier, and a mismatch in count or type is an error you will meet in the next lesson.

For the full set, the documentation of java.util.Formatter is the reference. The easiest way to find documentation for any Java class is a web search for Java and the class name.

48. A format string with two specifiers

Worked example

The format string can contain any number of format specifiers. The values after it are matched up in order.

int inch = 100;
double cm = inch * CM_PER_INCH;
System.out.printf("%d in = %f cm\n", inch, cm);
specifiergets which valuedisplayed as
%dinch, which is 100100
%fcm, which is 254.0254.000000
\n—ends the line

Write the literal text and drop a specifier in wherever a value goes.

Why: "%d in = %f cm" — two values, so two specifiers.

List the values after the format string, separated by commas.

Why: inch, cm — in the same order as the specifiers that will consume them.

Match the specifier to the type.

Why: inch is an int so it takes %d; cm is a double so it takes %f.

Remember the newline.

Why: Like print, printf does not append a newline, so format strings often end with one.

Verify: Run it and expect 100 in = 254.000000 cm followed by a line break.

Why: If the output ran into whatever came next, you left the newline out of the format string — printf never adds one for you.

Six decimal places on 254.0 is more than anyone wants; %.2f would give 254.00, and %.0f would give 254.

49. What does this display?

Prediction

Two specifiers, two values, matched in order.

System.out.printf("%s is %d\n", "x", 5);
specifiervalueoutput
%s"x"x
%d55

Predict first

What appears on the screen?

  • x is 5
  • %s is %d
  • x is 5 with quotation marks
  • 5 is x

Correct: x is 5

Why: The values are matched up with the specifiers in order, so "x" fills the %s and 5 fills the %d, while the literal words is and the space are printed as written. The quotation marks are not part of the string's value, so they do not appear.

50. Choosing the specifier for the job

Concept

Most of the time the choice is decided by the type of the value. The interesting decisions are about how many digits to show.

you want to displayspecifierresult
a whole number of items%d42
money%.2f6.79
a large count, readably%,d12,345
a name or any text%sHello
a percentage, no decimals%.0f98
a fixed-width code%08d00012345

The money row is the one to remember. %.2f rounds to two decimal places for display — which is not the same as storing money accurately, as Lesson 2b warned. Store cents in an int; format for display only.

51. Using %d for a double

Trap

The trap

The mismatch. The specifier says integer; the value is floating-point.

double cm = 254.0;
System.out.printf("%d cm\n", cm);
specifierexpectsgivenresult
%dan integera doubleIllegalFormatConversionException at run time

This compiles cleanly — the compiler does not check the format string against the values — and then throws at run time. It is a run-time error, not a compile-time one, which makes it easy to ship.

The fix

Match the specifier to the type of the value.

double cm = 254.0;
System.out.printf("%.1f cm\n", cm);   // 254.0 cm

int inch = 100;
System.out.printf("%d in\n", inch);   // 100 in
value typespecifieroutput
int%d100
double%f or %.1f254.000000 or 254.0
String%sHello

If you genuinely want a double shown with no decimal places, use %.0f rather than %d. The specifier describes how to display the value, and it cannot change what type the value is.

52. Match the specifier to what it produces

Matching

Four specifiers from the table.

Match the pairs

  • a. %d
  • b. %.2f
  • c. %s
  • d. %,d
  • r1. 12345
  • r2. 6.79
  • r3. Hello
  • r4. 12,345

Why: %d prints an integer plainly and %,d adds comma separators to the same value. %.2f rounds a floating-point number to two decimal places, and %s displays text. The letter chooses the kind of value; anything between the percent sign and the letter adjusts the presentation.

53. Format a price

Fill the middle

Produce the line: Total: 6.79

Fill in the blanks

double total = 6.789;
System.out.printf("Total: %.2f%n", total);

Why: %.2f displays a floating-point value rounded to two decimal places, giving 6.79 from 6.789. Using plain %f would show six decimal places (6.789000), and %d would throw at run time because the value is a double rather than an integer.

54. How do you print a literal percent sign?

Edge cases

The percent sign now has a special job. Ask the escaping question from Lesson 1b.

Discussion prompt

In a format string, % starts a format specifier. So how would you print an actual percent sign — for example, the output 98% complete? Reason it out from what you know about escaping before looking it up.

Hint: How did you print a literal backslash once backslash became special?

Answer:

You double it: %%. System.out.printf("%d%% complete%n", 98); displays 98% complete.

This is exactly the pattern from Lesson 1b — a character was promoted to punctuation, so it needs a way to escape itself. The backslash escaped itself with \\; the percent sign escapes itself with %%. Different syntax, identical idea, and recognising the pattern means you can guess it rather than memorise it.

Note also %n in that example: it is printf's own newline specifier, and it is slightly more portable than \n because it uses whatever line ending the platform expects.

55. print, println, and printf

Comparison

Three ways to produce output, each better at something different. Fill the blanks.

Comparison matrix

printprintlnprintf
appends a newline?noyesno — end the format string with a newline
controls decimal places?nonoyes — %.2f and similar
how values are combinedconcatenation with +concatenation with +specifiers, values listed after, separated by commas
best forbuilding a line in piecesone complete line of plain outputformatted or aligned output

The row that causes real bugs is the third: printf takes its values as separate arguments after a comma, not joined with +. The next lesson opens with what happens when you mix the two up.

56. The pattern to carry away

Pattern

An interactive program has the same five-part shape every time, and you have now seen all five parts.

import java.util.Scanner;                          // 1. import

public class Convert {
    public static void main(String[] args) {
        final double CM_PER_INCH = 2.54;              // 2. constants
        Scanner in = new Scanner(System.in);          // 3. create the Scanner

        System.out.print("How many inches? ");        // 4. prompt and read
        int inch = in.nextInt();

        double cm = inch * CM_PER_INCH;               // 5. compute and format
        System.out.printf("%d in = %.2f cm%n", inch, cm);
    }
}
partwhy it is there
importnames which Scanner you mean
final constantsgives every magic number a name that cannot be changed
new Scanner(System.in)connects the program to the keyboard
print then nextIntprompt on the same line, then read
printfoutput formatted to the precision you chose

57. Check: the import

Check

Work it out before you click.

Check your understanding

Why does a program using Scanner need an import statement while one using System does not?

  • A. System is in java.lang, which is imported automatically; Scanner is in java.util, which is not (correct)
  • B. System is part of the Java language, and Scanner is part of the library
  • C. System does not need to be created with new, and Scanner does
  • D. Scanner is a newer class, so it requires an explicit import

Answer: A

Why: Java imports the java.lang package automatically because it provides classes fundamental to the language, and System and String both live there. Scanner is in java.util, so you must import it explicitly or the compiler reports 'cannot find symbol'.

Why B tempts people
Both System and Scanner are library classes. The Java LANGUAGE is the keywords like public and class; neither of these names is a keyword.
Why C tempts people
Whether a class needs new is unrelated to whether it needs importing — the two are decided by different things entirely.
Why D tempts people
Age has nothing to do with it. The rule is purely about which package a class lives in.

58. Check: constants

Check

Work it out before you click.

final int IN_PER_FOOT = 12;
int feet = 76 / IN_PER_FOOT;
IN_PER_FOOT = 10;
linelegal?
final int IN_PER_FOOT = 12;yes
int feet = 76 / IN_PER_FOOT;yes — reading a constant is fine
IN_PER_FOOT = 10;no

Check your understanding

What happens with this code?

  • A. A compile error on the third line (correct)
  • B. It compiles and feet becomes 7
  • C. A run-time exception on the third line
  • D. It compiles and the constant silently keeps its old value

Answer: A

Why: A variable declared final cannot be reassigned once it has been initialised, and the compiler enforces this, so the third line is a compile error and no program is produced. Reading the constant on the second line is perfectly fine — final restricts writing, not reading.

Why B tempts people
Nothing runs at all, because the program fails to compile. And 76 / 12 is 6 rather than 7 in any case.
Why C tempts people
This is caught at compile time, which is the advantage of final — the mistake can never reach a user.
Why D tempts people
Java does not silently ignore illegal assignments; it refuses to build the program.

59. Check: format specifiers

Check

Work it out before you click.

Check your understanding

Which printf call correctly displays the int 42 and the double 3.14159 rounded to two decimal places?

  • A. System.out.printf("%d and %.2f%n", 42, 3.14159); (correct)
  • B. System.out.printf("%f and %d%n", 42, 3.14159);
  • C. System.out.printf("%.2f and %d%n", 42, 3.14159);
  • D. System.out.printf("%d and %.2f%n" + 42 + 3.14159);

Answer: A

Why: The specifiers must match the types in order: %d takes the int 42 and %.2f takes the double 3.14159, displaying it as 3.14. The values follow the format string as separate arguments separated by commas.

Why B tempts people
The specifiers are in the wrong order for the values given, so %f would receive an int and %d a double, throwing IllegalFormatConversionException.
Why C tempts people
Same problem reversed — %.2f is matched with the int and %d with the double, which is a type mismatch at run time.
Why D tempts people
This concatenates the values onto the format string instead of passing them as arguments, so printf receives no values to format at all — the bug the next lesson opens with.

60. Why every language has a printf

Real world

The format-string idea is far older than Java and appears almost unchanged in a dozen languages.

Discussion prompt

You have just learned %d, %s and %.2f. Where else have you seen a string with placeholders in it that get filled in from a list of values?

Hint: Think about any templating you have seen, in any language or tool.

Answer:

The syntax came from C's printf in the 1970s and was carried into C++, Java, Python (% formatting), Ruby, PHP, Perl, Go and the shell's printf command — in most of them %d and %s mean exactly what they mean here.

The idea outlived the syntax too. Modern string interpolation — Python's f-strings, JavaScript's template literals, Java's own text blocks and formatters — is the same concept with the placeholders named rather than positional.

Why it matters to you now: the mistake in the next lesson — concatenating values onto a format string instead of passing them separately — is possible in every one of those languages, and it fails the same way in all of them.

61. How sure are you?

Commit first

Commit to an answer and to your confidence.

Predict first

What does System.out.printf("%d", 3.0); do?

  • Compiles, then throws an exception at run time
  • Fails to compile — the types do not match
  • Displays 3
  • Displays 3.0

Correct: Compiles, then throws an exception at run time

Why: The compiler does not check a format string against the values that follow it — the format string is just a String as far as compilation is concerned. So this builds successfully and then throws IllegalFormatConversionException when the line runs, because %d requires an integer and it was handed a double. This is a good example of a mistake that the compiler cannot catch for you, which makes predicting your own output the only defence.

62. Explain it to someone else

Explain it

Two minutes, out loud.

Discussion prompt

Explain to someone who has written a few programs why final double CM_PER_INCH = 2.54; is better than writing 2.54 where it is used. They will say it is more typing for no benefit. Give them two distinct reasons, one about reading and one about changing.

Hint: Imagine the number appearing in five places.

Answer:

Reading: inch * CM_PER_INCH says what the calculation means; inch * 2.54 requires the reader to already know the conversion. The name turns the code into its own explanation.

Changing: if the value appears in five places and needs correcting, you must find all five and change none of the other 2.54s that meant something different. With a constant there is exactly one place, and final guarantees nothing else has quietly overwritten it.

The 'more typing' objection is real and worth conceding — it is more typing. The trade is a few characters now against a class of bug later, and it is the same trade Java makes everywhere by asking you to declare types.

63. Exit ticket

Exit ticket

One question before you close the deck.

Predict first

In Scanner in = new Scanner(System.in); what is System.in, and what is it telling the Scanner?

  • The input stream connected to the keyboard — it tells the Scanner where to read from
  • The name of the variable being created
  • A method that reads a line of input
  • The package that Scanner belongs to

Correct: The input stream connected to the keyboard — it tells the Scanner where to read from

Why: System.in is a value provided by the System class — an InputStream connected to the keyboard — and passing it to the Scanner says which stream of characters to read. That is why the same Scanner class can also read a file or a string: only the argument changes. in on the left is the variable name, nextLine is the method that reads, and java.util is the package.

64. Draw the whole lesson

Connect it up

One page, from memory.

Draw it

Draw the six levels of a Java program from package down to token, as nested boxes, and put one example from this lesson in each. Beside it, write out the five-line skeleton of an interactive program — import, constant, Scanner, prompt-and-read, printf — and label which line each of the five would break if it were removed. Finally, write the three specifiers %d, %.2f and %s with the type each one requires.

65. Recap

Recap

Five sections that turn a program from something that talks at you into something you can talk to.

if you remember one thingit is this
about dotsclass, then variable, then method
about numbers in codegive them names, and make them final
about printfthe specifier must match the value's type

Sources

  1. Downey & Mayfield, Think Java, 2nd edition (Green Tea Press / O'Reilly, 2020) — Think Java 2e, Chapter 3 (Input and Output), Sections 3.1-3.5, pp. 33-40
  2. Java SE 21 API — java.util.Scanner
  3. Think Java 2e — free online edition and source code

Want this taught 1-on-1? Alexander tutors Java — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108