Skip to content

Instantly share code, notes, and snippets.

@iocat
Created June 9, 2018 02:40
Show Gist options
  • Save iocat/0a4ae5944ae3065df453faa67049a8ce to your computer and use it in GitHub Desktop.
Save iocat/0a4ae5944ae3065df453faa67049a8ce to your computer and use it in GitHub Desktop.
Lambda expression in Java
import java.util.function.*;
public class Lambda {
public static void main(String[] args) {
// In the object world of Java when everything is an object, you can't really pass function as "object."
//
//
//
// Unlike Java <1.8, Javascript allows you to have first-class functions or function as value which you can
// assign to variable, pass them around, return them! This is fundametal to functional programming,
// where behavior can be constructed on the fly much easier!
// Example in js
/*
var triple = function (x) {return x * 3; }
var double = x => x * 2
var multiplyBy = function (factor){return x => x * factor } // returns a function that do multiplication
So in Java, how do we build behavior dynamically on the fly? We build objects that have specified behaviors.
Then we swap in other objects that have behaviors we desire.
Example: a cat can meow and another one can MEOW really loudly. This is how we build dynamic behavior
1. Way 1
*/
Meowable meowable = new SmallMeow();
meowable.meow();
meowable = new LoudMeow();
meowable.meow();
/*
This is quite a tedious task to add a new behavior, right?
If you want to add a new behavior such as GrumpyMeow, you would have to define a new class with that
name, and reimplement that same method!
2. Way 2
In Java version 1.3, Java introduces anonymous inner class which allows us to define
an abstract class/interface's implementation inline. This makes it easier to define behavior
dynamically without naming them... Let's try to implement GrumpyMeow
*/
// anonymous inner class
meowable = new Meowable(){
@Override
public void meow(){
System.out.println("GRURRRRRRRRRRMMMMMMMMMM!! MEOOOOOOOOOW!"); // a somewhat dramatic meow
}
};
meowable.meow();
/*
Better yet, this feature allows you to create class instance and implementation at the same
time without having to create a new file and put the implementation there. (quite a tedious task)
But the syntax is not clean however, and quite repetitive too!
new Meowable(){
@Override
public void meow(){
// THE ACTUALLY IMPORTANT IMPLEMENTATION GOES HERE
}
}
You have to rewrite the outer block of the code above many times if you happen to have different behaviors!
We do all that much just to write a single function? Yikes.
3. Way 3
So what happen is, in Java 8, they added functional interface that makes this process less verbose.
What you can do is to annotate the interface as a @FunctionalInterface, then you can assign
the variables holding that interface with a lambda expression. Better yet, the lambda expression
doesn't need to hold type because the types are infered from the functional interface
*/
meowable = () -> System.out.println("What? I'm not a cat!");
meowable.meow();
/*
In the object standpoint, lambda function is just like any other object.
Another cool thing about Java 8 is that it allows you to extract behavior which was already in
the older JDK using "method reference."
*/
Function<Integer, Integer> doubleFunc = Utils::doubleIt;
Predicate<Integer> isEven = Utils::trueIfEven;
System.out.println(doubleFunc.apply(1));
System.out.println(isEven.test(2));
}
public static class Utils{
public static Integer doubleIt(Integer i) {
return i*2;
}
public static boolean trueIfEven(Integer i){
return i % 2 == 0;
}
}
@FunctionalInterface
public static interface Meowable{
public void meow();
}
public static class SmallMeow implements Meowable{
@Override
public void meow(){
System.out.println("meow");
}
}
public static class LoudMeow implements Meowable{
@Override
public void meow(){
System.out.println("MEOOWWWW GRUHHHH!!");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment