Delet - cywongg/2025 GitHub Wiki
Below is a purely functional version of calculateSentenceScore
that:
- Uses no explicit loops (
for
,while
,do-while
,forEach
, etc.). - Uses no explicit conditionals (
if-else
,switch
, or ternary). - Avoids splitting the stream pipeline or creating temporary variables outside the pipeline.
- Relies on
Optional
and stream operations to provide the necessary “conditional” behaviors.
public static double calculateSentenceScore(Map<String, Double> wordScores, String text) {
return Optional.ofNullable(wordScores)
// First, filter out a null or empty wordScores Map
.filter(w -> !w.isEmpty())
// Next, "flatMap" into an Optional of text
.flatMap(w -> Optional.ofNullable(text)
// Filter out a null or empty text
.filter(t -> !t.isEmpty())
.map(String::toLowerCase)
// Now split into tokens and create a Stream<Double> of scores
.map(t -> Arrays.stream(t.split(" "))
// Filter tokens that are not empty and start with a letter
.filter(token -> !token.isEmpty() && Character.isLetter(token.charAt(0)))
// Convert each token to its associated score using Map::getOrDefault
.mapToDouble(token -> w.getOrDefault(token, 0d))
// Finally, compute the average score (returns OptionalDouble)
.average()
// If the stream was empty (no valid tokens), use 0.0
.orElse(0.0)
)
)
// If wordScores or text was invalid, fall back to 0.0
.orElse(0.0);
}
-
No loops: All iteration happens inside
Arrays.stream(...)
and the Stream methods. -
No
if-else
or switch: We use.filter(...)
calls and.orElse(...)
instead ofif-else
. -
No splitting the stream: The pipeline goes from
Optional.ofNullable(wordScores)
→.flatMap(...)
→.map(...)
→.mapToDouble(...)
. We only have nested calls, but it’s all a single flow. -
No temporary variables outside: We rely on the Stream pipeline and
Optional
transformations; nodouble total = 0;
or similar.
-
Q: How do
.filter(...)
and.orElse(...)
replace conditionals in functional programming?
A: Instead ofif-else
, we use.filter(...)
to keep only items that match a predicate, and.orElse(...)
to provide defaults when anOptional
is empty. -
Q: Why can we not just write
if (text == null) return 0;
in functional style?
A: The requirement prohibits explicit conditionals. Functional style usesOptional.ofNullable(text).filter(...)
or.orElse()
to handle null or missing values. -
Q: How does
.average()
help us avoid having to manually sum and count tokens?
A:.average()
in aDoubleStream
automatically computes the average. If the stream is empty (i.e., no valid tokens), it returns anOptionalDouble.empty()
. We then call.orElse(0.0)
to avoid exceptions or manual checks. -
Q: Is
.orElse(0.0)
considered a conditional statement?
A: No..orElse(...)
is a method call onOptional
orOptionalDouble
, which is allowed in functional style. It provides a fallback value if theOptional
is not present. -
Q: Why use
.flatMap(...)
when nestingOptional
calls?
A:.flatMap(...)
prevents having anOptional<Optional<T>>
. It unpacks the outerOptional
and gives you a nice chain of transformations without manual unwrapping.
By reviewing both the code example and the follow-up Q&A, you can deepen your understanding of how to translate from a loop/conditional-heavy imperative style to a more declarative, functional style using Java Streams and Optional
.