Why Functional Programming in Java is Dangerous

In my day job I work with a lot of very smart developers who graduated from top university CS programs such as MIT, CMU, and Chicago. They cut their teeth on languages like Haskell, Scheme, and Lisp. They find functional programming to be a natural, intuitive, beautiful, and efficient style of programming. They’re only wrong about one of those.

The problem is that my colleagues and I are not writing code in Haskell, Scheme, Lisp, Clojure, Scala, or even Ruby or Python. We are writing code in Java, and in Java functional programming is dangerously inefficient. Every few months I find myself debugging a production problem that ultimately traces back to a misuse of functional ideas and algorithms in a language and more importantly a virtual machine that just wasn’t built for this style of programming.

Recently Bob Martin came up with a really good example that shows why. Here’s a bit of Clojure (a real functional language) that returns a list of the first 25 integers:

(take 25 (squares-of (integers)))

This code runs, and it runs reasonably quickly. The output is:

(1 4 9 16 25 36 49 64 … 576 625)

Now suppose we want to reproduce this in Java. If we write Java the way Gosling et al intended Java to be written, then the code is simple, fast, and obvious:

for (int i=1; i<=25; i++)
    System.out.println(i*i);
}

But now suppose we do it functionally! In particular suppose we naively reproduce the Clojure style above:

import java.util.ArrayList;
import java.util.List;

public class Take25 {

    public static void main(String[] args) {    
        for (Object o : take(25, squaresOf(integers()))) {
            System.out.println(o);
        }
    }
    
    public static List<?> take(int n, List<?> list) {
        return list.subList(0, n);
    }
    
    public static List<Integer> squaresOf(List<Integer> list) {
        List<Integer> result = new ArrayList<Integer>();
        for (Integer number : list) {
            result.add(number.intValue() * number.intValue());
        }
        return result;
    }
    
    public static List<Integer> integers() {
        List<Integer> result = new ArrayList<Integer>();
        for (int i = 1; i <= Integer.MAX_VALUE; i++) {
            result.add(i);
        }
        return result;
    }
    
}

Try to run that. Go ahead. I dare you....OK, recovered from the heap dump yet?

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:2760)
	at java.util.Arrays.copyOf(Arrays.java:2734)
	at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
	at java.util.ArrayList.add(ArrayList.java:351)
	at Take25.integers(Take25.java:30)
	at Take25.main(Take25.java:9)

How did Clojure handle a function that returns every single int, while Java crapped out? The answer is that Clojure, like pretty much all true functional languages (and unlike Java) does lazy evaluation. It doesn't compute values it doesn't use. And it can get away with this because Clojure, unlike Java, is really and truly functional. It can assume that variables aren't mutated, that the order of evaluation doesn't matter, and thus that it can perform optimizations that a Java compiler can't. And this is why functional programming in Java is dangerous. Because Java isn't a true functional language, the JIT and javac can't optimize functional constructs as aggressively and efficiently as they can in a real functional language. Standard functional operations like returning infinite lists are death for a Java program. That's why functional programming in Java is dangerous.

You may object that I've set up a straw man here. OK, you can't return a list of all the integers (or even all the ints) in Java; but surely no one would really do that. Let's look at a more realistic approach. Here again I use recursion to compute the squares rather than a loop:

public class Squares {
    
    public static void main(String args[]) {
        squareAndPrint(1, Integer.parseInt(args[0]));
    }
    
    public static void squareAndPrint(int n, int max) {
        System.out.println(n * n);
        if (max > n) {
            squareAndPrint(n + 1, max);
        }
    }
    
}

That will run. But now suppose I don't want the first 25 squares but the first 25,000:

Ooops. Stack overflow. This is why in XOM I was very careful to use loops rather than recursion, even in places where recursion was much clearer. Otherwise a carefully configured XML document could have caused a XOM-using program to dump core. Avoiding arbitrarily large recursion in non-functional languages like Java and C isn't just a performance requirement, it's a security requirement too!

Now before the flames begin, let me be clear about what I am not saying. I am not saying that functional programming is a bad idea. I am not saying that functional programming is inefficient. I actually love functional programming. Like my colleagues I find find functional programming to be a natural, intuitive, and beautiful style of programming but only when it's done in a language that was designed for it from the beginning like Haskell. Functional idioms in Java are performance bugs waiting to bite you.

