Visit the bob exercise on Exercism to read the full instructions and download the exercise files.
Dig Deeper
method-based if statements
Method-Based if statements
class Bob {
String hey(String input) {
var inputTrimmed = input.trim();
if (isSilent(inputTrimmed)) {
return "Fine. Be that way!";
}
if (isShouting(inputTrimmed) && isQuestioning(inputTrimmed)) {
return "Calm down, I know what I'm doing!";
}
if (isShouting(inputTrimmed)) {
return "Whoa, chill out!";
}
if (isQuestioning(inputTrimmed)) {
return "Sure.";
}
return "Whatever.";
}
private boolean isShouting(String input) {
return input.chars()
.anyMatch(Character::isLetter) &&
input.chars()
.filter(Character::isLetter)
.allMatch(Character::isUpperCase);
}
private boolean isQuestioning(String input) {
return input.endsWith("?");
}
private boolean isSilent(String input) {
return input.length() == 0;
}
}
In this approach, the different conditions for Bob’s responses are separated into dedicated private methods within the Bob class.
This method-based approach improves readability and modularity by organizing each condition check into its own method, making the main response method easier to understand and maintain.
Explanation
This approach simplifies the main method hey by breaking down each response condition into helper methods:
The input is trimmed using the String trim() method to remove any leading or trailing whitespace.
This helps to accurately detect if the input is empty and should prompt a "Fine. Be that way!" response.
Note that a `null` `string` would be different from a `String` of all whitespace.
A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it.
Delegating to Helper Methods
Each condition is evaluated using the following helper methods:
isSilent: Checks if the trimmed input has no characters.
isShouting: Checks if the input is all uppercase and contains at least one alphabetic character, indicating shouting.
isQuestioning: Verifies if the trimmed input ends with a question mark.
This modular approach keeps each condition encapsulated, enhancing code clarity.
Order of Checks
The order of checks within hey is important:
- Silence is evaluated first, as it requires an immediate response.
- Shouted questions take precedence over individual checks for shouting and questioning.
- Shouting comes next, requiring its response if not combined with a question.
- Questioning (a non-shouted question) is checked afterward.
This ordering ensures that Bob’s response matches the expected behavior without redundancy.
Shortening
When the body of an if statement is a single line, both the test expression and the body could be put on the same line, like so:
if (isSilent(inputTrimmed)) return "Fine. Be that way!";
or the body could be put on a separate line without curly braces:
if (isSilent(inputTrimmed))
return "Fine. Be that way!";
However, the Java Coding Conventions advise always using curly braces for if statements, which helps to avoid errors.
Your team may choose to overrule them at its own risk.
variable-based if statements
Variable-Based if statements
import java.util.function.Predicate;
import java.util.regex.Pattern;
class Bob {
final private static Pattern isAlpha = Pattern.compile("[a-zA-Z]");
final private static Predicate < String > isShout = msg -> isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
public String hey(String message) {
var speech = message.trim();
if (speech.isEmpty()) {
return "Fine. Be that way!";
}
var questioning = speech.endsWith("?");
var shouting = isShout.test(speech);
if (questioning) {
if (shouting) {
return "Calm down, I know what I'm doing!";
}
return "Sure.";
}
if (shouting) {
return "Whoa, chill out!";
}
return "Whatever.";
}
}
In this approach you have a series of if statements using the private methods to evaluate the conditions.
As soon as the right condition is found, the correct response is returned.
Note that there are no else if or else statements.
If an if statement can return, then an else if or else is not needed.
Execution will either return or will continue to the next statement anyway.
The String trim() method is applied to the input to eliminate any whitespace at either end of the input.
If the string has no characters left, it returns the response for saying nothing.
Note that a `null` `string` would be different from a `String` of all whitespace.
A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it.
A Pattern is defined to look for at least one English alphabetic character.
The first half of the isShout Predicate
isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
is constructed from the Pattern matcher() method and the Matcher find() method
to ensure there is at least one letter character in the String.
This is because the second half of the condition tests that the uppercased input is the same as the input.
If the input were only "123" it would equal itself uppercased, but without letters it would not be a shout.
A question is determined by use of the endsWith() method to see if the input ends with a question mark.
Shortening
When the body of an if statement is a single line, both the test expression and the body could be put on the same line, like so
if (speech.isEmpty()) return "Fine. Be that way!";
or the body could be put on a separate line without curly braces
if (speech.isEmpty())
return "Fine. Be that way!";
However, the Java Coding Conventions advise to always use curly braces for if statements, which helps to avoid errors.
Your team may choose to overrule them at its own risk.
Answer array
Answer array
import java.util.function.Predicate;
import java.util.regex.Pattern;
class Bob {
final private static String[] answers = {
"Whatever.",
"Sure.",
"Whoa, chill out!",
"Calm down, I know what I'm doing!"
};
final private static Pattern isAlpha = Pattern.compile("[a-zA-Z]");
final private static Predicate < String > isShout = msg -> isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
public String hey(String message) {
var speech = message.trim();
if (speech.isEmpty()) {
return "Fine. Be that way!";
}
var questioning = speech.endsWith("?") ? 1 : 0;
var shouting = isShout.test(speech) ? 2 : 0;
return answers[questioning + shouting];
}
}
In this approach you define an array that contains Bob’s answers, and each condition is given a score.
The correct answer is selected from the array by using the score as the array index.
The String trim() method is applied to the input to eliminate any whitespace at either end of the input.
If the string has no characters left, it returns the response for saying nothing.
Note that a `null` `string` would be different from a `String` of all whitespace.
A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it.
A Pattern is defined to look for at least one English alphabetic character.
The first half of the isShout Predicate
isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
is constructed from the Pattern matcher() method and the Matcher find() method
to ensure there is at least one letter character in the String.
This is because the second half of the condition tests that the uppercased input is the same as the input.
If the input were only "123" it would equal itself uppercased, but without letters it would not be a shout.
A question is determined by use of the endsWith() method to see if the input ends with a question mark.
The conditions of being a question and being a shout are assigned scores through the use of the ternary operator.
For example, giving a question a score of 1 would use an index of 1 to get the element from the answers array, which is "Sure.".
| isShout | isQuestion | Index | Answer |
|---|
false | false | 0 + 0 = 0 | "Whatever." |
false | true | 0 + 1 = 1 | "Sure." |
true | false | 2 + 0 = 2 | "Whoa, chill out!" |
true | true | 2 + 1 = 3 | "Calm down, I know what I'm doing!" |
Shortening
When the body of an if statement is a single line, both the test expression and the body could be put on the same line, like so
if (speech.isEmpty()) return "Fine. Be that way!";
or the body could be put on a separate line without curly braces
if (speech.isEmpty())
return "Fine. Be that way!";
However, the Java Coding Conventions advise to always use curly braces for if statements, which helps to avoid errors.
Your team may choose to overrule them at its own risk.
Source: Exercism java/bob