Lambda's/Closures in JDK 1.6
Llewellyn Falco
isidore at setgame.com
Tue Oct 12 09:38:26 PDT 2010
Java Lambdas <http://blog.approvaltests.com/2010/10/java-lambdas.html>
Lambdas allow for code like:
Query.*orderBy*(people, *new* S1<Person>(a){{ret(a.getAge());}});
Check out the video and download the jar to get started at
http://bit.ly/lambdas
I mentioned last month that I had found a way to add lambdas to the current
JDK. I struck me that perhaps many of you had not used lambdas before, so I
thought I make a small tutorial on one of the common uses:
*Sql like queries against your objects.*
Let’s start with the most basic,
*Order By*
If you where writing an Sql query to get people based on age, you would say
*Select* *
*From* People
*Order By *age
or perhaps
*Select* *
*From* People a
*Order By* a.age
If you had an array of people in *C#* this would be written as
Linq.OrderBy(people, a => a.GetAge())
Now, to do this in Java is a little more compacted, but very similar
Query.*orderBy*(people, *new* S1<Person>(a){{ret(a.getAge());}});
let’s look at some more examples.
*Select*
Let’s say you wanted to get the names of all the people, you’d write a query
like
*Select* a.names
*From* people a
Now, let’s translate that into java
Query.*select*(people, *new* F1<Person, String>(a){{ret(a.getName());}});
of course, with java you can select more than just primitives, if you wanted
the Addresses, you could do that too.
Query.*select*(people, *new* F1<Person, Address>(a){{ret(a
.getAddress());}});
you can even do transforms
List<Student> students =
Query.*select*(people,
*new* F1<Person, Student>(a){{ret(*new* Student(a.getName(), a
.getAge()));}});
let’s move on.
*Where*
Of course most queries wouldn’t be much use without the where statement.
Let’s find the all the A+ students
Query.*where*(people, *new* F1<Person,Boolean>(a){{ret(a.getGradePoint() >
3.8);}})
btw: it might be worth expanding the code a bit. I’m cheating a little to
help with understanding. For lambdas to work in Java, there is an
unfortunate side effect. It gets call 1 extra time. Specifically the first
time. So you need to pass in an object. That object in the examples above
is pre-defined as ‘a’ but in practice I usually use a blank object
*new* F1<Person,Boolean>(new Person()){{ret(a.getGradePoint() > 3.8);}}
unfortunately, you can’t use ‘null’ because it would throw a null pointer
exception. I also use the null object pattern a lot: Person.Null
of course there are some standard calculations that are nice too.
*Average*
what if you wanted the average length of a person’s name?
simple
Query.*average*(people, *new* F1<Person, Number>(a){{ret(a
.getName().length());}});
of course for averages, the return type F1<InputType, ReturnType> must be a
Number.
*Min*
by now you probably see how easy it would be to get a minimum or maximum, so
let’s up the lambda by using a local variable. Let’s find the person who got
the closest grade to sally.
*final* Person sally = getPersonByName("Sally");
Query.*min*(people, *new* S1<Person>(a, sally){{
ret(Math.*abs*(a.getGradePoint() -
sally.getGradePoint()));}});
You might have noticed the *final *key word, java requires that for locals
to be used inside of the lambdas. you might also have noticed that this time
I had to pass in 2 parameters (a, sally) to use sally inside you need to add
her as a parameter as well. Lastly, I used the class S1<Input> here instead
of F1<Input,ReturnType> this is just a convenience class which extends F1,
since any where, min, or max queries require the output to be a
Comparable object,
like Integer, String etc.
Well, I hope this got you interested in what lambdas can do for you. Check
out the video and download the jar to get started at http://bit.ly/lambdas
Happy coding,
Llewellyn Falco
More information about the coin-dev
mailing list