Alex Collins is a enterprise Java developer and currently works in the UK. He has worked in the insurance, publishing, telecoms and supply chain. In his spare time he codes in Python, Clojure and Scala (but not at the same time) and enjoys a multitude of sports. His catchphrase is K.I.S.S! Alex has posted 20 posts at DZone. You can read more from them at their website. View Full User Profile

Functional Programming Concepts in JDK 7

07.31.2010
| 20397 views |
  • submit to reddit

There's much excitement about JDK 7 and in particular Lambdas! I've waded through the bloat to help you get an understanding of it.

If you search for JDK 7 in your favourite search engine the chances are you'll hit the controversies surrounding lambadas in Java fairly early on in your hunt. It's a contentious subject, which means it's getting a lot of attention from a lot of clever people, but this in turn makes the process slow and adds difficulty in making decisions.

My take is that lambdas will be in JDK 7 - you can see plenty of evidence of that around the web and in the snapshot builds. That said, no decision is concrete (which is a wise tip from The Pragmatic Programmer no less!). This article is aimed at those who don't know much about functional programming or what Lambdas, Closures or Currying are and want to get 'primed'.

Lambdas

Lambdas are not a new concept. They've been around since the '30s in the wider topic of Lambda Calculus, introduced by Alonzo Church. Since then they've been a major feature in many functional programming languages - the most prominent of which would probably be Lisp. The subject itself is therefore quite extensive, but in its simplest form it is fair to state that Lambda is the feature of having functions as first-class citizens in a language; that's to say they are treated as an object in their own right by the type system. A Lambda is an anonymous function. To demonstrate, here's a snippet of Python that you might commonly see:

list = [1, 2, 3, 6, 8,]
print filter(lambda x: x * 2 > 10, list)
[6, 8]

The expression "lambda x: x * 2 > 10" is a lambda function - one that is anonymous at runtime and executed in the filter function. Similarly, you could assign the same expression to a variable and pass that in, or alternatively call the function itself:

f = lambda x: x * 2 > 10
print filter(f, list)
[6, 8]
# Let's call f itself
f(1)
False

