Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[jdt-dev] A matter of style: loops vs. streams and - gasp - braces

Hi team,

(The following debate is as old as the invention of braces, but Java 8 gives a new twist to it, so please bear with me for minute as I turn your world upside down).


In a current gerrit I found the following comment:

> Also add missing braces on loops as necessary.

I doubt that any of those braces where "necessary", otherwise those would have been bugs, no?


I'd like to actively promote a braceless style for simple loops and ifs for the following reason:


Since Java 8 and the introduction of streams we have two main options for writing many things involving iteration over a collection. As a trivial first-level criterion to choose among the two, everybody uses "conciseness" of the code.

Take this pattern:
   for (X x : coll) {
       if (isGood(x)) {
            process(x);
       }
   }
vs.
   coll.stream().filter(x -> isGood(x)).forEach(x -> process(x));

Everybody can "clearly see" that the latter variant is "better".


NO, it is not. We simply cheat by choosing a more condensed layout.
In terms of conciseness, this is the winner:
   for (X x: coll) if (isGood(x)) process(x);

Do you see, how the initial example compared apples and oranges??


The stream() variant even has its own drawback: it will severely backfire should you ever need to debug that code section.


So my proposal is: Let's for a compromise explicitly admit this style:
    for (X x : coll)
        if (isGood(x))
            process(x);

IMHO this is the sweet spot to balance conciseness, readability and debuggability.

For slightly more involved cases I made a habit of using braces for the outer-most structure, thus delineating a meaningful chunk of code, s.t. like
    for (X parent : coll) {
        if (isGood(parent))
            for (Y child : parent.getChildren())
                 process(child);
    }

Remember, that we provide quick assists for converting to block, should we need to add more statements to some body.


If you don't like any of this, we should for fairness also forbid braceless lambdas and enforce line breaks around the lambda body:
   coll.stream().filter(x -> {
       return isGood(x);
   }).forEach(x -> {
       process(x);
   });
This style is suitable for comparison with the old, imperative style (but ugly, right?)


No, I'm not against lambdas (just a bit wary about debuggability), but visual comparison between options should be fair :)


Put differently: a loop structure that can be written without braces has the same mental clarity as a well structure stream-pipeline. Let's please not penalize such style by unnecessary verbosity.

best,
Stephan


Back to the top