Skip to content

Commit 512d048

Browse files
Bob approaches (exercism#2236)
* Create config.json * Create introduction.md * Create snippet.txt * Update config.json * Update introduction.md * Create snippet.txt * Update introduction.md * Update introduction.md * Create content.md * Create content.md * Update introduction.md * Update exercises/practice/bob/.approaches/if-statements/snippet.txt Co-authored-by: Erik Schierboom <erik_schierboom@hotmail.com> Co-authored-by: Erik Schierboom <erik_schierboom@hotmail.com>
1 parent 1bbd99e commit 512d048

6 files changed

Lines changed: 320 additions & 0 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Answer array
2+
3+
4+
```java
5+
import java.util.function.Predicate;
6+
import java.util.regex.Pattern;
7+
8+
class Bob {
9+
final private static String[] answers = {
10+
"Whatever.",
11+
"Sure.",
12+
"Whoa, chill out!",
13+
"Calm down, I know what I'm doing!"
14+
};
15+
final private static Pattern isAlpha = Pattern.compile("[a-zA-Z]");
16+
final private static Predicate < String > isShout = msg -> isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
17+
18+
public String hey(String message) {
19+
var speech = message.trim();
20+
if (speech.isEmpty()) {
21+
return "Fine. Be that way!";
22+
}
23+
var questioning = speech.endsWith("?") ? 1 : 0;
24+
var shouting = isShout.test(speech) ? 2 : 0;
25+
return answers[questioning + shouting];
26+
}
27+
}
28+
```
29+
30+
In this approach you define an array that contains Bob’s answers, and each condition is given a score.
31+
The correct answer is selected from the array by using the score as the array index.
32+
33+
The `String` [`trim()`][trim] method is applied to the input to eliminate any whitespace at either end of the input.
34+
If the string has no characters left, it returns the response for saying nothing.
35+
36+
```exercism/caution
37+
Note that a `null` `string` would be different from a `String` of all whitespace.
38+
A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it.
39+
```
40+
41+
A [Pattern][pattern] is defined to look for at least one English alphabetic character.
42+
43+
The first half of the `isShout` [Predicate][predicate]
44+
45+
```java
46+
isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
47+
```
48+
49+
is constructed from the `Pattern` [`matcher()`][matcher-method] method and the [`Matcher`][matcher] [`find()`][find] method
50+
to ensure there is at least one letter character in the `String`.
51+
This is because the second half of the condition tests that the uppercased input is the same as the input.
52+
If the input were only `"123"` it would equal itself uppercased, but without letters it would not be a shout.
53+
54+
A question is determined by use of the [`endsWith()`][endswith] method to see if the input ends with a question mark.
55+
56+
The conditions of being a question and being a shout are assigned scores through the use of the [ternary operator][ternary].
57+
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."`.
58+
59+
| isShout | isQuestion | Index | Answer |
60+
| ------- | ---------- | --------- | ------------------------------------- |
61+
| `false` | `false` | 0 + 0 = 0 | `"Whatever."` |
62+
| `false` | `true` | 0 + 1 = 1 | `"Sure."` |
63+
| `true` | `false` | 2 + 0 = 2 | `"Whoa, chill out!"` |
64+
| `true` | `true` | 2 + 1 = 3 | `"Calm down, I know what I'm doing!"` |
65+
66+
67+
## Shortening
68+
69+
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
70+
71+
```java
72+
if (speech.isEmpty()) return "Fine. Be that way!";
73+
```
74+
75+
or the body _could_ be put on a separate line without curly braces
76+
77+
```java
78+
if (speech.isEmpty())
79+
return "Fine. Be that way!";
80+
```
81+
82+
However, the [Java Coding Conventions][coding-conventions] advise to always use curly braces for `if` statements, which helps to avoid errors.
83+
Your team may choose to overrule them at its own risk.
84+
85+
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim()
86+
[pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
87+
[predicate]: https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html
88+
[matcher]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html
89+
[matcher-method]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#matcher-java.lang.CharSequence-
90+
[find]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#find--
91+
[ternary]: https://www.geeksforgeeks.org/java-ternary-operator-with-examples/
92+
[endswith]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#endsWith(java.lang.String)
93+
[coding-conventions]: https://www.oracle.com/java/technologies/javase/codeconventions-statements.html#449
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public String hey(String message) {
2+
var speech = message.trim();
3+
if (speech.isEmpty())
4+
return "Fine. Be that way!";
5+
var questioning = speech.endsWith("?") ? 1 : 0;
6+
var shouting = isShout.test(speech) ? 2 : 0;
7+
return answers[questioning + shouting];
8+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"introduction": {
3+
"authors": ["bobahop"],
4+
"contributors": []
5+
},
6+
"approaches": [
7+
{
8+
"uuid": "323eb230-7f27-4301-88ea-19c39d3eb5b6",
9+
"slug": "if-statements",
10+
"title": "if statements",
11+
"blurb": "Use if statements to return the answer.",
12+
"authors": ["bobahop"]
13+
},
14+
{
15+
"uuid": "11baf0c0-a596-4495-8c25-521c023c3103",
16+
"slug": "answer-array",
17+
"title": "Answer array",
18+
"blurb": "Index into an array to return the answer.",
19+
"authors": ["bobahop"]
20+
}
21+
]
22+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# `if` statements
2+
3+
```java
4+
import java.util.function.Predicate;
5+
import java.util.regex.Pattern;
6+
7+
class Bob {
8+
9+
final private static Pattern isAlpha = Pattern.compile("[a-zA-Z]");
10+
final private static Predicate < String > isShout = msg -> isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
11+
12+
public String hey(String message) {
13+
var speech = message.trim();
14+
if (speech.isEmpty()) {
15+
return "Fine. Be that way!";
16+
}
17+
var questioning = speech.endsWith("?");
18+
var shouting = isShout.test(speech);
19+
if (questioning) {
20+
if (shouting) {
21+
return "Calm down, I know what I'm doing!";
22+
}
23+
return "Sure.";
24+
}
25+
if (shouting) {
26+
return "Whoa, chill out!";
27+
}
28+
return "Whatever.";
29+
}
30+
}
31+
```
32+
33+
In this approach you have a series of `if` statements using the private methods to evaluate the conditions.
34+
As soon as the right condition is found, the correct response is returned.
35+
36+
Note that there are no `else if` or `else` statements.
37+
If an `if` statement can return, then an `else if` or `else` is not needed.
38+
Execution will either return or will continue to the next statement anyway.
39+
40+
The `String` [`trim()`][trim] method is applied to the input to eliminate any whitespace at either end of the input.
41+
If the string has no characters left, it returns the response for saying nothing.
42+
43+
```exercism/caution
44+
Note that a `null` `string` would be different from a `String` of all whitespace.
45+
A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it.
46+
```
47+
48+
A [Pattern][pattern] is defined to look for at least one English alphabetic character.
49+
50+
The first half of the `isShout` [Predicate][predicate]
51+
52+
```java
53+
isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
54+
```
55+
56+
is constructed from the `Pattern` [`matcher()`][matcher-method] method and the [`Matcher`][matcher] [`find()`][find] method
57+
to ensure there is at least one letter character in the `String`.
58+
This is because the second half of the condition tests that the uppercased input is the same as the input.
59+
If the input were only `"123"` it would equal itself uppercased, but without letters it would not be a shout.
60+
61+
A question is determined by use of the [`endsWith()`][endswith] method to see if the input ends with a question mark.
62+
63+
## Shortening
64+
65+
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
66+
67+
```java
68+
if (speech.isEmpty()) return "Fine. Be that way!";
69+
```
70+
71+
or the body _could_ be put on a separate line without curly braces
72+
73+
```java
74+
if (speech.isEmpty())
75+
return "Fine. Be that way!";
76+
```
77+
78+
However, the [Java Coding Conventions][coding-conventions] advise to always use curly braces for `if` statements, which helps to avoid errors.
79+
Your team may choose to overrule them at its own risk.
80+
81+
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim()
82+
[pattern]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
83+
[predicate]: https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html
84+
[matcher]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html
85+
[matcher-method]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#matcher-java.lang.CharSequence-
86+
[find]: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#find--
87+
[endswith]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#endsWith(java.lang.String)
88+
[coding-conventions]: https://www.oracle.com/java/technologies/javase/codeconventions-statements.html#449
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
if (questioning) {
2+
if (shouting)
3+
return "Calm down, I know what I'm doing!";
4+
return "Sure.";
5+
}
6+
if (shouting)
7+
return "Whoa, chill out!";
8+
return "Whatever.";
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Introduction
2+
3+
There are various idiomatic approaches to solve Bob.
4+
A basic approach can use a series of `if` statements to test the conditions.
5+
An array can contain answers from which the right response is selected by an index calculated from scores given to the conditions.
6+
7+
## General guidance
8+
9+
Regardless of the approach used, some things you could look out for include
10+
11+
- If the input is trimmed, [`trim()`][trim] only once.
12+
13+
- Use the [`endsWith()`][endswith] `String` method instead of checking the last character by index for `?`.
14+
15+
- Don't copy/paste the logic for determining a shout and for determing a question into determing a shouted question.
16+
Combine the two determinations instead of copying them.
17+
Not duplicating the code will keep the code [DRY][dry].
18+
19+
- Perhaps consider making `questioning` and `shouting` values set once instead of functions that are possibly called twice.
20+
21+
- If an `if` statement can return, then an `else if` or `else` is not needed.
22+
Execution will either return or will continue to the next statement anyway.
23+
24+
- If the body of an `if` statement is only one line, curly braces aren't needed.
25+
Some teams may still require them in their style guidelines, though.
26+
27+
## Approach: `if` statements
28+
29+
```java
30+
import java.util.function.Predicate;
31+
import java.util.regex.Pattern;
32+
33+
class Bob {
34+
35+
final private static Pattern isAlpha = Pattern.compile("[a-zA-Z]");
36+
final private static Predicate < String > isShout = msg -> isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
37+
38+
public String hey(String message) {
39+
var speech = message.trim();
40+
if (speech.isEmpty()) {
41+
return "Fine. Be that way!";
42+
}
43+
var questioning = speech.endsWith("?");
44+
var shouting = isShout.test(speech);
45+
if (questioning) {
46+
if (shouting) {
47+
return "Calm down, I know what I'm doing!";
48+
}
49+
return "Sure.";
50+
}
51+
if (shouting) {
52+
return "Whoa, chill out!";
53+
}
54+
return "Whatever.";
55+
}
56+
}
57+
```
58+
59+
For more information, check the [`if` statements approach][approach-if].
60+
61+
## Approach: answer array
62+
63+
```java
64+
import java.util.function.Predicate;
65+
import java.util.regex.Pattern;
66+
67+
class Bob {
68+
final private static String[] answers = {
69+
"Whatever.",
70+
"Sure.",
71+
"Whoa, chill out!",
72+
"Calm down, I know what I'm doing!"
73+
};
74+
final private static Pattern isAlpha = Pattern.compile("[a-zA-Z]");
75+
final private static Predicate < String > isShout = msg -> isAlpha.matcher(msg).find() && msg == msg.toUpperCase();
76+
77+
public String hey(String message) {
78+
var speech = message.trim();
79+
if (speech.isEmpty()) {
80+
return "Fine. Be that way!";
81+
}
82+
var questioning = speech.endsWith("?") ? 1 : 0;
83+
var shouting = isShout.test(speech) ? 2 : 0;
84+
return answers[questioning + shouting];
85+
}
86+
}
87+
```
88+
89+
For more information, check the [Answer array approach][approach-answer-array].
90+
91+
## Which approach to use?
92+
93+
Since benchmarking with the [Java Microbenchmark Harness][jmh] is currently outside the scope of this document,
94+
the choice between `if` statements and answers array can be made by perceived readability.
95+
96+
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim()
97+
[endswith]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#endsWith(java.lang.String)
98+
[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
99+
[approach-if]: https://exercism.org/tracks/java/exercises/bob/approaches/if-statements
100+
[approach-answer-array]: https://exercism.org/tracks/java/exercises/bob/approaches/answer-array
101+
[jmh]: https://github.com/openjdk/jmh

0 commit comments

Comments
 (0)