- Forbid using null;
- Use only immutable objects, add "final" modifier to everything;
- Swap methods by static functions with the the original "this" as the first argument, e.g. "foo.bar()" turns into "bar(foo)";
- Add a lot of features to the type system;
- Remove type annotations, i.e. "Foo bar(Foo self)" turns into "bar(self)";
- Remove useless parens, i.e. "bar(foo)" turns into "bar foo";
- Add call-by-need evaluation;
- Done, you have Haskell.
One, using null references is a recognized bad practice, see "Null References: The Billion Dollar Mistake." Java 8 already provides the Optional type to stop using nulls.
Two, immutable objects are a win strategy, see posts by Hirondelle Systems, IBM, Yegor, and others.
Three, as you only have immutable objects, there is no reason to use methods instead of static functions, considering you maintain polymorphism (not quite the case for Java, but for the sake of this rant, consider as if it has this feature).
Four, improve the type system. The type system used by Java language misses a lot of features. If you don't feel it, just consider this as an added bonus. When you start using the type system features in your favor, you end up with much better code.
Five, imagine the Java compiler could infer the type of the arguments, so you don't need to type them everywhere. You still have the same static typing language, you just don't need to write the types. Shorter code means less liability to haunt you.
Six, why all those parens? Just drop them. Less code to write, hurray!
Seven, call-by-need just makes a lot of things easier (also makes a lot of things harder), but I really think it is a winner when you talk about productivity. When coding, I feel it a lot easier to express things in terms of values instead of steps (mathematicians have been doing this since long before computers). Expressing things in terms of values in a universe without call-by-need will result in a lot of useless computations, so call-by-need is a must.
Eight, done! This is Haskell. No functors, monads, arrows, categories or lists needed.
Why this post? Well, I don't know. It just occurred to me that if you really go into following good coding practices in Java (e.g. avoid null, use immutable objects), you will eventually feel familiar with functional code. Add some more things to the mix, and you end up with Haskell. I think people feel a bit scared at first contact with Haskell (and family) because of the academic and mathematical atmosphere it has, but in the end it is just a lot of good practices that you are kind of required to comply with.