70 Responses to “Why Functional Programming in Java is Dangerous”

  1. Hugo Sereno Ferreira Says:

    I think your first and last paragraph are contradictory. You can’t say that “… they find functional programming to be a natural, intuitive, beautiful, and efficient style of programming. They’re only wrong about one of those…” and then “… I am not saying that functional programming is inefficient”.

    I do agree that FP is not a mere idiom, or *style* [1] and I do also agree that the JVM really sucks when it comes to support FP out-of-the-box — though, through clever trickery, one can come very far, i.e., Scala and Clojure. I think what you are trying to claim is that you shouldn’t mix apples with oranges. Java was never meant to natively support FP. So, please, fix that first paragraph to something like “people should know their stuff” and then you’ll have my support.

    [1] Things such as “I do FP in Javascript” or “Ruby is multi-paradigm” is marketing BS. Wanna know the greatest, oldest and most flexible multi-paradigm language (according to those ideas) ? Assembly… There you go ;-)

  2. Lemontree75 Says:

    Do you really think that somebody would really write this?

    public static List integers() {
    List result = new ArrayList();
    for (int i = 1; i <= Integer.MAX_VALUE; i++) {
    result.add(i);
    }
    return result;
    }

    :O

    I think this example is a little bit extreme even for somebody who comes from a functional background.

  3. Juan Manuel Says:

    But the example is misleading. The code in Clojure uses the sequence library and this library is more similar to iterators than to lists, so the equivalent would be to create iterators, not lists.

  4. Mike V. Girkin Says:

    The example you’ve gave, it is a very good example of tool misusage, and example of using patterns outside the environment they are designed for.

  5. Mark Perry Says:

    Of course, you are right. These naive examples demonstrate that Java does not support laziness or tail call optimisation (TCO). But lazy streams are easy to create and reuse, see Functional Java (http://functionaljava.org/) for examples. TCO is a bigger problem. You could eshew FP and use mutable state and imperactive style programming. But now you have turned one problem into two. This is worse, much worse, than just doing FP in Java. The biggest turnoff for new FP people in Java is the verbose syntax, obviously alleviated by Java 8.

  6. Nicolas Says:

    Don’t see the point honestly.

    You say the JIT and JVM where not made for functional programming. Then how can you think Scala and Clojure are acceptable? They run on the JVM and benefit of the JIT for performance boost. Ruby? JRuby run on JVM and perform better than standard Ruby.

    You give the example of lazy lists in clojure. Do you know this is a just an API? Standard JRE stream allow you to read a file lasily. If you just need to read the first line of the file, the whole 1GB file will not be loaded into memory. If it is done for streams in java, it could be done for lists.

    There after you give the example of recursion. Do you know that clojure share the same flows as java for this? You have to be explicit for your tail recursion optimisation with recur. Otherwise you’ll see the stack explode.

    You haven’t shown any good reason to not use functional idioms in java. You didn’t even mention basic functional programming support in upcoming Java 8.

  7. Sylvain Says:

    Maybe you should learn java before writing such post…

  8. Maxim Says:

    Totally agree with Nicolas.
    Very bias assumptions.

  9. Jason Smith Says:

    If you want to do this in Java, override AbstractList to a calculated value, not a stored one, and set the size to Integer.MAX…

    Now you can take the first 25 of a List that has 2 billion (calculated) items in it, square them, and print the results.

    Just as Clojure forces you to think about things differently, if you want to bring the same techniques into Java, you have to think differently.

  10. aleksandar Says:

    Ivy League education seems to be really paying off. I teach at ITT Tech and have had some brainiacs come through but no one in their right mind would write code like this! Wow! Bookmarking this for when I get asked “does which university you go to really matter for CS education?!”

  11. Steve Says:

    A kind response and helping the author understand are much more productive than a flameroast. I realize that’s not the nature of many Internet denizens, but it’s worth mentioning.

  12. Scott Parker Says:

    That is one heck of a straw man there! =) The truth is that you can blow the stack with that technique in nearly any language. If I write my own integers method in Clojure following your technique I (unsurprisingly) get an OOM as well:

    (defn integers []
    (range Integer/MAX_VALUE)) ;=> OutOfMemoryError

    Regarding recursion, again Clojure has the same problem with your technique. Again, the Clojure version:

    (defn square-and-print [n max]
    (println (* n n)
    (when (< n max)
    (square-and-print (inc n) max)))

    Again, this blows the stack too.

    I think ultimately you may be stuck in the same trap I fell into when I first started learning functional programming. It was very hard for me to conceive of how to apply those concepts to my bread and butter language (which was then C#). The trick is realizing that functional programming is a *technique*, not just a language paradigm. When you write code in a functional style, then you can achieve some impressive results in nearly any modern language. If you aren't thinking functionally though, it doesn't matter if you're working in Java, Scala, or even Common Lisp – you'll run into these kinds of roadblocks and will be left frustrated and confused.

    I encourage you to keep pushing though. The Clojure source code is surprisingly readable – look into tricks like loop/recur as well as lazily evaluated methods like map, and you'll see techniques that you *can* apply in your own Java code. Clojure, after all, is on the JVM and so doesn't have access to any tricks that you as a Java developer do not.

    Good luck!

  13. Dave Copeland Says:

    You are missing the point – lazy lists can be implemented in Java using java.util.Iterator, and it’s quite simple. Here’s a walkthrough of how you’d do it: http://www.naildrivin5.com/blog/2013/01/20/bad-programming-in-java-is-dangerous.html

  14. Jacque Le Roux Says:

    I vaguely remember having learnt how to transform recursions in iteration. It was in the late 80′, so it’s only a vague remembering. At this time there was mostly C and Lisp (I used APL). But I guess the argument still stands…

  15. Eldc Says:

    I’m just gonna rephrase your post so that its flaws seem more apparent: “functional programming in Java is dangerous because some people would assume that Java optimizes recursive tail calls and has lazy lists”.

  16. RB Says:

    You have to be kidding me. You should have your programming license taking away for that little gem of a loop…guessing you don’t have much stick time with Java, eh?

  17. Ian Clarke Says:

    How did Clojure handle a function that returns every single int, while Java crapped out?

    Because no competent programmer would implement this the way you implemented it in Java.

    They would have created an Iterable implementation that returned successive numbers, lazily. Then they would have used Google Guava’s Iterables class, specifically the *filter* and *limit* methods.

    Of course, this is very verbose in Java 7, but Java 8 will solve that problem.

  18. Paul Says:

    lol Obviously, using an ArrayList to implement an infinite list, you are going to run out of memory. An infinite list can be implemented in java, especially since the List interface doesn’t have any space requirements. You really should really read up on how infinite lists are implemented, even in other languages, to understand how they can be implemented in java. You can also check out apache commons library:

    http://commons.apache.org/collections/apidocs/org/apache/commons/collections/list/package-summary.html

    It provides a lot of lazy list evaluations(although it doesn’t provide an infinite list). You can see how they are implemented to help understand how an infinite list could be implemented in a lazy manner.

  19. Elliotte Rusty Harold Says:

    Looks like I touched a nerve. I think a few folks need to go back and reread what I actually wrote. If you think I was actually suggesting someone should write code like this, you didn’t get the point.

    It’s true that you could redo this with problem iterators or a special subclass of List, and avoid some (not all) of the problems of this approach. In effect you’d be hand rolling the lazy evaluation that a true functional language gives you for free.

    But unless you’re really, really careful, and put in a lot more effort, then functional style code in Java is going to perform like a dog, if it works at all. The problem is that the language, the libraries, the compiler, the VM and the JIT are all not expecting any of this, and are not designed for this. When you change languages, even one that runs on the VM such as Clojure, you’ve changed at the very least the language, the compiler, and the libraries. If you change to a non-JVM language such as Haskell, then you’ve optimized every component for this style of programming. The tools are now working with you instead of against you. You no longer have to think about stack overflows from excessive recursion because tail call elimination takes care of that. You don’t worry about when to use iterators and when to use lists, or whether objects might be changing in separate threads. Sublists become trivial because there’s no chance a backing list will change out from under them.

    But you get none of that in Java. So one of two things happens, either you reimplement the natural boundaries of functional programming in every class you write, protections you should get for free; or you ignore them and watch your system fail in production every few weeks because of functional assumptions that weren’t satisfied.

  20. Ricky Clarkson Says:

    I’d call these correctness problems rather than performance problems, as you hit actual errors. A performance problem you might get in Java from attempting functional programming would be longer running time for doing a list.map(function) instead of a foreach loop. A performance problem you might get from _not_ doing functional programming in Java would be excessive copying of collections in case the collection could get modified elsewhere.

    You can get stack overflows in Haskell, and there are techniques such as trampolines that are applicable in both Haskell and Java when you start to hit stack limits.

  21. Giacomo Stelluti Scala Says:

    Agree with Nicolas,
    one thing is the Java language and one thing is the JVM.

    If a compiler of a functional language that targets JVM can emit efficient bytecode, the only thing to avoid is try programming in Java as you would do in Clojure.

    But for what masochistic reason you should do it?
    I do not think that people that come from functional background is not able to write correct imperative code.

  22. Alexander Kober Says:

    “Looks like I touched a nerve. I think a few folks need to go back and reread what I actually wrote. If you think I was actually suggesting someone should write code like this, you didn’t get the point.”

    If you think that is what the comments are criticizing, you didn’t get the point. The point is that you constructed an utterly absurd example to prove a point that would, at the very least, deserve a longer discussion.

    As for touching nerves: When a lot of people disagree with you, don’t think ‘Hey, i uncovered an inconvenient truth’. Think ‘Maybe what I said wasn’t as smart as I thought’. One wrong-way driver, not a hundred.

    “The problem is that the language, the libraries, the compiler, the VM and the JIT are all not expecting any of this, and are not designed for this.”

    Scala works surprisingly well, using the same VM and JIT. The language and the libraries will start covering the basics of functional programming starting with Java 8, which is no where near release. So your point is…?

    “You no longer have to think about stack overflows from excessive recursion because tail call elimination takes care of that”

    First of all, you can eliminate tail calls on the JVM just as well, again proven by scala. Secondly, not all recursive calls are tail recursive, and no language will take away your responsibility to program accordingly.

  23. Pawe? Wielgus Says:

    Totally disagree. Firstly – lazy evaluations is possible in java – in fact in any language i know of and choosing not to use it where it’s essential is simply your problem. Secondly functional programming is not only about lazy evaluation, there are more ideas inside – why didn’t you show more of them? Why didn’t you show that applying a function to a list is a bad idea in java? Sadly it’s another post that states that missusage is bad – wow what a discovery!

  24. flying sheep Says:

    sorry, man, i don’t think you’re qualified to write about this if the simple concept of iterators and interfaces implementing those eludes you, or you fail to realize that functional “lists” are not different from those. i didn’t implement a map function because that (along with lambdas, which are crucial for the painlessnes of maps, filters and foldings) will come in java 8, where functional programming is really being introduced into the language.

    following comes some code which solves the remaining part elegantly. please try to learn something that broadens your perspective before trying this again, ok? just take a week off and seriously try to implement something in haskell, ruby, or whatnot.

    http://paste.kde.org/651818/

  25. Ian Clarke Says:

    Looks like I touched a nerve.

    Alternate explanation: Your article was dumb.

    If, despite virtually everyone telling you the exact same thing, your takeaway is “all of these people are upset because they just can’t handle my truth”, then I really pity your co-workers.

  26. Elliotte Rusty Harold Says:

    It’s a fair point that functional does not imply lazy. I suppose Haskell has spoiled me there.

    The bottom line remains the same though: you can’t use an idiom you’ve learned in one programming language in another language based on a completely different paradigm without a lot of pain and care. Perhaps Java 8 will make functional programming feasible in Java, though I have my doubts. But today functional idioms just don’t work in Java. At best they produce convoluted, hard to follow code that performs no better than non-functional equivalents. At worst, they cause production failures. And most of the time they just slow everything down.

    And to all those who claim that this is a straw man, and no one would actually do anything like this in practice, I wish you were right. :-(

  27. Osvaldo Doederlein Says:

    The problem is not in the “low-level” features like tail recursion or lazy evaluation (the latter is not by any means a standard feature of functional languages, btw). Absence of such things is annoying, but they can generally be worked around even if requiring verbose idioms or special libraries that support high-level idioms such as lazy lists.

    The problem is the higher-level idioms. When in a proper functional language, you write something like: (foldr + 0 ‘(1 2 3 4)), any compiler worth its salt will optimize this all way down to the constant 10. Even in a less-trivial example where this code is inside a function and the values to add are parameters, the optimizer should generate the equivalent of a simple for loop. Even more, this optimization should still work if you have that kind of code as part of a higher-order function, e.g. (define (adder values) foldr + 0 values) => the compiler should still produce a for loop for applications like (adder ‘(a b c)), and a compile-time constant when all arguments are constants or can be computed at compile-time like (adder ‘(1 2 3 (+ 2 2))).

    These optimizations are viable because, in a functional language, data types like linked lists ad operations like foldr are primitive to the language; the compiler has full understanding of their semantics. When the foldr expression is compiled, it becomes a simple AST subtree that, if being compiled to native code, is trivial to transform to a loop or constant. (Not to mention other optimizations like replacing linked lists by arrays, specializing the function for integer*->integer if that’s the dominant case, unboxing the integers etc.).

    Library-based implementations of these idioms can work and avoid the most egregious problems like stack overflows, but they cannot hope to benefit from special optimization. If you write code equivalent to the foldr example in Java, you end up using some kind of Collection object (or Iterator/Iterable), and libraries like Guava or equivalent, and the end result is that the bytecode required by that simple foldr expression is a nightmare: Consider that with an ArrayList$Itr, you need 106 bytecodes for each element (= sum of bytecode size for hasNext(), next() and the private checkForComodification()). Now add the code to build the Collection/Iterator, the libraries that perform the foldr, etc. and you’re easy in the high hundreds or low thousands of bytecodes, so the compiler IR for a trivial foldr-like expression is an impenetrable mess for the optimizer; even with full inlining, poor HotSpot is hopeless to pattern-match all this code and say, “hmmm all this crap is just a foldr over such and such values”. So the JIT will produce the best code possible to create an iterable object, then iterate it, then apply some inner class (or soon a lambda) to each element etc.; but it will still do all these steps, mimicking a completely stupid functional-language interpreter that calls runtime helpers to build lists or perform a foldr operation.

    Alternative languages for the JVM such as Clojure can perform these semantic optimizations at their own IR level, emitting bytecode that’s pre-optimized: with lists replaced by primitive arrays, integers unboxed, foldr’s converted to for loops etc. But that takes a full-blown optimizer, complete with aggressive inlining. The result would then be a very low-level bytecode that would depend on the JVM only for low-level optimizations such as register allocation etc. I’m not sure if any of the functional languages-for-JVM have such sophistication. For one thing, the necessity of efficient integration with Java often requires that these languages use java.util-compatible collections and many other constraints like that.

  28. Christian Kohlschütter Says:

    The following line of code is valid Java. It is functional and does what you want (full code below).

    print(new Take(25, new SquaresOf(new Integers())));

    You sir, are dangerous, not Java.

    // the code is also here, and easier to read: http://pastebin.com/YEd2VMsh

    package functional;

    import java.util.Iterator;

    public class FunctionalJava {

    public static void main(String[] args) {
    print(new Take(25, new SquaresOf(new Integers())));
    }

    static abstract class Sequence implements Iterator,
    Iterable {
    private boolean hasNext = true;
    protected Iterator in;

    protected Sequence() {
    this(null);
    }

    protected Sequence(final Iterator in) {
    this.in = in;
    }

    @Override
    public Iterator iterator() {
    return this;
    }

    @Override
    public boolean hasNext() {
    return hasNext && (in == null || in.hasNext());
    }
    @Override

    public abstract T next();

    @Override
    public void remove() {
    throw new UnsupportedOperationException();
    }

    protected void endOfSequence() {
    hasNext = false;
    }
    }

    static final class Integers extends Sequence {
    private int value;

    Integers() {
    this(1);
    }

    Integers(final int startValue) {
    this.value = startValue;
    }

    @Override
    public Integer next() {
    return value++;
    }
    }

    static final class Take extends Sequence {
    private int limit;

    Take(final int limit, final Iterator in) {
    super(in);
    this.limit = limit;
    }

    @Override
    public Integer next() {
    try {
    return in.next();
    } finally {
    if (–limit == 0) {
    endOfSequence();
    }
    }
    }
    }

    static final class SquaresOf extends Sequence {
    SquaresOf(final Iterator in) {
    super(in);
    }

    @Override
    public Integer next() {
    final int v = in.next();
    return v * v;
    }
    }

    static void print(final Iterator it) {
    System.out.print(‘(‘);
    if (it.hasNext()) {
    System.out.print(it.next());
    while (it.hasNext()) {
    System.out.print(‘ ‘);
    System.out.print(it.next());
    }
    }
    System.out.println(‘)’);
    }
    }

  29. Holger Oehm Says:

    There, I fixed it for you:


    package clojure;

    import java.util.Iterator;

    public class Take25 {

    public static void main(final String[] args) {
    for (final Object o : take(25, squaresOf(integers()))) {
    System.out.println(o);
    }
    }

    public static Iterable take(final int max, final Iterable from) {
    return new TakeFromIterable(max, from);
    }

    @SuppressWarnings("hiding")
    public static class TakeFromIterable implements Iterable {
    public static class TakeIterator implements Iterator {
    private final int max;
    private final Iterator from;
    int count = 0;

    public TakeIterator(final int max, final Iterable from) {
    this.max = max;
    this.from = from.iterator();
    }

    @Override
    public boolean hasNext() {
    return count < max && from.hasNext();
    }

    @Override
    public TT next() {
    count++;
    return from.next();
    }

    @Override
    public void remove() {
    throw new UnsupportedOperationException();
    }
    }

    private final int max;
    private final Iterable from;

    public TakeFromIterable(final int max, final Iterable from) {
    this.max = max;
    this.from = from;
    }

    @Override
    public Iterator iterator() {
    return new TakeIterator(max, from);
    }
    }

    @SuppressWarnings("hiding")
    public static class SquaringIterable implements Iterable {
    public static class SquaringIterator implements Iterator {
    private final Iterator from;

    public SquaringIterator(final Iterable from) {
    this.from = from.iterator();
    }

    @Override
    public boolean hasNext() {
    return from.hasNext();
    }

    @Override
    public Integer next() {
    final int value = from.next().intValue();
    return Integer.valueOf(value * value);
    }

    @Override
    public void remove() {
    throw new UnsupportedOperationException();
    }
    }

    private final Iterable from;

    public SquaringIterable(final Iterable from) {
    this.from = from;
    }

    @Override
    public Iterator iterator() {
    return new SquaringIterator(from);
    }
    }

    public static Iterable squaresOf(final Iterable from) {
    return new SquaringIterable(from);
    }

    public static class IntegerIterable implements Iterable {

    public class IntegerIterator implements Iterator {
    int i;

    @Override
    public boolean hasNext() {
    return i != Integer.MAX_VALUE;
    }

    @Override
    public Integer next() {
    return Integer.valueOf(i++);
    }

    @Override
    public void remove() {
    throw new UnsupportedOperationException();
    }
    }

    @Override
    public Iterator iterator() {
    return new IntegerIterator();
    }

    }

    public static Iterable integers() {
    return new IntegerIterable();
    }
    }

    Sorry for the formatting, and the angle brackets with the generics are gone… Sigh!

  30. Elliotte Rusty Harold Says:

    Sorry about the angle brackets. I’m afraid WordPress strips out raw < unless you escape it.

  31. Craaazy Says:

    tough crowd!

  32. robert annett Says:

    I think I agree with your general argument. I would say that if you want to program in a functional way (and there are many problem domains where it is very natural to do so) then USE A FUNCTIONAL LANGUAGE. It’ll work much better than trying to make Java work this way.

    Java was designed, and works very well, as a procedural object-orientated language.

    Most of my development is done in Java as I find that most applications that businesses want us to write involve a lot of imperative actions and conditional testing (if a customer chooses X then do these 20 actions but if they choose Y then do these 10 etc). Your problem domain may be different but choose the right tool for the job!

  33. Andreas Neubacher Says:

    I fully agree with you – and I think Osvaldo Doederlein expanded on your key arguments quite well.

    One cannot simply transplant language paradigms and expect high performance. We know that all major languages are equally powerful independent of their basic paradigms (i.e. you can implement an interpreter for any language in any other language), so all of those flame posts arguing “but it can be done!” are obviously true but obviously ignore the performance aspect – both for code development and for execution.

  34. Morten Says:

    If you check out “State of Collections” http://cr.openjdk.java.net/~briangoetz/lambda/sotc3.html that describes how Lambda expressions are supported by Java 8, you’ll find that lazy evaluation, and parallel execution is built-in to the functional components. See the “The role of laziness” section for details.

    It is essentially built by each function wrapping the input’s iterable, returning another iterable. Quite elegant!

  35. Nicolas Says:

    You already use functional concept in standard java. It just comes with more boilerplate. Listener pattern is defining an interface because it misses higher order functions. Command pattern is the same. Factories are just functions returning functions.

    Comparable, Runable and all theses kind of interfaces are just “poor” ways to pass code/function in parameters to other functions.

    Like Iterator give you a way to process infinite streams.

    In the example of the first 25 squares, there is no need for an infinite list of integer. Keep It Stupid Simple.

    So in java you would write:
    List list = new ArrayList();
    for (int i = 1; i<26; i++) {
    list.add(i*i);
    }

    And in clojure you would write:

    (map #(* %1 %1) (range 26))

    If you do more than that, you are doing too much for what you need. Adding infinite range and take in this precise case give you nothing.

    But this doesn't mean that java doesn't really need functional concepts from time to time, and that there is no benefit of using them. Swing use listeners everywhere. Concurrent framework use the concept of task and runables…

    That's why really grasping the concepts is important. Because really at start there is no functional programming or structured programming or whatever. There is assembly language. and even at lower level transistors. We add usefull abstractions and build up language to ease theses abstractions. Assembly is designed for compiler performance. Higher level languages give you OOP, functional programming, you name it.

    But you can do with the added boilerplate. OOP is surprisely easy in C. Functionnal programming can work well in java. And so on. So obviously you'll not use theses concepts for thing java can do "eleguantly" already. You inline your square function, because there so much boiler plate to define it explicitely.

    But what if you want to notify all objects interrested in some state that this state has been updated? You don't know what code theses objects want to run. So you define an interface:

    interface EventListener {
    void onEvent();
    }

    You define a method addListener that take a EventListener instance that anybody can implement so it can be later notified.

    listeners.add(listener);

    When you need to notify listener you call the onEvent method on registered listeners:

    for(EventListener listener : listeners) {
    listener.onEvent();
    }

    You just used some functional programming concept. Passing a function as a parameter to another function so it can be called later. Why ? Because this time this was a good solution. It is not possible to bypass the function call because well you don't know what method will be called.

  36. Alastair Says:

    I really didn’t think this article was as controversial as some of the commentors seem to. The author seems to be implying that, while it’s tempting to use functional language idioms in Java, you have to be careful because it can really kill you if you don’t understand what’s happening. And it’s important to realise how much work the languages – Clojure etc. – have done to make it possible.

    Seems pretty reasonable to me?

  37. Talbott Crowell Says:

    I think many of the comments have a point. But Holger Oehm’s comment included code for the implementation written in Java that is almost 100 lines of code that is not as readable as Elliotte’s Clojure example that was only one line of code. Brevity is another benefit of using a functional first language for functional programming. More lines of code introduce the potential for more bugs.

  38. Jazir Malik Says:

    Umm so this is FP 101 – Lazy vs Strict evaluation. There are strict functional languages too, by the way. This has nothing to do with Java as such.

  39. hey joe Says:

    Well said Osvaldo Doederlein.
    Many people criticized, but didn’t show functional code replacement that works. “use this …”, “use that …”. “Talk is cheap, show me the code” …
    The title don’t say to you don’t use functional programming in Java, it just says that you need to care if you do use.
    Thanks for the code Holger Oehm. And the code supports the author’s arguments: “More lines of code introduce the potential for more bugs.” Talbott Crowell
    http://www.youtube.com/watch?v=kE3FAY-NOiU

  40. Dan Howard Says:

    OMG the number of functional apologists is so hilarious.

  41. Zardoz Says:

    Why not hire deveopers from the community college instead?

  42. Misja Says:

    I think the writer has a good point.
    Sure, it is possible to write good functional code in Java. It is also possible to write nice class hierarchies in Javascript, or concurrent applications in C.
    All of that is possible, but you have to be very careful, because the language doesn’t give you much support.

    Some answers, like Holger Oehm’s, are actually nice illustrations of what kind of trouble you have to go through in Java to write something that is really basic in any truly functional language.

  43. Fadi El-Eter Says:

    I’m not sure whether it’s a fact that clojure is a functional language, and whether it’s a fact that Java is not.

    I don’t think that there are “functional languages” and “imperative languages”. I think it all has to do with the style.

    The problem that you’re describing is inherent to Java and to its memory management, and has nothing to do with the style of programming. You may have similar (negative) results if you try another example that is not what you label as “functional programming”.

  44. Thor Åge Eldby Says:

    Download jdk8 from http://jdk8.java.net/lambda/ and run this example to see how it’s done:

    IntStream squares = Streams.iterate(1, n -> n + 1).map((Integer n) -> n * n);
    squares.limit(25000).forEach(n -> System.out.print(n + “, “));

  45. Christian Kohlschütter Says:

    I usually do not comment on posts that bash Java or any other language. But I think this post is very dangerous to any novice.
    You essentially claim that Java is unable/not easily usable to compute the square roots for 25,000 integers, especially in a row without crashing or demanding huge amounts of memory, or at least not in the functional way that you have in mind.

    This is factually wrong.

    The following line is perfectly legal Java code, and it does what you expect. (full class code below).
    print(new Take(25, new SquaresOf(new Integers())));

    This pretty much is the same as
    (take 25 (squares-of (integers)))

    wouldn’t you agree?

    /**
    * Reply to http://cafe.elharo.com/programming/java-programming/why-functional-programming-in-java-is-dangerous/
    * Source: http://pastebin.com/YEd2VMsh
    *
    * @author Christian Kohlschütter
    */
    package functional;

    import java.util.Iterator;

    public class FunctionalJava {

    public static void main(String[] args) {
    print(new Take(25, new SquaresOf(new Integers())));
    }

    static abstract class Sequence implements Iterator,
    Iterable {
    private boolean hasNext = true;
    protected Iterator in;

    protected Sequence() {
    this(null);
    }

    protected Sequence(final Iterator in) {
    this.in = in;
    }

    @Override
    public Iterator iterator() {
    return this;
    }

    @Override
    public boolean hasNext() {
    return hasNext && (in == null || in.hasNext());
    }

    @Override
    public abstract T next();

    @Override
    public void remove() {
    throw new UnsupportedOperationException();
    }

    protected void endOfSequence() {
    hasNext = false;
    }
    }

    static final class Integers extends Sequence {
    private int value;

    Integers() {
    this(1);
    }

    Integers(final int startValue) {
    this.value = startValue;
    }

    @Override
    public Integer next() {
    return value++;
    }
    }

    static final class Take extends Sequence {
    private int limit;

    Take(final int limit, final Iterator in) {
    super(in);
    this.limit = limit;
    }

    @Override
    public Integer next() {
    try {
    return in.next();
    } finally {
    if (–limit == 0) {
    endOfSequence();
    }
    }
    }

    }

    static final class SquaresOf extends Sequence {
    SquaresOf(final Iterator in) {
    super(in);
    }

    @Override
    public Integer next() {
    final int v = in.next();
    return v * v;
    }
    }

    static void print(final Iterator it) {
    System.out.print(‘(‘);
    if (it.hasNext()) {
    System.out.print(it.next());
    while (it.hasNext()) {
    System.out.print(‘ ‘);
    System.out.print(it.next());
    }
    }
    System.out.println(‘)’);
    }
    }

  46. Robert J Saulnier Says:

    Someone better tell Oracle that functional programming in Java is dangerous because they’re coming out with Java SE 8 this year with support for lambdas.

    Do as the God of Thunder mentioned in the comments above. Download jdk8 and play with it.

    This post would almost make sense in 2010 when lambdas in Java was a scary idea (for some), but now we have an implementation to play with.

    Like all our moms told us when we were young, try it before saying you don’t like it.

  47. Javin Paul Says:

    I come across here from another post which says what is wrong about it, I mean first question is why some one would write code like that in Java?

  48. Thomas Broyer Says:

    With Guava:


    take(25, squaresOf(integers());

    Iterable<Integer> take(int max, Iterable<Integer> it) {
      return Iterables.limit(it, 25);
    }

    Iterable<Integer> squaresOf(Iterable<Integer> it) {
      return Iterables.transform(it, new Function<Integer, Integer>() {
        @Override public Integer apply(Integer input) {
          assert input != null;
          return input * input;
        }
      });
    }

    Iterable<Integer> integers() {
      return ContiguousSet.create(Range.greaterThan(0), DiscreteDomain.integers());
    }

    or using a FluentIterable:

    FluentIterable
      .from(ContiguousSet.create(Range.greaterThan(0), DiscreteDomain.integers()))
      .transform(new Function<Integer, Integer>() {
        @Override public Integer apply(Integer input) {
          assert input != null;
          return input * input;
        }
      })
      .limit(25);

  49. Trav Says:

    Here are two libraries that will help you write function code in java.

    http://functionaljava.org/

    http://code.google.com/p/functionaljava/

  50. Why Functional Programming in Java is NOT Dangerous | Yesterday I was wrong Says:

    [...] This is a quick post in response to Elliotte Rusty Harold article titled Why Functional Programming in Java is Dangerous. [...]

  51. Rainer Joswig Says:

    > The answer is that Clojure, like pretty much all true functional languages (and unlike Java) does lazy evaluation.

    Clojure does not do ‘lazy evaluation’. Clojure uses strict evaluation, like Lisp, Scheme, SML, OCAML, Erlang, …

    Clojure supports lazy lists. As a data structure – not in evaluation.

    See also http://en.wikipedia.org/wiki/No_true_Scotsman

  52. jujuju Says:

    Shity article
    do you know Iterator ?

  53. Marcel Valdez Says:

    Functional programming in Java is as dangerous as Parallel and Concurrent programming is in Java.

    Both will tend to be hard to understand and have hidden bugs. But that doesn’t mean that it is *always* a bad idea. And both will require careful implementation from the programmer.

    Just as it is a bad idea to unnecessarily use Parallel & Concurrent programming in Java; it is also a bad idea to unnecessarily use functional programming in Java.

    I think this is the point of this post. But you wrote the title as if it was a single universal truth. This reminds me of the ‘[XXX] considered harmful’ articles.

  54. carlok Says:

    For F’s (Frank Umberto Clark Kennedy’s) sake, those saying that “Java 8 will solve this”: haven’t you noticed the pattern ? Java 6 will fix ___, Java 7 will fix ___, Java 8 will fix ___, Java N will fix ___, Java N+1 will fix ___ …..

    In the meantime, you wasted YEARS programming in (and defending) an UNFIXABLE BRAINDEAD PARODY OF A LANGUAGE/RUNTIME/ECOSYSTEM, whilst you might have saved yourselves the troubles and used a sane one.

    Of what use is that JVM can be fast in microbenchmarks when you kill that advantage with layers upon layers of needles abstractions and wrappers and libraries that allow you to do ___ when this can be done in a few lines in a sane language ?

    In the end a LARGE applications written in Ruby/Python/Tcl/$whatever$ can be faster then Java ones (and more flexible / maintainable) because you don’t need shitloads of useless boilerplate nor tons of XML, there are no pointless hoops to jump through, just plain solution which even slower runtimes can execute faster than JVM will execute your mammoth blobs.

    ALSO:

    All idiots crying “This is not how you would do this in Java, … yada yada”: it seems to me that this was the point of the post, which you somehow missed. But missing the point is perhaps to be expected from average [Java] code monkey.

  55. MeMySelfAndI Says:

    @OP: Please do not use straw-men arguments, those are ONLY reserved for people trying to push (shiny new feature) into Java.
    Otherwise I agree with those writing that if you want functional programming, please go use a functional language and stop trying to screw up our Java. It is not perfect and I bet that other cool language you were using did everything sooo much better. If it was that great, why not stay with it?

  56. Sequências Infinitas em Scala e Java « Mente de Iniciante Says:

    [...] Recentemente, o polêmico Uncle Bob tem escrito sobre como utilizar conceito de Programação Funcional em Java e tem recebido diversas críticas. [...]

  57. diego Says:

    Venkat Subramaniam solution -> http://blog.agiledeveloper.com/2013/01/functional-programming-in-java-is-quite.html

  58. FFFFFF Says:

    “Functional idioms in Java are performance bugs waiting to bite you. ”

    Nope.

    - You can always compromise and use loops instead of tail recursion, and still have mostly “functional” java code. If you do this there is no “performance bugs”
    - Functional Java (http://functionaljava.org/) has no problem with recursion
    - If you actually need recursion (i.e. the function cannot be written tail-recursively) the most natural way is to use the stack instead of making an explicit stack. Turn up the stack size.

  59. Semiografo Says:

    I wonder why functional programming is considered more elegant than other paradigms. The right question is: more elegant where? For traversing graphs? For japanese people or anyone else who read from right to the left?

    Sometimes I think functional programmers are pleased by the fact that only them can understand their code. Functional code produce much less source code than procedural’s for doing some complex scientific algorithm. In fact, functional code almost mimics mathematical notation. On the other hand, procedural is more algorithmic in the sense that you can organize your solution as an ordered sequence of tasks – and not a reverse order or a fixed-point trick making every stuff anonymous (the fewer the identifiers the better for functionalists).

    That said, I love Javascript, the convergence between the functional and procedural worlds. You can do anonymous recursions with something like a Y combinator or even making something more legible like encapsulating named recursive functions inside another (outer) function which holds static parameters in relation to the inner function.

  60. EricH Says:

    Clojure, Scala, Haskell, et al, would all also crap out if you write code that forces them to store all positive integers in a list. That’s not what they’re doing. The example you cite uses method which creates a list of numbers in a range. Being lazy has nothing to do with it. You could extract the list to a concrete immutable and be fine. You create a list of all integers, and then (would without OOM exception) *use* the first 25 of them. Functional is a style. Java can be used to write purely functional code… it’s just painfully verbose.

    Guava is one such library that adds a number of functional pattern support, including lazy evaluation of transformations of collections. With a bit of finagling, one could implement them from scratch though. (for some reason the forum is eating my indents…)


    public List nameList(List people) {
    return Lists.transform(people, new Function() {
    public String apply(Person person) {
    return person.getName();
    }
    });
    }

    Whereas e.g. scala has a lot of support for functional idioms, largely due to first class functions and convenient shorthand:


    def nameList(people: List[Person]) = people.map(_.name)

    Same method, less headaches. :)

    As for why the java std lib doesn’t have a Range class, I have no idea. This is a simple way to create one:

    http://stackoverflow.com/a/6828887/1057157

  61. Bret Says:

    I don’t think most of the commenters can read, or else they are choosing to grind another axe off this article.

    The author writes: “Every few months I find myself debugging a production problem that ultimately traces back to a misuse of functional ideas and algorithms in a language and more importantly a virtual machine that just wasn’t built for this style of programming.”

    That means he DOES see these sort of mistakes being made by professional programmers, and he’s writing about it for that reason. All the comments along the lines of “no one does that” are obviously not correct. The professional coders he works with DO, and that’s what he’s writing about, and why he’s writing about it.

    He does provide a contrived simplifiled example to illustrate what he’s writing about. Probably to make it quite clear. He doesn’t provide actual code written by one of his colleages – probably becuase it’s copyright by the company, and he can’t, and perhaps because he doesn’t want to single out one of his colleagues for the level of derision evident in the responses to this article.

    But as he clearly stated, he does see this sort of thing in professional code, and so it’s quite legitimate for him to piont it out and discuss it.

    In the comments I read quite a lot of “I don’t code like that!”. That’s good, I’m glad you don’t. But as he clearly states, some people do, and the article is written for them. For people who do write their code like he’s illustrating, this is a useful article – this may help show them what they obviously don’t know yet.

    For those of you who know better already, he has clearly not directed his comments at your code, and many of the responses come across to me as either poor reading comprehension, or perhaps evidence of insecurity. He didn’t write that you do these things – he wrote that some of his colleages do.

  62. Ben Gillard Says:

    Basically agree with OP, although he has phrased it too absolutely in places I think. I partly agree with Christian Kohlschütter’s criticism in that respect – a novice programmer or casual reader might get the wrong message if they don’t read the fine print.

    OP says (or implies) that it can be “dangerous” to _naively_ bring functional assumptions, patterns and idioms to Java which is by design, by paradigm, by mindset an imperative environment. (By environment I mean the JVM, the language, most libraries, dev tools, and the intent of its designers) With that, I agree.

    Even Clojure and Scala, which are designed from the beginning to be functional languages, have to make some compromises and incur some awkwardness or verbosity (“recur” for example) because in the end they run on the JVM which is designed for imperative rather than functional programming. (From wikipedia: “Limitations in Java bytecode complicate tail call optimization on the JVM”). Comments from Java fans that “functional programming is coming in Java 8″, or that the JVM might be getting a TCO enhancement, miss the wider point, I think.

    Osvaldo Doederlein made some excellent additional (perhaps stronger and more general) points, imnsho, about performance and optimisation. (Recall OP’s original gripe was poor performance rather than outright stack overflow or heap exhaustion.)

    I’d like to add one other point which is nothing to do with code performance. Each language has a “way”. Rubyists talk of “the Ruby way”, for example. That is, to solve a particular kind of problem or implement a particular abstraction, an idiom has emerged from that language’s community which is The (“Best”) Way of doing it in that language. Furthermore, moderately experienced users of that language will recognise that Way when they see it in someone else’s source, and can quickly understand it at a higher/more abstract level without having to spend too many brain-cycles parsing the basic syntax or following the code path to discover its intent.

    It seems to me, for example that in many functional languages loops are usually coded with either a built-in iterator or recursion, but in imperative languages a for or while loop would usually be used. Someone who’s raised on conventional Java alone is likely to be confused (cache miss? page fault? skip a gear?) by a loop in Java which is coded using recursion. Not saying they won’t work it out eventually, but it takes extra effort. What are the initial and stopping conditions? What is the loop counter/variable? And of course it goes the other way too: You can usually do imperative things in functional languages but they often won’t be as elegant or efficient as The (functional) Way, and they may also confuse other coders who are reading the source in a functional frame of mind.

    A meat-space parallel might be the different human cultures. In some countries, business discussions are usually quick and aggressive, in others you chat over coffee for a few hours first. If you try to do it the ‘wrong’ way in either country, you may still get your business done, but things just won’t be as smooth and the result might not be as favourable.

    Interesting discussion. Thanks to all posters.

  63. David Marsh Says:

    @Bret, then point his colleagues at Guava or FunctionalJava libraries and tell them not to roll their own code with bugs.
    Tell them to write decent JUnit tests that will show up stack overflow and possibly highlight poor performance before production.
    Tell them to download the latest Java 8 SDK and learn the new features.
    Tell them to order this book and read it:- http://pragprog.com/book/vsjava8/functional-programming-in-java

    Lastly tell your boss you aren’t doing production support and bug fixing for Ivy league muppets unless they listen to the above advice.

    Then go enjoy your less stressful life…

  64. explosiveamber Says:

    Excellent article. I appreciate this piece of information as I currently program in a lot of functional languages, but I need to resort to Java to build an experimental application for scientific computing. The tipping point, past which of it is not safe to use functional paradigm to solve a problem is already found in small-size problems rather than in medium. Analysis will let me predict the cost of each operation, but not the amount of input data that others will use. That’s why they – and I – will hit the wall.

  65. rhg135 Says:

    I do agree with the OP in that it’s dangerous in java. The language can let you write atrocious code (as you showed) that’s neither functional or procedural. @carlok, for “F”‘s sake get your facts straight, the JVM is no parody, at the time there was nothing like it.

  66. mschaef Says:

    I recently spent a few weeks converting a tree-query language written in Java from an imperative implementation to a functional, streaming implementation. The technique I used is similar to what many of your comments have suggested: my implementation used Iterables and Iterators to provide a lazy stream abstraction. My first comment based on this experience is that it’s quite possible to safely write code in a functional style in Java (I was using JDK6 ported to JDK7, so none of the fancy JDK8 stuff). My second comment is that the experience felt a lot like writing procedural code in assembler or object-oriented code in C. The language does have the ability to express functional designs, but with a heavy syntactic overhead. For me, and the system I was developing, it only made sense because the total amount of code was relatively low, and the benefits were very high. (It was an interactive query language, so it was very important that the query language produce its first result quickly. Switching to stream based processing both achieved this goal and kept memory usage WAY down in many of our more important scenarios.)

  67. A Java Dev Says:

    I think you are wrong on many instances.

    This is official Java 8 , look how it is short and beautiful, does exactly what you want.

    import java.util.*;
    public class Main
    {
    public static void main (String[] args)
    {
    List numbers = new ArrayList();
    for(int i = 0; i System.out.println(e*e)); // functional
    }
    }

  68. A Java Dev Says:

    import java.util.*;

    public class Main
    {
    public static void main (String[] args)
    {
    List numbers = new ArrayList();

    // populate list

    numbers.forEach((Integer e) -> System.out.println(e*e));
    }
    }

  69. A Java Dev 2 Says:

    Even more easy in Java 8.

    public static void main (String[] args)
    {
    List integers =IntStream.range(0, 25).boxed().collect(Collectors.toList());
    integers.forEach( e -> System.out.println(e*e));
    }

  70. Java? ??? ?????? ???? ???? ?? ?? | Just hack'em Says:

    […] ??? ????? ? Why Functional Programming in Java is Dangerous? ??? ?? ?????. ??? ??? ?? Clojure ??? Java? […]

Leave a Reply