Say we have to iterate over a list of complex object, and "group" them in a map where a key is (for example) a date and the relative value is a list of complex objects that share that same date.
I'm a sucker for elegant and readable code, in my way though.
Map<ZonedDateTime, List<ComplexObject >> map = new HashMap<>();
for(var complexObject : complexObjectsList)
if (map.containsKey(complexObject.getZonedDateTime()))
map.get(complexObject.getZonedDateTime()).add(complexObject);
else
map.put(complexObject.getZonedDateTime(), new ArrayList<ComplexObject>().add(complexObject));
As you can see, for and if/else constructs do not need {} nor additional lines.
The problem here, is:
in the case of a date not present yet in the map, I would love to add it in a one-liner, also creating the list with the first element inside. However, since ArrayList's ".add" method does not return a List (which is what the map value expects) and, instead, returns a boolean, I cannot do so.
I'm forced to declare a new List a few lines higher, add the element in another line, and then pass it. Consequentially, I will have to use "{}", multiple lines and a variable declaration that is not going to be used anymore.
Is there a way to achieve this? Thanks a lot!
However the question is about having a one line where you can create a list, add an element to it, and return the list.
Depends on the kind of list you want:
List.of(element)
.Arrays.asList(element)
.new ArrayList<>(/* one of the above suggestions */)
, e.g. new ArrayList<>(List.of(element))
.Many other ways also exist, e.g. Stream.of(element).collect(toList())
, many other list implementations exist, e.g. ImmutableList.of(element)
with Guava.
Another way of approaching the problem outlined in the question, which is basically creating a new list and adding an element to it would be:
map.computeIfAbsent(complexObject.getZonedDateTime(), k -> new ArrayList<>()).add(complexObject);
I challenge your preference towards omitting {}
and doing things in one-liners: neither of these are good general approaches:
{}
are useful visual cues, which help people reading the code to identify the start and end of blocks. They also guard against some kinds of mistakes when the code is modified in the future, for example intending to add something in the block, but not in fact doing so, because the braces are omitted.
Note that some style guides, e.g. Google's Java style guide require the use of optional braces, to improve readability of the code.
One-liners can, in certain circumstances, be the best way to write things; in many circumstances they can make things much harder to express.
I would probably choose List.of(element)
or Array.asList(element)
if I needed an unmodifiable list - that's nice and easy, clear. But once you start using new ArrayList<>(List.of(element))
, that starts getting quite a bit harder to read, because there's a lot of burden imposed by the API - why the diamond brackets, why create a list and then create another list? You can hide some of this burden by extracting a method; but then, isn't a method more verbose than a variable?
So, you have to declare a variable if you write something as a not-one-liner. Does that matter? It doesn't make the code slower; it may make it easier to read, because you're given the opportunity to provide type information (unless you've used var
) and a name to indicate the purpose.
Ultimately, you should optimize for readable code. Far more time is (or should be) spent reading code than writing code. The poor person who has to read your code next might be you - it's easy to forget what you meant when you return to the code a week, a month, a year later.
Be kind, take the time to help future you.