Don't Use Null
The null keyword should never be used in your code. Now that Java has the Optional type, there is simply
no need for it. Whenever you have a method, you should be explicit about whether or not you accept
null , and you generally shouldn't accept it. This will save you from NullPointerException cropping up
in obnoxious places, far from the site of the actual error. This is an especially painful problem when you
start working with streams and lambdas, because the stack trace may not be very useful for you when
you go to debug. The solution is to never accept null and to aggressively check for it, exploding loudly as
soon as it occurs. Some developers are concerned that this is adding overhead to their code and hindering
performance, but that concern is the height of premature optimizations. On the one hand, not guarding
against null can lead your code to break badly, and so it is important to ensure correctness: I can give you
the wrong answer infinitely fast. At the same time, adding in these guards will remove a lot of null from your
code, and so those null checks will become cold branches and Java's highly optimized runtime will make
them effectively costless. So these null checks are both high value and low cost.
Don't Release Zalgo
It's popular wisdom that programmers should learn multiple programming languages. The reasons for this
are numerous, but one is often overlooked: programming languages form ecosystems with different people
and different cultures, and you can often learn things in those cultures that enrich how you think about
programming in general.
incomprehensible horror that seeks to consume and destroy you. Programmers are at risk, because Zalgo
lurks beneath your code, waiting to be released by unwary programmers who write code that is impossible
to reason about. Every programmer of functional code must be vigilant against the threat of Zalgo.
When you are passing around lambdas, it is easy to release Zalgo if you mix synchronous and
asynchronous styles. When your code executes a user's lambda, it needs to be clear about whether
the lambda will execute before the method resolves (“synchronous”), or at some point in the future
(“asynchronous”). You must never mix the two approaches.
Consider, for instance, the following code:
List<Number> numbers = Arrays.asList(1, 2, 3);
numbers.forEach(i -> System.out.println(i));
What will print first in that code, "3 , " or "Done?" If you look up the API for Iterable.forEach , it tells
you that it executes the lambda “until all elements have been processed or an exception is thrown,” which
tells you that it is synchronous. Therefore, you know that "Done" will come before "3 . "
On the other hand, consider this code:
s -> System.out.println(s)
In this case, there is no guarantee about whether "Done" will come before the contents of build.
gradle — the API for the Stream.forEach method explicitly states, “For any given element, the action
may be performed at whatever time and in whatever thread the library choses,” which tells you that it is
It may seem obvious enough at this point to avoid Zalgo, but the path to Zalgo is easy to tread for the