-
-
Notifications
You must be signed in to change notification settings - Fork 681
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,39 @@ | ||
# Method-Based Approach | ||
|
||
<<<<<<< HEAD | ||
Check failure on line 3 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesHeading style
Check failure on line 3 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesHeadings should be surrounded by blank lines
Check failure on line 3 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesMultiple top-level headings in the same document
|
||
======= | ||
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. | ||
|
||
The main `hey` method determines Bob’s response by delegating each condition to a helper method (`isSilent`, `isYelling`, and `isAsking`), each encapsulating specific logic. | ||
|
||
## Explanation | ||
|
||
This approach simplifies the main method `hey` by breaking down each response condition into helper methods: | ||
|
||
1. **Trimming the Input**: | ||
The `input` is trimmed using the `String` [`trim()`][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. | ||
|
||
2. **Delegating to Helper Methods**: | ||
Each condition is evaluated using the following helper methods: | ||
|
||
- **`isSilent`**: Checks if the trimmed input has no characters. | ||
- **`isYelling`**: Checks if the input is all uppercase and contains at least one alphabetic character, indicating shouting. | ||
- **`isAsking`**: Verifies if the trimmed input ends with a question mark. | ||
|
||
This modular approach keeps each condition encapsulated, enhancing code clarity. | ||
|
||
3. **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 yelling and asking. | ||
- Yelling comes next, requiring its response if not combined with a question. | ||
- Asking (a non-shouted question) is checked afterward. | ||
|
||
This ordering ensures that Bob’s response matches the expected behavior without redundancy. | ||
|
||
## Code structure | ||
|
||
>>>>>>> e67fc434c32715ee323ebc5079ef0497932738f6 | ||
```java | ||
Check failure on line 37 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesFenced code blocks should be surrounded by blank lines
|
||
class Bob { | ||
String hey(String input) { | ||
|
@@ -35,6 +69,7 @@ class Bob { | |
} | ||
``` | ||
|
||
<<<<<<< HEAD | ||
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 | ||
|
@@ -80,4 +115,26 @@ if (isSilent(inputTrimmed)) | |
However, the [Java Coding Conventions][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. | ||
Check failure on line 115 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesReference links and images should use a label that is defined
|
||
|
||
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim() | ||
======= | ||
## Advantages of the Method-Based Approach | ||
Check failure on line 119 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesHeadings should be surrounded by blank lines
|
||
|
||
- **Readability**: Each method is clearly responsible for a specific condition, making the main response logic easy to follow. | ||
- **Maintainability**: Changes to a condition can be confined to its method, minimizing impacts on the rest of the code. | ||
- **Code Reusability**: Helper methods can be reused or adapted easily if new conditions are added in the future. | ||
|
||
## Considerations | ||
|
||
- **Efficiency**: While this approach introduces multiple method calls, it enhances readability significantly, which is often more valuable in non-performance-critical applications. | ||
- **Error Prevention**: This approach avoids redundant code, reducing the risk of maintenance errors. | ||
|
||
## Shortening Condition Checks | ||
|
||
If each `if` statement body is only a single line, braces can be omitted, or the test expression and result could be placed on a single line. However, [Java Coding Conventions][coding-conventions] recommend always using curly braces for error prevention and easier future modifications. | ||
Check failure on line 132 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesReference links and images should use a label that is defined
|
||
|
||
### Alternative: Inline Helper Methods | ||
|
||
For smaller projects, consider implementing helper methods inline or as lambdas, though this might reduce readability. | ||
|
||
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim() | ||
Check failure on line 138 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesLink and image reference definitions should be needed
|
||
>>>>>>> e67fc434c32715ee323ebc5079ef0497932738f6 | ||
[coding-conventions]: https://www.oracle.com/java/technologies/javase/codeconventions-statements.html#449 | ||
Check failure on line 140 in exercises/practice/bob/.approaches/method-based/content.md GitHub Actions / Lint Markdown filesBare URL used
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"introduction": { | ||
"authors": [ | ||
"masiljangajji" | ||
] | ||
}, | ||
"approaches": [ | ||
{ | ||
"uuid": "dee2a79d-3e64-4220-b99f-55667549c12c", | ||
"slug": "fork-join", | ||
"title": "Fork/Join", | ||
"blurb": "Parallel Computation Using Fork/Join", | ||
"authors": [ | ||
"masiljangajji" | ||
] | ||
}, | ||
{ | ||
"uuid": "75e9e93b-4da4-4474-8b6e-3c0cb9b3a9bb", | ||
"slug": "parallel-stream", | ||
"title": "Parallel Stream", | ||
"blurb": "Parallel Computation Using Parallel Stream", | ||
"authors": [ | ||
"masiljangajji" | ||
] | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# `Fork/Join` | ||
|
||
```java | ||
import java.util.Map; | ||
import java.util.List; | ||
import java.util.concurrent.ConcurrentMap; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.ForkJoinPool; | ||
import java.util.concurrent.RecursiveTask; | ||
|
||
class ParallelLetterFrequency { | ||
|
||
List<String> texts; | ||
ConcurrentMap<Character, Integer> letterCount; | ||
|
||
ParallelLetterFrequency(String[] texts) { | ||
this.texts = List.of(texts); | ||
letterCount = new ConcurrentHashMap<>(); | ||
} | ||
|
||
Map<Character, Integer> countLetters() { | ||
if (texts.isEmpty()) { | ||
return letterCount; | ||
} | ||
|
||
ForkJoinPool forkJoinPool = new ForkJoinPool(); | ||
forkJoinPool.invoke(new LetterCountTask(texts, 0, texts.size(), letterCount)); | ||
forkJoinPool.shutdown(); | ||
|
||
return letterCount; | ||
} | ||
|
||
private static class LetterCountTask extends RecursiveTask<Void> { | ||
private static final int THRESHOLD = 10; | ||
private final List<String> texts; | ||
private final int start; | ||
private final int end; | ||
private final ConcurrentMap<Character, Integer> letterCount; | ||
|
||
LetterCountTask(List<String> texts, int start, int end, ConcurrentMap<Character, Integer> letterCount) { | ||
this.texts = texts; | ||
this.start = start; | ||
this.end = end; | ||
this.letterCount = letterCount; | ||
} | ||
|
||
@Override | ||
protected Void compute() { | ||
if (end - start <= THRESHOLD) { | ||
for (int i = start; i < end; i++) { | ||
for (char c : texts.get(i).toLowerCase().toCharArray()) { | ||
if (Character.isAlphabetic(c)) { | ||
letterCount.merge(c, 1, Integer::sum); | ||
} | ||
} | ||
} | ||
} else { | ||
int mid = (start + end) / 2; | ||
LetterCountTask leftTask = new LetterCountTask(texts, start, mid, letterCount); | ||
LetterCountTask rightTask = new LetterCountTask(texts, mid, end, letterCount); | ||
invokeAll(leftTask, rightTask); | ||
} | ||
return null; | ||
} | ||
} | ||
} | ||
``` | ||
|
||
Using [`ConcurrentHashMap`][ConcurrentHashMap] ensures that frequency counting and updates are safely handled in a parallel environment. | ||
|
||
If there are no strings, a validation step prevents unnecessary processing. | ||
|
||
A [`ForkJoinPool`][ForkJoinPool] is then created. | ||
The core of [`ForkJoinPool`][ForkJoinPool] is the Fork/Join mechanism, which divides tasks into smaller units and processes them in parallel. | ||
|
||
`THRESHOLD` is the criterion for task division. | ||
If the range of texts exceeds the `THRESHOLD`, the task is divided into two subtasks, and [`invokeAll(leftTask, rightTask)`][invokeAll] is called to execute both tasks in parallel. | ||
Each subtask in `LetterCountTask` will continue calling `compute()` (via `invokeAll(leftTask, rightTask)`) to divide itself further until the range is smaller than or equal to the `THRESHOLD`. | ||
For tasks that are within the `THRESHOLD`, letter frequency is calculated. | ||
|
||
The [`Character.isAlphabetic`][isAlphabetic] method identifies all characters classified as alphabetic in Unicode, covering characters from various languages like English, Korean, Japanese, Chinese, etc., returning `true`. | ||
Non-alphabetic characters, including numbers, special characters, and spaces, return `false`. | ||
|
||
Additionally, since uppercase and lowercase letters are treated as the same character (e.g., `A` and `a`), each character is converted to lowercase. | ||
|
||
After updating letter frequencies, the final map is returned. | ||
|
||
[ConcurrentHashMap]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html | ||
[ForkJoinPool]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html | ||
[isAlphabetic]: https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html#isAlphabetic-int- | ||
[invokeAll]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
for (int i = start; i < end; i++) { | ||
for (char c : texts.get(i).toLowerCase().toCharArray()) { | ||
if (Character.isAlphabetic(c)) { | ||
letterCount.merge(c, 1, Integer::sum); | ||
} | ||
} | ||
} |