In Java we currently have Anonymous Inner Classes which slightly demonstrate Lambdas in that they are anonymous and objects in their own right (because they're just compiled into an inner class). Once passed to a method they're just an everyday object. An example would be:

File cwd = new File(".);
System.out.println(cwd.list(new FileFilter() {
public boolean accept(File f) {
return f != null && f.getName().endsWith(".java");
}
}));

For now, think of lambdas simply as an anonymous functions which are as objects in their own right. In Java this could mean 'callbacks', true recursion and other wonderful things - perhaps gone are the days of implementing the Comparator interface to filter a Collection. Should they be completed in JDK 7, I personally look forward to seeing a much more dynamic language that'll have a whole new lease of life!

Function Types

As alluded to previously, lambdas would intrinsically introduce another concept of functionaly programming: function types. This simply refers to having fucntions as objects, just like a String or BigDecimal. This allows you to pass them to other functions (or indeed return them - see "higher order functions" below) like you would any other type.

Closures

You may also have heard of another term often thrown about in the debate - 'Closures'. This is another aspect of functional programming that is quite simple. A closure is the ability to have a function within another function and for that inner function to refer to variables outside of its scope; such variables are said to be "free" because they are not parameters of the closure or local variables. Think of the final variables that are available to anonymous inner classes in Java from their enclosing method.

In fact, if you have read much on this subject with regards to JDK 7 you'll probably see the term closure more than lambdas, this is because the two are often seen together - lambdas become closures when they access variables outside their scope and closures are lambdas by definition. 

Higher order functions

A higher order function is one that takes or returns a another function. In the Python examples at the beginning of this article you would've seen use of the 'filter' function. This itself is a higher order function because its first parameter is a function which is used to test the contents of each element of the list (the second parameter). 

Currying

Currying can be best explained as 'chaining' lambdas. Given a function that takes multiple arguments, curryingis the process of transforming that function so that each argument is passed to a function returned by each original function call. To demonstrate:

// "mul" is function that takes two arguments; both ints
mul(5).(5); // returns 25

Some "nice to haves"

Other functional programming concepts that I think might be nice to have are:

  • List comprehensions - syntactic sugar for generating lists (or sets, maps etc) as "one-liners"; e.g. List<String> l = (for x in someOtherCollection) { x.someMethod() && x.another(); }
  • Tail recursion - the ability for the compiler (or runtime environment) to identify a function as calling itself in the last of its instructions, therefore allowing for significantly optimised code.  

What's the point?

Good question. There's plenty of reasoning, the most obvious to me would be less code being written overall and another avenue of abstraction. Instead of implementing interfaces to pass around for FilenameFilters, Comparators and the like, you can pass functions which syntactically require less bloat.

A good source of 'use case' based examples is Neil Gafter's blog (who tends to know a few things about Java :)), start here and here.

Conclusion

The world of programming is rife with alternative paradigms, new age thinking and tradition. Functional programming is just another excellent approach to software development that provides its own set pros and cons; as with all programming features it's another tool that may or may not aid you in your quest to writing better software. Regardless of its use, I believe Project Lambda - should it be completed - could provide a breath of fresh air to a language that's still very popular but has its faults. 

 

 

Published at DZone with permission of its author, Alex Collins.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Joerg Wassmer replied on Fri, 2010/07/30 - 6:49am

In the actual state of the JDK 7 development function types have been removed in favour of SAM types. Thus the Lambdas are nothing but another syntax for inner classes.

cowwoc replied on Fri, 2010/07/30 - 7:31am

Goodbye Java, we knew you well.

 

Any new feature that is added to Java must look like Java. At least try to make an effort...

Andy Leung replied on Fri, 2010/07/30 - 8:40am

well, I really hate all these new features coming from other languages because they all make Java syntax messy!!! Now Java is going towards the C++ directions, like C++ Template is nothing really useful. If you think these closures thing would make your code clean, good luck with that!! Try with 10,000 line and you want to search a function!!!

Vikrant Kumar C... replied on Fri, 2010/07/30 - 9:45am

I too feel these features addition made the java to move towards c/c++ direction. This is something Java was not suppose to do. This way Java is losing its charm. However I really like concept of SCALA & others.But i don't want Java to go in that direction.

Alex Collins replied on Fri, 2010/07/30 - 9:53am in response to: Vikrant Kumar Choudhary

I agree to some extent. Java's an old language when you compare it to its .Net or FOSS counterparts, and in many respects it's attempting to modernise but at the same time maintain its *excellent* track record of stability and rigidity and of course: backwards compatibility. The beauty of these JVM languages is that they intermix with the Java API which gives a best of both worlds scenario - you get modern dynamic (and functional( languages that can integrate with legacy code within an organisation as well as the safety of the JVM. Whether the JVM languages or modernising Java will succeed is something time will tell...

Otengi Miloskov replied on Fri, 2010/07/30 - 12:43pm

If this features arrive with JDK7, Java will be updated for the next 10 years of development. Some people in here are not agree with this features and they think Java is getting complex as C++. I dont think so, It is just syntatic sugar, thats all, even the easy scripting languages this days have all this features as lambdas and closures for example Python, PHP, Ruby, Clojure, Groovy, Perl, IO and more. Java need this for to stay relevant for the next wave of development. As a Java developer I hope Java gets this boost of features because I care for Java to keep healthy and not become the next cobol cause that only big corporation burocratic fat lazy asses use cobol.

Honey Monster replied on Fri, 2010/07/30 - 1:57pm in response to: Alex Collins

I think you are missing some of the finer points here. The attempt to introduce *some* functional aspects into Java are *not* motived by a desire to turn Java into a multi-paradigm language (like e.g. C#), rather the goal is rather narrowly to support a fork-join style of parallelism.

There is a broad realization that a traditional threading model simply does not cut it when going massively parallel. The model becomes too complex and the result will be apps which do not take full advantage of many-core architectures. To scale simple apps to many cores you need to divide the executable parts into even smaller parts which can be individually scheduled. This is where lambdas/closures comes in.

Functional languages have a number of inherent advantages in this category, e.g. immutable state comes more natural. Immutable state is really important as it can help overcome memory barriers and caching problems.

But the aim of the current endeavor seems not to add functional programming as much as merely allowing easier syntax for subdivision into smaller executable units - i.e. lambdas. So I really think that focusing on the (severely limited) functional aspects of Java 7 is setting the community up for a *major* disappointment. Lambdas in the current proposal is merely just syntactic sugar for anonymous inner classes. You will *still* not be able to use free non-final variables (local vars, parameters, fields) from the lexical scope. You will *still* not be able to compose lambdas freely, like e.g. writing a generic or or other boolean function. Only in the most creative interpretation can what is now being considered be termed closures.

Meanwhile C# has evolved into a modern multi-paradigm language: It had delegates (function types) from the start, it quickly added closures and inline functions. With C# 3.0 it had lambdas - primarily as an enabler for LINQ. Closures and function pointers lets you freely compose and consume in a true functional style.

Java/JVM is severely lagging in a another paradigm as well: Dynamic typing and interop with dynamically typed languages. The situation on the JVM can best be described pair-wise (or even one-way) interop: Most alternative JVM language can consume native Java classes (to tap into the vast library) and *some* languages even allow *some* of their objects to be consumed by Java programs as well without too many rituals (not how JavaFX is *not* in this category. But consuming JRuby or Jython objects from JavaFX or Scala is virtually impossible.

Compare that to C#/CLR/DLR where C# not only supports (since 4.0) dynamic typing, but more importantly the platform has a hub-and-spoke architecture for exchanging objects. This means that IronRuby objects can be readily consumed by C#, F#, IronPython or any other language and vice versa! Not only that, but the platform also comes with extensive support for name/member resolution and sophisticated caching techniques which makes implementing efficient, dynamic languages much easier. On the JVM such caching is being implemented in each and every dynamic language. Again and again. And incompatible with each other.

This is my gripe. Java has lagged so much that it is now squarely in the legacy category. The huge library is its now it's only advantage. But there is no obvious path forward, the current attempts are far too little (and late at that). If Java is not going to evolve into a modern multi-paradigm language, we really need the *platform* to better support migration and *co-existence*, two-way integration with other-paradigm languages, functional and dynamic or both. But it doesn't.

Andy Leung replied on Fri, 2010/07/30 - 11:49pm in response to: Honey Monster

I am not sure if I understood your points correctly but this is a common mistakes people are making now, well at least from my point of view:

Java/JVM is severely lagging in a another paradigm as well: Dynamic typing and interop with dynamically typed languages
People seem to mix the idea of "dynamic type" means dynamic software functionalities but this is absolutely wrong. If you think about it from high level like architectural level or even business requirements level, it doesn't care what languages you use. Next level may involve some high level design but only involving platforms, time and communication channels. Then we will see detail data flow and all other things coming into analysis and honestly, at this point, people make try to find the most powerful language that gives you the most libraries or tools to build it in shortest time but I think there is an existing fundamental problem here: Architectural Design. When coming from top-down, you see it from big picture down to earth. However, if you don't go back up and then analyze both with horizontal components to put all ingredients into it, regardless of what dynamic language you use, problem occurs quickly when there is a change in business requirements. If we take a look at the Architectural Design, some of the most successful designs are business engines. These software takes simple input and output in bottom layer, could be as channels. Then internal it allows you to build virtual components on top of this physical layers and on top there is business components.

Now if you think about it, does it matter if you use static type or dynamic type? Since input is very solid, it's like a hardware optimized for one purpose only, static type is the answer which lets you find out defects during development time instead of runtime and things won't change during runtime so it's always static.

An example would be HTTP, see how many things going around HTTP, Ajax, XML, JSON, Web, all these keywords are simply things contained inside the fundamental concept of HTTP and that's it. So HTTP will be a communication component reused by business regardless of how they change the data or workflow within.

That is why I like the idea of BPM. Eventually I think many Developers will start building business process using BPM-like tools and there will be component developers who develop optimized components only. With this, unless there is a new component required for new business requirement, business requirement change is as simple as couple clicks. Anyhow just my 2 cents.

Viorel Craescu replied on Sat, 2010/07/31 - 2:04am

Java will never be what today programmers want it to be until it break the compatibility with legacy code. Any new feature borrowed from other languages will make the language itself worse. I believe Java developers are looking for the feeling they have when they do code in pure dynamic type language, working with a less bloated technology.

I don't think Java will ever be the next Cobol. Too many corporations make a living from it and they have all the reasons to keep it alive for a long long time. I don't think Java is in same position as Cobol...

Personally, i do believe Java is what it has to be for the job it has to do.

Bob Smith replied on Sat, 2010/07/31 - 8:30am

As the number of cores grows, and massive parallelism and multithreading become essential paradigms, something better than Java will come along.

 I understand why Sun has made backward compatibility so critical in Java, but I think they've gone way too far.  The disaster that is java.util.Date (I mean methods like setDate()) have been deprecated since Java 1.1.   Guess what?  They're still there and haven't been removed, and probably never will.

Generics has type erasure, which is a very bad idea and the only reason it was implemented was because of backward compatibility.

Sun's support of backward compatibility is extreme.  Ideally, a deprecated method or class or some other construct should be removed after 3, max 4 versions after it's been deprecated.   If somebody's stupid enough to use Date.setDate() by now, they probably aren't paying Oracle enough money to make it worthwhile.

Java either needs to eliminate a lot of cruft, or Oracle should start working on Java++ (or something along those lines) as the next generation of Java.   Maybe Scala will be that language, maybe something else.

 

Honey Monster replied on Sat, 2010/07/31 - 6:54pm in response to: Bob Smith

Generics has type erasure, which is a very bad idea and the only reason it was implemented was because of backward compatibility.

That is not entirely correct. Unfortunately it is a common misconception. Reified generics (i.e. with no type erasure) were definitively possible while maintaining backwards compatibility. What was required of the language designers (and regrettable never successfully challenged) for specifying generics was migration compatibility.

Migration compatibility is a different beast which is only really required in some hypothetical situations where your product relies on two products library A and library B which you don't have source code for and which has a direct non-interceptable dependency (e.g. library B builds upon library A). Migration compatibility is then required if the vendor of library A upgrades to using generics and refuses to maintain a non-generic version. At the same time (for migration compatibility to be required), vendor of library B refuses to upgrade to generics-aware code. Now they would be incompatible if not for migration compatibility.

Backward compatibility - in the sense that existing code can run without recompilation on a newer VM - was quite possible. C# did it by designing new generic collection classes which implement the old-style collection interfaces with proper casts/checks.

Neal Gafter replied on Sat, 2010/07/31 - 9:55pm

This article contains pointers to two of my articles about use cases for closures, but unfortunately it looks like the lambda expressions we're likely to get will not be powerful enough to express them.

Honey Monster replied on Sun, 2010/08/01 - 6:08am in response to: Neal Gafter

Neal, I have been sort of lurking on the lambda-dev. I know that you have already been-there-done-that (BGGA) and each time a new proposal is put forward you can immediately home in on the problematic aspects. I have gained a lot of respect for language designers reading that list. It really is immensely complex.

It seems to me (AFAIK this has not been stated officially) that the process now is to dump features to avoid the complex pit-holes and get to *some* kind of result. Can you confirm this? If that is the case, falling back to SAMs which are widely understood, although not exactly elegant.

I also get a deja-vue to generics. I think a great mistake was made back then because the initial requirements were not challenged. As I wrote above, backwards compatibility was entirely possible, but the requirements called for migration compatibility (your term, I believe), which - given the Java ecosystem where a lot of code is open source or at least distributed in source form - is must less of a problem than initially thought. Well, at least this time it seems that while there still at divide about the end-goal, most designers realize that at least they should not design these extensions so that e.g. control abstractions are forever impossible.

Whenever I encounter a situation where idea after idea is floated only to be shot down, I usually end up pushing the chair back and try to look at the situation from the outside. If a good solution is impossible given the current constraints, perhaps it is time to take a look at the constraints?

Neal Gafter replied on Sun, 2010/08/01 - 3:53pm

@Uffe: Yes, it appears that project lambda is simplifying to get *some* kind of result.  But unfortunately the result is no more expressive than the anonymous inner classes already in the language, which leaves one wondering if we'd be better off with no result than a language extension that adds nothing.  The kinds of complexities that people seem most concerned about are ones that have given little difficulty to programmers in languages such as Scala, Ruby, Smalltalk, etc.  But being unfamiliar with the concepts, Java programmers shy away from anything they don't already have.

J Szy replied on Mon, 2010/08/02 - 5:04pm in response to: Honey Monster

You will *still* not be able to use free non-final variables (local vars, parameters, fields) from the lexical scope.

Unfortunately this restriction is all too easily defeated by using one-element arrays and it will so remain.

But consuming JRuby or Jython objects from JavaFX or Scala is virtually impossible. 

The question is: who cares?

This means that IronRuby objects can be readily consumed by C#, F#, IronPython or any other language and vice versa!

I'm pretty sure there are orders of magnitude more blog posts bragging about this than real word production uses. Is there really any widely used language for .NET apart from C# and VB.NET?

If Java is not going to evolve into a modern multi-paradigm language, we really need the *platform* to better support migration and *co-existence*, two-way integration with other-paradigm languages, functional and dynamic or both.

Face it: JVM supports many languages for years and noone gives a damn, ever did or will. They are just toys and IMHO most of them were created just because it looks better in a resume to have created a language (which nobody will ever use for production) than to have implemented a standard API (which would be actually useful, but it's so boring and unchallenging). But whatever the reasons, one thing is sure: those languages can use the huge Java library and yet hardly anyone is switching. 

And even if the support for SLDJs were better, it wouldn't change a bit. .NET has this better support from day one and .NET folks almost completely ignore IronWhatever - if you count real world production uses, not blog postings, that is.

 

J Szy replied on Mon, 2010/08/02 - 5:40pm in response to: Neal Gafter

it appears that project lambda is simplifying to get *some* kind of result.  But unfortunately the result is no more expressive

I'd say that they are trying to do as little harm as possible while doing something. I agree that this is bad policy: they should drop the concept altogether.

See, Java is not for cute programming tricks, Java is for writing robust code for real business use. It doesn't need and should not welcome any grahamesque "Write And Never Dare Touch Again" kind of expressivity. On the contrary, it should focus on solutions that make code maintenance easier, even at the cost of making the initial development harder.

That's what Java designers did at the beginning, consciously or not, and that's what has ensured Java's position for today and forthcoming years.

unfamiliar with the concepts, Java programmers shy away from anything they don't already have.

That, or they are just wise enough not to get overexcited about a new shiny feature, and to consider its possible downsides.

 

Honey Monster replied on Mon, 2010/08/02 - 6:17pm in response to: J Szy

I'd say that they are trying to do as little harm as possible while doing something. I agree that this is bad policy: they should drop the concept altogether.

See, Java is not for cute programming tricks, Java is for writing robust code for real business use. It doesn't need and should not welcome any grahamesque "Write And Never Dare Touch Again" kind of expressivity. On the contrary, it should focus on solutions that make code maintenance easier, even at the cost of making the initial development harder.

Unfortunately, the world has changed a little bit since Javas inception. Java came with threading-aware and ground-breaking synchronization (even if faulty at first) built into the language. But time has passed and "threading" doesn't cut it anymore. It is too complex to control successfully and much too error-prone. The solution is widely recognized (and has been for some time): Divide your app up into even smaller executable chunks (then methods), tasks, and let them be scheduled using a thread-pool pattern. This is why you saw an about-face also within parts of the anti-closure camp. The stated goal of project lambda is to enable/assist fork-join.

If Java doesn't respond to the many-core development, Java developers will have a hard time keeping up with the performance gains experienced using other (task aware) languages. That is what this is really about. There is some divide over how much needs to be done, but the current "use anonymous inner classes" doesn't cut it.

I personally believe that multi-paradigm languages (like C#) will be transitional at best: They will not fulfill the end-goal but they will pave a way to get there. Functional programming really has a great story to tell in a many-core world. But we need bridges to get there: We need to cultivate the ecosystems and we must be able to leverage the sizable investments in libraries/legacy code. That is why co-existence becomes vitally important if the core language is not fulfilling the paradigm gap. The JVM may have many languages developed on top of it, but it's co-existence support is abysmal. Often you only have one-way interop (like with JavaFX).

J Szy replied on Tue, 2010/08/03 - 8:43am in response to: Honey Monster

The solution is widely recognized (and has been for some time): Divide your app up into even smaller executable chunks (then methods), tasks, and let them be scheduled using a thread-pool pattern.

"Smaller than methods"? It's meaningless. And you don't need anything "smaller than methods" to have it scheduled in a thread pool. In fact, classes do just fine.

But of course, many companies require that classes and methods be documented and I start to think that this is what really bothers most closure-braggers - closure syntax not only enables cute tricks and maintenance headaches, it also precludes formal documentation!

Just another reason to keep it out.

If Java doesn't respond to the many-core development, Java developers will have a hard time keeping up with the performance gains experienced using other (task aware) languages.

There are evidently some things that could be done to enhance multicore development (and maintenance) experience, like e.g. allowing for static enforcement of object immutability (WANT IT!), but special syntax for functions, function types, non-local returns or mutable variable capture are not among them. I'd even say some of them significantly worsen multicore dev.

hard time keeping up 

Oh, and don't worry about us Java developers because anything like this will not happen. I'll tell you what will happen: blog weenies will keep whining about how Java is backwards, full of boilerplate and unsuited to "serious parallel development", and the business world will keep ignoring them.

It is of course possible that some other platform, and associated language will take over the world in the storm like Java once did, but I wouldn't bet my money that anything like this would happen in a dozen years or so. And even less so that this new dominant language would not be object oriented.

 the current "use anonymous inner classes" doesn't cut it.

Use named classes.

Functional programming really has a great story to tell in a many-core world.

If only Stephen King hadn't taken the title.

That is why co-existence becomes vitally important if the core language is not fulfilling the paradigm gap. The JVM may have many languages developed on top of it, but it's co-existence support is abysmal.

No, that's why bloggers remain bloggers, whining about Java, bragging about Clojure and posting golfed examples of trivial solutions to book problems, and that's why business remains business, ignoring this entire mess and sticking to Java.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.