Home Commenting inside methods
Method header vs inline comments
There are three different kinds of comments you can write: class header comments, method header comments, and inline comments (which are comments that go inside your method).
It's important to note that what we expect from inline comments are somewhat different from what we expect from class/method header comments.
Inline comments
Use inline comments to describe complex pieces of code – to explain your implementation. You may also use inline comment to help delineate distinct "sections" of your method. Do not over-comment and leave excessive amounts of inline comments.
Unlike class header comments, which summarizes your entire program, and method header comments, which explains how to use your method and what users can expect from it, inline comments are meant to explain how your method works.
You should assume that whoever is reading your inline comments is not only interested in how to use your method, but also in understanding how it works (possibly so they can modify it later). Like before, you should assume whoever is reading your inline comments is a competent programmer.
They will already know a fair amount about Java, but will need help understanding why you made certain decisions, or understanding what a particularly complex piece of logic does.
Your reader will NOT need help understanding how your code works on a line-by-line basis. In particular, do not comment like this:
// Returns how many of a given character is in the provided string, // ignoring case. public int countCharacters(String str, char letter) { // converts the letter to lowercase char lower = Character.toLowerCase(letter); // converts the letter to uppercase char upper = Character.toUpperCase(letter); // start counting from 0 int count = 0; // start looping from i = 0 up to the end of the string, incrementing // once each time for (int i = 0; i < str.length(); i++) { // get the i-th character char ch = str.charAt(i); // compare the current char against the upper and lowercase // strings to see they match, ignoring case if (ch == lower || ch == upper) { // increment the counter count++; } } // return the count return count; }
This is terrible commenting because the comments add zero value and annoy the reader. All the comments do is simply parrot and repeat what the code does. An experienced programmer does not need a comment to explain how a for loop or a return statement works.
A better-commented version would look like this:
// Returns how many of a given character is in the provided string, // ignoring case. public int countCharacters(String str, char letter) { // Stores lowercase/uppercase versions of the char to // avoid recomputing it in the loop char lower = Character.toLowerCase(letter); char upper = Character.toUpperCase(letter); // Uses cumulative sum to find matches int count = 0; for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); if (ch == lower || ch == upper) { count++; } } return count; }
Now, the comments are much less intrusive, and adds some additional value. We now understand a little better why we implemented the code in the way we did, and clearly delineates the code into two separate sections.
Here is another example of bad inline commenting, which uses a CSE 143 example:
// Randomly shuffles a list of numbers in place public static void shuffle(List<Integer> numbers) { // Creates a new random object Random random = new Random(); // Iterates through the list of numbers for (int currIndex = 0; currIndex < numbers.size(); currIndex++) { // Picks a random number between 0 to (numbers.size() - currIndex) // offset by the currIndex int randIndex = random.nextInt(numbers.size() - currIndex) + currIndex; // Grabs two cards from the currIndex and randIndex String cardA = numbers.get(currIndex); String cardB = numbers.get(randIndex); // Sets the currIndex and randIndex numbers.set(currIndex, cardB); numbers.set(randIndex, cardA); } }
The inline comments here add zero value – all they do is parrot what the code is doing. A better version would look like this:
// Randomly shuffles a list of numbers in place public static void shuffle(List<Integer> numbers) { // Implements the Fisher-Yates shuffle algorithm // http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle Random random = new Random(); for (int currIndex = 0; currIndex < numbers.size(); currIndex++) { // Selects a random element beyond this one (selecting literally // any element is proven to result in an in an imperfect, not // fully random shuffle). int randIndex = random.nextInt(numbers.size() - currIndex) + currIndex; // Swaps the randomly selected card with the current one String itemA = numbers.get(currIndex); String itemB = numbers.get(randIndex); numbers.set(currIndex, itemB); numbers.set(randIndex, itemA); } }
This is much better, since the inline comments now links to the specific algorithm we're using in case the reader wants to learn more, and we're explaining peculiarities, such as why the code to select a random number is so convoluted.
Note that we also don't comment on things like "we're creating a Random object" or "we're looping over the list" – your reader already knows Java, and does not need help to understand these things. However, we do briefly note that the four lines of code at the end are being used to swap two elements. This is the sort of thing which may not be immediately obvious, so is worth briefly mentioning.
However, an even better way to "comment" this method would be to break up the code into smaller methods, like so:
// Randomly shuffles a list of numbers in place public static void shuffle(List<Integer> numbers) { // Implements the Fisher-Yates shuffle algorithm // http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle Random random = new Random(); for (int currIndex = 0; currIndex < numbers.size(); currIndex++) { // Selects a random element beyond this one (selecting literally // any element is proven to result in an in an imperfect, not // fully random shuffle). int randIndex = randomInt(random, currIndex, numbers.size()); swap(numbers, currIndex, randIndex); } } // Gets a random int between min (inclusive) and max (exclusive), using // the given random object. public static int randomInt(Random random, int min, int max) { return random.nextInt(max - min) + min; } // Swaps the items at the two indices in the given list public static void swap(List<Integer> numbers, int indexA, int indexB) { String itemA = numbers.get(indexA); String itemB = numbers.get(indexB); numbers.set(indexA, itemB); numbers.set(indexB, itemA); }
Now, our shuffle
method is much more clear, since we've moved each distinct subtask into a separate helper with a clear and readable method name. We still keep some of our inline comments, but we're able to convert some of the others into method header comments.
Formatting inline comments
There are no hard-and-fast rules for formatting inline comments. However, you should generally place inline comments on the line directly before the thing you are commenting.
There is no "correct" way to format an inline comment – anything reasonable will be acceptable.
However, you should most likely avoid writing inline comments that go on the same line as the thing you are commenting. For example, you will typically want to avoid writing code that looks like this:
// Returns how many of a given character is in the provided string, // ignoring case. public int countCharacters(String str, char letter) { char lower = Character.toLowerCase(letter); // Stores lowercase/uppercase versions char upper = Character.toUpperCase(letter); // of the char to avoid recomputing // it in the loop int count = 0; for (int i = 0; i < str.length(); i++) { // Uses cumulative sum to find matches char ch = str.charAt(i); if (ch == lower || ch == upper) { count++; } } return count; }
There are several reasons for this. The main reason is that this will most likely end up violating the 80-characters-per-line limit that we have. You'll find it hard to fit in both your code and your comments on a single line.
The other reason is that you want to be able to freely edit and tweak your inline comments. When you need to share space with existing content, you'll often end up becoming distracted as you constantly format and reformat your text.