Java 8 has arrived. Every Java shop should embrace this new language version, which represents the most significant advance in the language since the 1990s. The headline feature is the addition of lambdas: in-line anonymous functions and important touchstones on the path toward the functional programming paradigm.

The availability of lambda functions is a low threshold to qualify a language as “functional,” and Java 8 is the last of the mainstream languages to add support for first-class functions. In that strict sense, we’re all functional programmers now. And, as I’ve said, certain functional techniques and mindsets have become commonplace. Unit testing in particular has shown us all that it’s easier to maintain a set of smaller functions that each compute and return a single thing rather than a monolithic function that does a complex calculation and then stores the result as internal state.

Many development managers are rightfully conservative, and they recognize the risk of introducing newly learned techniques into mission-critical codebases. This is wise when it comes to functional programming. Although I believe that functional programming techniques are broadly beneficial, a well-written study by Pankratius, Schmidt and Garretón showed that “Scala code is more compact than Java code, but clearly refute other claims of Scala on lower programming effort and lower debugging effort.”

I always caution about the difficulty of generalizing from specific experiments, but I’m going to ignore my own advice because this conclusion agrees with my own experience in using Scala as my day-to-day programming language for two years. I think Scala is an excellent language, and would choose it over Java—even Java 8—for new development by a small, experienced team. With larger codebases and situations where maintenance programming is already a significant part of the budget, choosing Scala has the significant downside that there are relatively few Scala programmers, and those programmers are expensive.

Java, on the other hand, is the most popular of the mainstream languages for corporate development. The downside of that is that the population of Java programmers contains many developers who have not been pushing themselves to continue learning, and who may be overconfident about their ability or blind to the challenges of functional code.

Functional code can be very dense, especially with functions that manipulate other functions. It can also be abused into a mess of spaghetti (when lambdas define lambdas defining lambdas, etc.). Object-oriented and functional designs do not always merge cohesively, especially in larger codebases where sweeping evolution to an entire module is not practical. Dense code, spaghetti code and confusing designs are not unique to functional programming, of course, but they are areas where developers who don’t know better can dig themselves into deeper and deeper holes.

Compounding the problem is the pragmatic issue that debuggers haven’t evolved to deal well with first-class functions. This holds true for the Java 8 preview IDEs that I have looked at. Debuggers have become excellent at allowing developers to inspect values, but I’ve yet to see one that excels at visualizing a variable that is actually a handle to a function or that is focused on a program whose state is primarily stored in the stack, not the heap. (I think Light Table may well show the path toward what a functional debugger might look like.)

Having raised a few caution flags, I want to reiterate my belief that Java 8 should be embraced. I’ve never met a developer who doesn’t rapidly grow to appreciate the elegance of using higher-order functions for transforming collections, and Java 8’s Stream library (java.util.stream) will give Java shops similar power to the kind enjoyed by C# developers using LINQ. This power includes not only obvious querying and filtering, but also a firmer foundation for reactive programming.

Many would say that, even more than first-class functions, the essence of functional programming stems from the immutability of variables after they have been assigned, and lazy evaluation—the ability to “call by need” in a manner that allows for such delightful things as infinite sequences and data structures (theoretically, but of course resource-limited in reality) and extremely flexible control-flow manipulation. Although I was initially hopeful that the Stream library was based on lazy evaluation, it appears not, but third-party libraries have already begun to appear.

Finally, I want to praise Java 8’s “default methods,” which are interfaces with implementations. While this may seem like a “see also” feature, it facilitates the Data-Context-Interaction approach, which I very much like.

Java 8 is a 450MB download from Oracle. Best of all, it doesn’t include the Ask toolbar.

Larry O’Brien, former Editor of Software Development and Computer Language magazines, is a software developer living in Hawaii.