1.8.1 Comments Are Notes for People
Open a program you wrote two months ago and you may not remember why a line says quizScore += bonus or what the 2 in int bonus = 2; stands for. Now imagine reading a program someone else wrote. Java code says exactly what the computer does, but it rarely says why. The reasons live in the programmer’s head, and nobody else can see them.
The fix is to write the reasons down, right next to the code, in plain English. Java gives you a way to do this so the compiler does not try to read your English as Java. In Topic 1.1 you saw that the compiler checks every line and translates it before the program runs. Text marked as a note is skipped by the compiler entirely: it is never checked, never translated, and never run.
A comment is text in a program that is written for people to read. Comments help the original programmer (you, later) and other programmers understand what the code does and why. The compiler ignores comments, so they are not part of the running program at all.
Key idea
Comments are notes for people. The compiler ignores them, so adding, removing, or changing a comment never changes what a program does.
The quickest kind of comment starts with two slashes, //: everything from // to the end of that line is a comment. (1.8.2 looks at this kind closely.)
Worked example: The same program with and without comments
Here is a short program with no comments. Read it and ask yourself: what is the 18? What is the 2? Is a score above 20 a mistake?
public class ScoreReport
{
public static void main(String[] args)
{
int quizScore = 18;
int bonus = 2;
quizScore += bonus;
System.out.print("Final quiz score: ");
System.out.println(quizScore);
}
}Final quiz score: 20Now the same statements with comments added on lines 5, 7, and 9:
public class ScoreReportCommented
{
public static void main(String[] args)
{
// Points earned on the quiz, out of 20.
int quizScore = 18;
// Extra credit for showing all work.
int bonus = 2;
// The bonus may push the score above 20. That is allowed.
quizScore += bonus;
System.out.print("Final quiz score: ");
System.out.println(quizScore);
}
}Final quiz score: 20Step by step, here is what the compiler and the computer do with the second version:
- The compiler reaches line 5, sees
//, and skips the rest of the line. The same happens on lines 7 and 9. - What is left to translate is exactly the five statements from the first program.
- When the program runs, it stores 18 in
quizScore, stores 2 inbonus, adds the bonus (quizScorebecomes 20), and prints the label and the score.
The output is identical. The only difference is for the human reader: the comments answer all three questions (18 is the quiz score out of 20, 2 is extra credit, and going above 20 is allowed).
Now change one thing: put a Java statement inside a comment. Programmers do this on purpose to switch a line off without deleting it, which is called commenting out the line.
int tickets = 3;
// System.out.println("Checking tickets...");
tickets *= 2;
System.out.println(tickets);6
Line 2 is a perfectly good println statement, but it sits after //, so the compiler treats it as a note and the program never prints Checking tickets.... Only line 4 prints, showing tickets after it was doubled. The rule depends on where the text is, not on what the text looks like: anything inside a comment is ignored, even if it is valid Java.
Watch out
Trusting a comment over the code. Because the compiler never reads comments, it cannot tell you when a comment is wrong. Read this carefully:
int score = 80;
// Add 10 bonus points.
score += 5;
System.out.println(score);85A student who reads only the comment predicts 90. But the comment is out of date: someone changed the bonus to 5 and forgot to update the note. The program does what the code says, so it prints 85. When a comment and the code disagree, the code wins. Whenever you change code, update its comment in the same moment, or you leave a trap for the next reader.
Pause and try
Question 1 · Multiple choice
A programmer adds ten comments to a program that already compiles and prints 42. Nothing else changes. What happens?
- The program still prints
42, because the compiler ignores comments. - The program prints the comments along with
42. - The program runs more slowly, because the computer has to read each comment.
- The program no longer compiles, because comments are not Java statements.
Check your reasoning
A. Comments are skipped by the compiler, so the translated program is exactly the same as before, and it prints 42.
- B is wrong: only
printandprintlnstatements produce output. A comment is never executed, so it is never displayed. - C is wrong: comments are not translated, so the running program does not contain them and cannot spend time on them.
- D is wrong: comments are allowed anywhere their markers are written correctly. They are not statements, so the compiler does not check them as Java.
Reread 1.8.1 Comments Are Notes for People if you chose differently.
Question 2 · Tracing
What does this code print?
int laps = 4;
// laps += 3;
laps *= 2;
// System.out.println(laps);
laps -= 1;
System.out.println(laps);Check your reasoning
7| Line | What happens | laps |
|---|---|---|
| 1 | laps is set to 4 |
4 |
| 2 | Comment: skipped | 4 |
| 3 | laps *= 2 doubles it |
8 |
| 4 | Comment: skipped, nothing shown | 8 |
| 5 | laps -= 1 subtracts 1 |
7 |
| 6 | Prints laps |
7 |
Lines 2 and 4 contain valid Java, but they are commented out, so they never run. If you got 13 or printed 8 as well, you ran a commented-out line. Reread 1.8.1 Comments Are Notes for People.
1.8.2 Single-Line Comments
Most notes a programmer needs are short: what a variable stands for, the units of a number, why a step is there. For those, a whole paragraph is too much. You want a note that fits on one line, sometimes on the same line as the code it explains.
A single-line comment starts with // and ends at the end of that line. It can take up a whole line by itself, or it can come after code on the same line, which is called an end-of-line comment.
// A whole-line comment: the entire line is a note.
int count = 3; // An end-of-line comment: the code runs, the note does not.
Take the second line apart:
int count = 3;comes before//, so it is ordinary code. The compiler translates it and it runs.//marks where the comment begins.An end-of-line comment: ...runs to the end of the line and is ignored.
There is no closing marker. The end of the line ends the comment, so the next line is code again.
Worked example: Labeling units with end-of-line comments
Each statement below has a note on its right. Look for where each note begins.
double price = 4.5; // price of one smoothie, in dollars
int count = 3; // smoothies ordered
double total = price * count; // 3 times 4.5
System.out.println(total);13.5- Line 1:
double price = 4.5;runs; the note “price of one smoothie, in dollars” tells the reader the unit. - Line 2:
int count = 3;runs; the note says what is being counted. - Line 3:
double total = price * count;runs. Adoubletimes anintgives adouble(Topic 1.3), sototalis 13.5. The note3 times 4.5is ignored, even though it looks like arithmetic. - Line 4 prints
13.5.
Now vary the order on a line. In int pages = 320; // number of pages, the code comes first and runs. Flip it, and the code is gone:
Watch out
Putting code after // on the same line. A student types the note first and the declaration after it:
public class CommentSwallowsCode
{
public static void main(String[] args)
{
// number of pages in the book int pages = 320;
System.out.println(pages);
}
}Everything after // on line 5 is a comment, including int pages = 320;. So pages is never declared, and line 6 cannot use it. The compiler reports:
CommentSwallowsCode.java:6: error: cannot find symbol
System.out.println(pages);
^
symbol: variable pages(The exact wording can vary between Java versions.) The fix is to put the code first and the note after it:
int pages = 320; // number of pages in the book
System.out.println(pages);This prints 320. A // comment is always the last thing on its line.
Pause and try
Question 3 · Multiple choice
In the line double tip = bill * 0.2; // 20% of bill * 0.2, which part does the compiler translate?
- Nothing; a line that contains
//is skipped completely. double tip = bill * 0.2;only- The whole line, including
20% of bill * 0.2 - Only
20% of bill * 0.2, because it comes last
Check your reasoning
B. A single-line comment starts at // and runs to the end of the line. Code before // is ordinary code.
- A is wrong: only the part from
//onward is ignored. End-of-line comments rely on the code before them still running. - C is wrong: the text after
//is a note, even though it looks like math. - D is wrong: it reverses the rule. What comes after
//is the part that is ignored.
Reread 1.8.2 Single-Line Comments if you chose differently.
Question 4 · Debugging
This code is supposed to start an album with 12 stamps, add 6, and print 18. It compiles, but it prints 12. Find the error and correct it.
int stamps = 12; // stamps in the album stamps += 6;
System.out.println(stamps);Check your reasoning
The error: stamps += 6; is on line 1, after //. That makes it part of the comment “stamps in the album stamps += 6;”, so it never runs. stamps stays 12.
Corrected code:
int stamps = 12; // stamps in the album
stamps += 6;
System.out.println(stamps);Now stamps += 6; is on its own line, outside any comment, and the code prints 18.
Notice that the original compiles. Unlike the pages example in 1.8.2, nothing later depends on a missing declaration, so the compiler has nothing to complain about. The result is a logic error (Topic 1.1): the program runs to the end with the wrong answer. Reread 1.8.2 Single-Line Comments if you did not spot it.
1.8.3 Block Comments
Sometimes a note needs several lines: a description of what a whole program does, or a few sentences about how a tricky step works. You could start every line with //, but there is a tool made for longer notes.
A block comment starts with /* and ends with */. Everything between the two markers is a comment, no matter how many lines it covers. Unlike //, the end of a line does not end a block comment; only */ does.
Worked example: Describing a program with a block comment
Lines 1 through 5 are one block comment. Look for where it opens and closes.
/*
* GardenOrder
* Works out how many seed packets to buy for a garden.
* Each row of the garden needs 4 packets.
*/
public class GardenOrder
{
public static void main(String[] args)
{
int rows = 6;
int packets = rows * 4;
System.out.println(packets);
}
}24- Line 1 opens the comment with
/*. From here on, the compiler ignores everything. - Lines 2 to 4 are the note. The
*at the start of each line is only decoration that many programmers use to make the block easy to see. It is ignored like the rest. - Line 5 closes the comment with
*/. Line 6 is code again. - The program runs:
rowsis 6,packetsis 6 × 4 = 24, and line 12 prints24.
Now use a block comment for a different job: switching off several lines at once.
int rows = 6;
/*
rows += 2;
System.out.println("Added two rows");
*/
int packets = rows * 4;
System.out.println(packets);24
Lines 3 and 4 are valid statements, but they sit between /* on line 2 and */ on line 5. Neither runs: rows stays 6 (not 8), Added two rows is never printed, and the output is still 24. Commenting out four lines with // would take four markers; a block comment takes one pair.
Watch out
Forgetting the closing */. Since only */ ends a block comment, leaving it out turns the rest of the file into a comment:
public class UnclosedComment
{
/*
* Prints a reminder before the test.
public static void main(String[] args)
{
System.out.println("Bring a calculator!");
}
}The comment opened on line 3 never closes, so the compiler swallows main, the println, and both closing braces. It reports:
UnclosedComment.java:3: error: unclosed comment
/*
^usually followed by a second error saying the end of the file was reached too early (wording can vary between Java versions). Fix it by adding */ on its own line after the note, before public static void main. Whenever you type /*, type */ right away and then fill in the note between them.
Here are the two kinds of comments so far, side by side:
| Kind | Starts with | Ends at | Typical use |
|---|---|---|---|
| Single-line comment | // |
The end of that line | Short note on one line, or after code |
| Block comment | /* |
The next */ |
Notes several lines long; switching off a block |
Pause and try
Question 5 · Tracing
What does this code print? Watch where the block comment ends.
int coins = 10;
/* coins += 5;
coins *= 2; */ coins -= 3;
System.out.println(coins);Check your reasoning
7| Line | What happens | coins |
|---|---|---|
| 1 | coins is set to 10 |
10 |
| 2 | /* opens a block comment; coins += 5; is inside it |
10 |
| 3 | coins *= 2; is still inside; */ closes the comment; coins -= 3; is code |
7 |
| 4 | Prints coins |
7 |
A block comment ends exactly at */, even in the middle of a line, so the code after it on line 3 runs. If you got 10, you treated all of line 3 as a comment. If you got 27, you ran the commented-out lines. Reread 1.8.3 Block Comments.
Question 6 · Multiple choice
A program has /* on line 4 and no */ anywhere after it. What happens?
- Only line 4 is a comment; the rest of the program compiles normally.
- The program compiles, but nothing after line 4 runs.
- The program does not compile, because the comment never ends.
- Java closes the comment automatically at the end of line 4.
Check your reasoning
C. Only */ ends a block comment, so everything after line 4 becomes part of it. The compiler reaches the end of the file still inside a comment and reports an “unclosed comment” error. A program with that error cannot run.
- A and D are wrong: they treat
/*like//. The end of a line does not end a block comment. - B is wrong: a program with a compile error is never translated, so nothing runs at all (Topic 1.1).
Reread 1.8.3 Block Comments if you chose differently.
1.8.4 Javadoc Comments and API Documentation
In Topic 1.7 you learned that a library’s documentation tells you what its classes can do: the methods of String and Math, what each one needs, and what each one gives back. Someone had to write those pages. Writing them separately from the code would be risky, since the pages and the code could drift apart. So the people who write a class put the documentation inside the source code, right above each class and method, and a tool builds the pages from it.
A Javadoc comment starts with /** (a slash and two stars) and ends with */. It is written directly above a class or a method and describes it. To the compiler, a Javadoc comment is just another comment and is ignored. But a separate tool that comes with Java, called javadoc, reads every /** */ comment in a class and turns them into the documentation pages, known as the API documentation, that programmers read. The String documentation you looked at in Topic 1.7 was built this way from comments in the String class’s source code.
Key idea
A Javadoc comment, written /** */ directly above a class or method, is ignored by the compiler like any comment, and
is used by the javadoc tool to create API documentation.
Worked example: Inside the String class
Here is a simplified sketch of how the String class’s source code begins. The real file is far longer, and its comments use different wording; this keeps only the shape. The bodies are left out, so this is for reading, not running.
/**
* A String holds a sequence of characters, such as "Hopper".
*/
public class String
{
/**
* Returns the number of characters in this string.
*
* @return the number of characters in this string
*/
public int length()
{
// ...the statements that count the characters...
}
}Read it from the top:
- The first comment, opened by
/**, sits directly abovepublic class String. It describes the whole class. The javadoc tool puts this sentence at the top of theStringdocumentation page. - The second Javadoc comment sits directly above the method header
public int length(). Its first sentence becomes the method’s description on the page. (publicis a word you can read past for now; method headers are taught fully in Topic 1.9.) - The line beginning with
@returnholds a Javadoc tag. A tag is a word starting with@that the javadoc tool treats specially.@returndescribes the value the method gives back, and the tool lists it under a “Returns” heading. - Inside the method’s braces is an ordinary
//comment. It is a note for whoever maintainsString, not for users of the class, so the tool does not put it on the documentation page.
A second common tag is @param, which describes a value the method needs to be given. Here is a simplified Javadoc comment for a Math method you will use in Topic 1.11:
/**
* Returns the absolute value of a: the value without its minus sign.
*
* @param a the number to use
* @return the absolute value of a
*/
public static int abs(int a)
The @param line names a, the value that goes in, and says what it is. The @return line says what comes out. (public static can be read past for now; those words are explained in later topics.)
Javadoc comments work in your own programs too. This program has one above the class and one above main:
/**
* Works out the tip on a restaurant bill.
*/
public class TipCalculator
{
/**
* Prints a 20 percent tip on a 45-dollar bill.
*/
public static void main(String[] args)
{
double bill = 45.0;
double tip = bill * 0.2;
System.out.println(tip);
}
}9.0
The compiler skips lines 1 to 3 and 6 to 8, just as it skips any comment. The program stores 45.0 in bill, computes 45.0 × 0.2 = 9.0, and prints 9.0. The Javadoc comments change nothing about how the program runs; they only give the javadoc tool something to turn into documentation.
Watch out
Writing /* when you mean /**. A comment that starts with /_and one that starts with/**look almost the same, and both compile, because the compiler ignores both. The difference shows up only in the documentation: the javadoc tool collects comments that start with/**and skips ordinary block comments. A student who writes a careful description in/_ _/above a method will find it missing from the documentation pages. Use/\*\*for documentation that users of a class should see, and/_or// for notes about how the code works inside.
All three kinds of comments together:
| Kind | Written as | Ignored by the compiler? | Used for |
|---|---|---|---|
| Single-line | // … |
Yes | A short note to the end of the line |
| Block | /* … */ |
Yes | A note spanning several lines |
| Javadoc | /** … */ |
Yes | Describing a class or method; builds API documentation |
Pause and try
Question 7 · Multiple choice
A programmer wants the description of a method to appear in the API documentation for her class. Which comment should she write directly above the method header?
// Returns the total price in cents./* Returns the total price in cents. *//** Returns the total price in cents. */- Any of these; the javadoc tool reads every comment.
Check your reasoning
C. The javadoc tool builds API documentation from comments that start with /** and sit directly above a class or method.
- A is wrong: a
//comment is a note for people reading the code. It is not collected into the documentation. - B is wrong: this is an ordinary block comment, one star short of a Javadoc comment, so the tool skips it.
- D is wrong: only
/** */comments become documentation. All three are ignored by the compiler, but that is a different question.
Reread 1.8.4 Javadoc Comments and API Documentation if you chose differently.
Question 8 · Short answer
Here is a simplified Javadoc comment from the Math class. Using only the comment, say what you must give this method, and what it gives back.
/**
* Returns the larger of two values.
*
* @param a one number
* @param b another number
* @return the larger of a and b
*/
public static int max(int a, int b)Check your reasoning
Model answer: The two @param lines say I must give the method two numbers, a and b. The @return line says it gives back whichever of the two is larger. For example, given 7 and 12, it gives back 12.
A complete answer must:
- use the
@paramlines to name what goes in (two values), and - use the
@returnline (or the first sentence) to name what comes out (the larger one).
Reread 1.8.4 Javadoc Comments and API Documentation if your answer differed.
1.8.5 Preconditions
A recipe for bread might say, “Start with the oven heated to 200 °C.” The recipe does not tell you to check the oven; it assumes you already did. If you skip that, the recipe still runs its steps, and you get a pale, raw loaf. Code works the same way: much of it only works if something is already true before it starts.
You have already met a piece of code like that. In Topic 1.5 you rounded a double to the nearest whole number with (int) (x + 0.5), and that trick works only when x is not negative. That “only when” is the idea of this subsection.
A precondition is a condition that has to be true right before a method or a segment of code runs, so that it does what its documentation says. Preconditions are usually stated in a comment. Here is the most important rule about them: the method or code is not expected to check its own precondition. Making sure the precondition is true is the job of whoever uses the code. If the precondition is false, all bets are off: the code may give a wrong answer, or the program may crash.
Key idea
A precondition is what must be true before a method or code segment runs. The code does not check it for you; you are responsible for making it true before you use the code.
Worked example: A precondition that is met, and one that is broken
The comment on line 1 states the precondition for the rounding code.
// Precondition: temperature is not negative.
double temperature = 2.7;
int rounded = (int) (temperature + 0.5);
System.out.println(rounded);3With temperature 2.7, the precondition holds (2.7 is not negative). Line 3 adds 0.5 to get 3.2, and the (int) cast drops the decimal part, giving 3. The nearest whole number to 2.7 is 3, so the code worked.
Now change only the value, so the precondition is broken:
// Precondition: temperature is not negative.
double temperature = -2.7;
int rounded = (int) (temperature + 0.5);
System.out.println(rounded);-2| Step | Value |
|---|---|
temperature |
-2.7 |
temperature + 0.5 |
-2.2 |
(int) drops the decimal |
-2 |
| Correct nearest whole number | -3 |
The code did not stop, warn, or check anything. It ran every step and printed -2, which is wrong: -2.7 is closer to -3. Casting drops the decimal part, which moves a positive number down but a negative number up, so the + 0.5 trick only works on the nonnegative side. The comment warned about exactly this, and it was the user’s job to obey it.
Breaking a precondition does not always give a quiet wrong answer. Sometimes the program crashes. This segment finds a player’s average points per game:
// Precondition: games is greater than 0.
int totalPoints = 84;
int games = 6;
System.out.println("Computing average...");
int average = totalPoints / games;
System.out.println(average);Computing average...
14
84 / 6 is 14, so all is well. Now suppose the player has not played yet, so games is 0:
// Precondition: games is greater than 0.
int totalPoints = 84;
int games = 0;
System.out.println("Computing average...");
int average = totalPoints / games;
System.out.println(average);Computing average...
Exception in thread "main" java.lang.ArithmeticException: / by zero
The first println runs, then line 5 asks Java to divide by zero. As you saw in Topic 1.1, that throws an exception and stops the program, so the average is never printed. (The full message also names the line, and its wording can vary between Java versions.) Again, the code did nothing to protect itself; the precondition comment was the only warning.
Methods in Java’s libraries have preconditions too, written in their Javadoc comments. Here is a simplified version of the documentation for the Math class’s square-root method, which you will use in Topics 1.10 and 1.11:
/**
* Returns the square root of a.
* Precondition: a is not negative.
*/
public static double sqrt(double a)
No real number times itself is negative, so a negative number has no square root to give back. The method does not promise to check its precondition for you; if you pass a negative number, you do not get a usable answer. So before you call it, you make sure the argument is not negative. Here it is used correctly. (Math.sqrt(area) calls the method on the value of area; Topic 1.10 explains calls like this fully.)
double area = 49.0;
double side = Math.sqrt(area);
System.out.println(side);7.0
area is 49.0, which is not negative, so the precondition holds and sqrt gives back 7.0.
Watch out
“If the input were bad, the code would tell me.” Students often assume code checks its own inputs and complains about bad ones. A precondition means the opposite: the code assumes the condition is true and goes ahead. The rounding example printed -2 with no warning at all. Before you run code that has a precondition, look at the values you are about to give it and confirm they meet the precondition yourself.
Pause and try
Question 9 · Multiple choice
The documentation for a method says, “Precondition: count is greater than 0.” A program calls the method with count equal to 0. Which statement is true?
- The method will notice that
countis 0 and print a warning. - The program will not compile, because the precondition is false.
- The method may give a wrong result or crash; the caller was responsible for making
countgreater than 0. - The method will change
countto 1 so that its precondition is true.
Check your reasoning
C. A method is not expected to check its precondition. Meeting it is the caller’s job, and if it is not met, the method’s behavior is not guaranteed.
- A is wrong: nothing promises a check. That is exactly what a precondition does not mean.
- B is wrong: the compiler ignores comments, so it never reads the precondition. And it cannot know what values a variable will hold when the program runs.
- D is wrong: the method does not repair its inputs. It simply assumes the condition is true.
Reread 1.8.5 Preconditions if you chose differently.
Question 10 · Tracing
What does this code print? Is that the nearest whole number to temperature?
// Precondition: temperature is not negative.
double temperature = -4.6;
int rounded = (int) (temperature + 0.5);
System.out.println(rounded);Check your reasoning
-4| Step | Value |
|---|---|
temperature |
-4.6 |
temperature + 0.5 |
-4.1 |
(int) drops the decimal |
-4 |
It is not the nearest whole number: -4.6 is closer to -5. The value is negative, so the precondition on line 1 is broken, and the rounding trick is not guaranteed to work. The code does not check; it just prints a wrong answer. Reread 1.8.5 Preconditions if your answer differed.
1.8.6 Postconditions
A precondition tells you what you must do before using some code. The other half of the deal is what the code promises after. When you use Math.sqrt correctly, what exactly do you get? If a method changes something, what will be different when it finishes? Without that promise, you would have to read the method’s code to find out, which is what documentation is meant to save you from.
A postcondition is a condition that is always true after a method or code segment finishes running (as long as its precondition was met). A postcondition describes the result: what value the method gives back, or what the current values of an object’s attributes are afterward. Think of it as the method’s promise. The precondition is your side of the deal; the postcondition is the method’s side.
Key idea
A postcondition is the guaranteed outcome after a method or code segment runs: the value it gives back, or the state its object’s attributes are left in.
Worked example: Checking a postcondition on real output
The comments on lines 1 to 3 state both conditions for this segment. Read the postcondition, then check the output against it.
// Precondition: totalMinutes is not negative.
// Postcondition: hours holds the whole hours in totalMinutes,
// and minutes holds the leftover minutes, from 0 to 59.
int totalMinutes = 135;
int hours = totalMinutes / 60;
int minutes = totalMinutes % 60;
System.out.print(hours);
System.out.print(" h ");
System.out.print(minutes);
System.out.println(" min");2 h 15 min| Line | What happens | Value |
|---|---|---|
| 4 | totalMinutes is set |
135 |
| 5 | 135 / 60, an int division |
hours is 2 |
| 6 | 135 % 60, the remainder |
minutes is 15 |
| 7–10 | Prints the parts on one line | 2 h 15 min |
The precondition held (135 is not negative), and the postcondition is true afterward: 2 whole hours, and 15 leftover minutes, which is between 0 and 59.
Now vary the input to test the edge of the promise: use 59 minutes, which is less than one hour. Changing line 4 to int totalMinutes = 59; prints:
0 h 59 min
59 / 60 is 0 and 59 % 60 is 59. The postcondition still holds: 0 whole hours, and 59 leftover minutes, which is in the 0 to 59 range. A good postcondition holds for every input that meets the precondition, not just typical ones.
Postconditions appear in Javadoc comments too. In the String sketch from 1.8.4, the line “Returns the number of characters in this string” is a postcondition stated in terms of what is returned: after length runs, you are guaranteed a count of the characters. The sqrt method’s documentation promises that it returns the square root of a.
A postcondition can also describe an object’s attributes (from Topic 1.7, the data a class keeps in variables). Here is the documentation for a method in an invented BankAccount class, whose attribute is the account’s balance. The rest of the header is taught in Topic 1.9; for now, focus on the comment.
/**
* Adds money to this account.
* Precondition: amount is greater than 0.
* Postcondition: the balance has gone up by amount.
*/
public void deposit(double amount)
This method does not give back a value. Its promise is about the attribute: when it finishes, the balance is larger by exactly amount.
| Question | Precondition | Postcondition |
|---|---|---|
| When is it true? | Right before the code runs | Right after the code finishes |
| Whose job is it? | The caller’s: make it true | The method’s: it promises this |
sqrt example |
a is not negative |
Returns the square root of a |
deposit example |
amount is greater than 0 |
The balance has gone up by amount |
Watch out
Mixing up the two. A student writes “Postcondition: amount must be greater than 0.” But that is a requirement on the value given to the method before it runs, so it is a precondition. Ask two questions about any condition: When is it true, before or after? And who makes it true, the caller or the method? A requirement the caller must meet beforehand is a precondition. A result the method guarantees afterward is a postcondition.
Pause and try
Question 11 · Multiple choice
A method that converts a test score to a letter grade is documented with four statements. Which one is a postcondition?
- The score must be between 0 and 100.
- The score given to the method is an
int. - The method returns one of the letters A, B, C, D, or F.
- The caller must not pass a negative score.
Check your reasoning
C. It describes the outcome: what the method gives back after it runs.
- A is wrong: it is a requirement on the input before the method runs, so it is a precondition.
- B is wrong: it is also about what goes in, not about the result.
- D is wrong: “the caller must” is the language of a precondition. It is the caller’s job, beforehand.
Reread 1.8.6 Postconditions if you chose differently.
Question 12 · Tracing
The segment from 1.8.6 is run with a new value. What does it print, and is its postcondition true afterward?
// Precondition: totalMinutes is not negative.
// Postcondition: hours holds the whole hours in totalMinutes,
// and minutes holds the leftover minutes, from 0 to 59.
int totalMinutes = 200;
int hours = totalMinutes / 60;
int minutes = totalMinutes % 60;
System.out.print(hours);
System.out.print(" h ");
System.out.print(minutes);
System.out.println(" min");Check your reasoning
3 h 20 min| Line | What happens | Value |
|---|---|---|
| 4 | Set the total | 200 |
| 5 | 200 / 60 |
hours is 3 |
| 6 | 200 % 60 |
minutes is 20 |
3 × 60 = 180, and 200 − 180 = 20. The precondition held (200 is not negative), so the postcondition is true: 3 whole hours and 20 leftover minutes, which is between 0 and 59. Reread 1.8.6 Postconditions if your answer differed.
Putting it together
This complete program uses all three kinds of comments and documents a precondition and a postcondition. Before reading the walkthrough, find each comment and decide which kind it is.
/**
* Splits pizza slices evenly among friends.
*/
public class PizzaShare
{
/**
* Prints each friend's share and the slices left over.
*/
public static void main(String[] args)
{
/*
* Precondition: friends is greater than 0.
* Postcondition: each friend's share and the leftover
* slices have been printed, and leftover is less than friends.
*/
int slices = 16; // 2 pizzas, 8 slices each
int friends = 5;
int perFriend = slices / friends; // whole slices only
int leftover = slices % friends;
System.out.print("Each friend gets ");
System.out.println(perFriend);
// System.out.println("Enjoy!");
System.out.print("Slices left over: ");
System.out.println(leftover);
}
}Each friend gets 3
Slices left over: 1
The comments.
| Lines | Kind | What it is for |
|---|---|---|
| 1–3 | Javadoc | Describes the class; would appear in documentation |
| 6–8 | Javadoc | Describes main |
| 11–15 | Block | States the precondition and postcondition for the code below it |
| 16, 19 | End-of-line | Explain where 16 comes from and that division keeps whole slices |
| 24 | Single-line | A println that has been commented out |
The run. The compiler skips every comment, leaving the statements on lines 16, 17, 19, 20, 22, 23, 25, and 26.
| Line | What happens | Variables or output |
|---|---|---|
| 16 | slices is set |
slices = 16 |
| 17 | friends is set |
friends = 5 |
| 19 | 16 / 5, an int division |
perFriend = 3 |
| 20 | 16 % 5, the remainder |
leftover = 1 |
| 22–23 | Label, then the value | Each friend gets 3 |
| 24 | Commented out: nothing happens | |
| 25–26 | Label, then the value | Slices left over: 1 |
Checking the conditions. The precondition held, since 5 is greater than 0. So the postcondition must be true, and it is: both values were printed, and the leftover (1) is less than the number of friends (5). If there were 5 or more slices left over, everyone could have had one more, so the division would have been wrong.
Breaking the precondition. If line 17 were int friends = 0;, the precondition would be false. Nothing in the program checks for that. Line 19 would divide by zero, Java would throw an ArithmeticException, and the program would stop before printing anything. The precondition comment is what tells the next programmer to make sure friends is never 0.
Vocabulary
| Term | Definition | Example |
|---|---|---|
| comment | Text in a program written for people to read; ignored by the compiler and never run | // points out of 20 |
| commenting out | Turning code into a comment so it does not run, without deleting it | // tickets += 1; |
| single-line comment | A comment from // to the end of that line |
int count = 3; // smoothies |
| block comment | A comment from /* to the next */, over any number of lines |
/* Each row needs 4 packets. */ |
| Javadoc comment | A comment from /** to */ placed above a class or method; used to build API documentation |
/** Returns the number of characters. */ |
| javadoc | The tool that turns Javadoc comments into API documentation pages | Builds the String documentation |
| tag | A word starting with @ in a Javadoc comment; @param describes an input, @return the result |
@return the larger of a and b |
| precondition | What must be true right before a method or code segment runs; the caller must make it true, and the code does not check it | a is not negative, for sqrt |
| postcondition | What is always true right after a method or code segment runs: what it returns, or the state of its object’s attributes | The balance has gone up by amount |
Chapter summary
- Comments are notes written for the original programmer and for other programmers. The compiler ignores them and they never run, so they never change a program’s output; code inside a comment (commented out) does not run either.
//makes a comment that ends at the end of its line./* */makes a block comment that can cover many lines and ends only at*/./** */makes a Javadoc comment. Written above a class or method, it describes it, and the javadoc tool turns these comments into API documentation like the pages forStringandMath. Tags such as@paramand@returndescribe what goes in and what comes out.- A precondition is what must be true before a method or code segment runs. The code does not check it; the user is responsible, and breaking it can cause a wrong result or a crash.
- A postcondition is what is guaranteed to be true afterward, described in terms of the value returned or the values of the object’s attributes.
Review questions
Question 13 · Multiple choice
Which statement is true about all three kinds of Java comments (//, /* */, and /** */)?
- They are all used by the javadoc tool to create API documentation.
- They are all ignored by the compiler and never executed.
- They all end at the end of the line on which they start.
- They are all printed when the program runs, so users can read them.
Check your reasoning
B. Every kind of comment is skipped by the compiler, so none of them run.
- A is wrong: only
/** */comments become API documentation. - C is wrong: only
//ends at the end of its line./* */and/** */end at*/, which may be many lines later. - D is wrong: comments are for people reading the code, not for people running the program. Only print statements produce output.
Reread 1.8.1 Comments Are Notes for People and the table in 1.8.4 Javadoc Comments and API Documentation if you chose differently.
Question 14 · Tracing
What is the exact output of this program?
/**
* Keeps count of the books a student has read.
*/
public class ReadingLog
{
public static void main(String[] args)
{
int books = 2; // read in September
/* books += 4; read in October
books += 1; */
books *= 3; // books -= 1;
// books += 10;
System.out.print("Books: ");
System.out.println(books);
}
}Check your reasoning
Books: 6| Line | What happens | books |
|---|---|---|
| 1–3 | Javadoc comment: skipped | |
| 8 | books is set to 2; the note after // is skipped |
2 |
| 9–10 | A block comment from /* to */: both += lines are skipped |
2 |
| 11 | books *= 3 runs; // books -= 1; is an end-of-line comment |
6 |
| 12 | Commented out | 6 |
| 13–14 | Prints the label, then the value | 6 |
If you got Books: 21, Books: 5, or a total including the 10, you ran one of the commented-out lines. Reread 1.8.2 Single-Line Comments and 1.8.3 Block Comments.
Question 15 · Debugging
This code should record 5 cups of water, then add 3 glasses of 2 cups each, and print 11. It prints 5. Find the error and correct it.
int water = 5; // cups of water so far
/* Each glass holds 2 cups.
The student drinks 3 more glasses.
water += 2 * 3; */
System.out.println(water);Check your reasoning
The error: the block comment opens on line 2 but does not close until the end of line 4, so water += 2 * 3; is inside the comment and never runs.
Corrected code:
int water = 5; // cups of water so far
/* Each glass holds 2 cups.
The student drinks 3 more glasses. */
water += 2 * 3;
System.out.println(water);Moving */ to the end of the note lets water += 2 * 3; run: 2 × 3 is 6, and 5 + 6 is 11, so the code prints 11. The original compiled because the comment did close eventually; it just closed one line too late, which is a logic error. Reread 1.8.3 Block Comments if you did not spot it.
Question 16 · Short answer
A library includes this documentation for a method in an invented Ticket class:
/**
* Works out the total cost of an order of tickets.
* Precondition: quantity is greater than 0, and priceCents is not negative.
* Postcondition: returns quantity times priceCents.
*/
public static int totalCost(int quantity, int priceCents)(a) Who is responsible for making sure quantity is greater than 0? (b) If a program passes 0 for quantity, what does the documentation promise about the result? (c) Which kind of comment is this, and how can you tell?
Check your reasoning
Model answer: (a) The programmer who calls totalCost is responsible. The method is not expected to check its precondition. (b) Nothing. The postcondition is only guaranteed when the precondition was met, so with quantity 0 the documentation makes no promise about what comes back. (c) It is a Javadoc comment, because it starts with /** and sits directly above a method header, so the javadoc tool would put it in the API documentation.
A complete answer must:
- give the job of meeting the precondition to the caller, not the method,
- say that breaking the precondition means the postcondition is no longer promised, and
- identify the comment as Javadoc from its
/**opening.
Reread 1.8.5 Preconditions, 1.8.6 Postconditions, and 1.8.4 Javadoc Comments and API Documentation if your answer differed.
Question 17 · Tracing
The minutes segment from 1.8.6 is run with a value that breaks its precondition. What does it print, and which part of the postcondition is false afterward?
// Precondition: totalMinutes is not negative.
// Postcondition: hours holds the whole hours in totalMinutes,
// and minutes holds the leftover minutes, from 0 to 59.
int totalMinutes = -135;
int hours = totalMinutes / 60;
int minutes = totalMinutes % 60;
System.out.print(hours);
System.out.print(" h ");
System.out.print(minutes);
System.out.println(" min");Check your reasoning
-2 h -15 min| Line | What happens | Value |
|---|---|---|
| 4 | Set the total | -135 |
| 5 | -135 / 60 |
hours is -2 |
| 6 | -135 % 60 |
minutes is -15 |
In Java, an int division of a negative number drops the decimal part, giving -2, and the remainder keeps the sign of the number being divided, giving -15. The postcondition promised leftover minutes from 0 to 59, and -15 is outside that range, so that part is false. That is allowed: the precondition (not negative) was broken, so the postcondition was never promised. The code ran without complaint and printed a strange result. Reread 1.8.5 Preconditions and 1.8.6 Postconditions if your answer differed.
Question 18 · Multiple choice
A programmer writes this segment to split cookies evenly into boxes:
int perBox = cookies / boxes;Which comment is the best precondition to write above it?
// Precondition: perBox holds the number of cookies in each box.// Precondition: boxes is not 0.// Precondition: the code checks that boxes is not 0.// Precondition: perBox is greater than 0.
Check your reasoning
B. A precondition states what must already be true before the code runs. Dividing by zero throws an exception, so boxes must not be 0 when this line runs.
- A is wrong: it describes the result after the line runs, so it is a postcondition, not a precondition.
- C is wrong: the code does no such check. A precondition is a requirement on whoever uses the code, not a promise that the code checks anything.
- D is wrong:
perBoxdoes not have its value until after the line runs, so it cannot be a condition before it. (It could also be 0 with no problem, if there are fewer cookies than boxes.)
Reread 1.8.5 Preconditions and 1.8.6 Postconditions if you chose differently.
Reflection
Check each statement. If the answer is “not yet,” reread the linked subsection.
- I can explain who comments are for and why they never change what a program prints. Reread
- I can tell which part of a line is code and which part is a // comment. Reread
- I can find where a /* */ block comment starts and ends, even in the middle of a line. Reread
- I can explain how /** */ comments become API documentation and read @param and @return. Reread
- I can state a precondition and explain that the caller, not the code, must make it true. Reread
- I can state a postcondition and tell it apart from a precondition. Reread