Favor Format Over Concatenation

 class​ Mission {
 
  Logbook logbook;
  LocalDate start;
 
 void​ update(String author, String message) {
  LocalDate today = LocalDate.now();
  String month = String.valueOf(today.getMonthValue());
  String formattedMonth = month.length() < 2 ? ​"0"​ + month : month;
» String entry = author.toUpperCase() + ​": ["​ + formattedMonth + ​"-"​ +
  today.getDayOfMonth() + ​"-"​ + today.getYear() + ​"](Day "​ +
  (ChronoUnit.DAYS.between(start, today) + 1) + ​")> "​ +
  message + System.lineSeparator();
  logbook.write(entry);
  }
 }

Understandability and readability don’t just matter in your code—they’re also important for the output your code produces.

If you have to build large strings, you can use format strings to make them more readable.

Here, we’re revisiting the log book we already mentioned in Avoid NullPointerException in Conditionals. The problem is that it’s quite hard to see what the output will actually look like. There are multiple String variables, some of them using Java’s in-line notation.

The code isn’t really complex. There’s no deep nesting, no conditional branching, and even the names of variables and methods are meaningful. Despite all this, it’s comparably hard to read. The number of plusses, quotes, and spaces obfuscates the actual processing going on (humans are generally better at understanding words in a natural language than combinations of symbols). This makes the code harder to read and increases the chance of making mistakes when writing it.

Additionally, performing in-line computations like summing int values adds to the confusion, as the + operator has different semantics when it comes to Strings and ints. Using it with different semantics in the very same line makes it even harder to maintain an overview of what’s happening. Don’t do this!

We can trim this down a lot. Take a look at the following code:

 class​ Mission {
 
  Logbook logbook;
  LocalDate start;
 
 void​ update(String author, String message) {
»final​ LocalDate today = LocalDate.now();
» String entry = String.format(​"%S: [%tm-%<te-%<tY](Day %d)> %s%n"​,
  author, today,
  ChronoUnit.DAYS.between(start, today) + 1, message);
  logbook.write(entry);
  }
 }

Format strings help to overcome this issue, and they’re available in practically any contemporary programming language—not just in Java. The key lies in separating the layout of a String (how it is printed) from the data (what is being printed). Format strings define a coherent String in a single block using special placeholder characters, marked by %.

Format methods, such as String.format(), or System.out.printf(), accept data using placeholder characters in the order in which they’re listed after the String.

In our example here, %S converts an object into an upper case String using its toString() method. The parameter author will be processed this way. The date variable today serves as data for %tm, the month, %te the day of the month, and %tY, the year. The additional character < makes sure that all three placeholders read the same input data. %d processes a decimal value and %s accepts a String. Finally, %n is the symbol for a line break.

The actual data is listed in a nicely formatted fashion after the String layout. This makes it a little more acceptable to perform in-line computations, as we can use one line for each parameter. Point taken that it’s not so easy to see what "%S: [%tm-%<te-%<tY](Day %d)> %s%n" will print in the end. But it’s a well-documented standard[23] and actually a good alternative to the cluttered code from the problem—for large strings we recommend StringTemplate,[24] a powerful template engine.

Consider documenting the formatted string with a few examples similar to Document Using Examples so that the next developer reading your code doesn’t have to look up how %S or any other special formatting syntax behaves to know what the resulting string will be.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.176.194