2. Take Away Point
> “FP Works In Java If You Do It Right”
> It work even in Java 6
> It carries many of the FP benefits from pure FP languages
> Java 7 will make it a bit more elegant
> Agenda
> FP quick introduc7on
> Top 10 lessons learned
> Q&A
Func7onal Programming in Java: Lessons Learned by GridGain Slide 2
3. FP Quick Introduc%on
> General
> First‐class & higher‐order func7ons
> Pure func7ons ‐ no side effects and referen7al opaqueness
> Currying as par7al func7on applica7on
> Recursion
> Language specific
> Monads and collec7on comprehension
> PaSern matching
> Lazy ini7aliza7on
Func7onal Programming in Java: Lessons Learned by GridGain Slide 3
4. FP Quick Introduc%on cont.
> Java + FP = Post Func7onal system
> Java is impera7ve OOP system
> Java + FP ‐ Garbage = Scala
> Pure FP languages suck in object domain design
> OO is way beSer in describing our world
> FP excels at actual coding of the algorithm
> Post Func%onal “manifesto”:
> Use OO to build your classes
> Use FP to implement their methods
Func7onal Programming in Java: Lessons Learned by GridGain Slide 4
5. Lesson 1 ‐ FP Is More Than Just Cool Concept...
Impera7ve GridGain 2.0 Functional GridGain 3.0
@Gridify(taskClass = Task.class) public int length(String msg) {
public int length(String msg) { return G.grid().reduce(SPREAD, F.yield(msg.split(“s”, 0),
return msg.replaceAll("s", "").length(); F.<String, Integer>c1("length")), F.sumIntReducer());
} }
class Task extends GridifyTaskSplitAdapter<Integer> {
@Override
protected Collection<? extends GridJob> split(int gridSize,
GridifyArgument arg) throws GridException {
String msg = (String)arg.getMethodParameters()[0];
String[] words = msg.split("w", 0);
Collection<GridJob> jobs = new ArrayList<GridJob>();
for (final String word : words) {
jobs.add(new GridJobAdapter() {
@Override
public Object execute() throws GridException {
return word.length();
}
});
}
return jobs;
}
@Override
public Integer reduce(List<GridJobResult> results) throws GridException {
int length = 0;
for (GridJobResult res : results) {
length += (Integer)res.getData();
}
return length;
}
}
Func7onal Programming in Java: Lessons Learned by GridGain Slide 5
6. Lesson 2 ‐ Typedes Help Reduce Java Bloat
> Java, unlike Scala, does not have type aliases
> The only choice: Inheritance
> public abstract class C1<E1, R> extends GridClosure<E1, R> {}
> public class F extends GridFunc {}
> Can only be used during crea7on for stateful classes
> Can be used as a real alias for u7lity classes
> Without typedef:
return GridFunc.isEmpty(a) ? GridFunc.<T>alwaysFalse() : new GridPredicate<T>() { ... }
> With typedefs:
return F.isEmpty(a) ? F.<T>alwaysFalse() : new P1<T>() { ... }
Func7onal Programming in Java: Lessons Learned by GridGain Slide 6
7. Lesson 3 ‐ Immutability Actually Works
> CPU and memory inefficiency is greatly exaggerated
> Copy‐On‐Write structures gebng more and more aSen7on
> Strong support for immutability from FP library
GridPredicate2<Integer, Integer> p = new P2<Integer, Integer>() {
@Override public boolean apply(Integer i1, Integer i2) { return i1 > i2; }
};
Collection<Integer> c = new ArrayList<Integer>();
...
F.forEach(F.retain(c, true, p.curry(10)), F.<Integer>print("", " ")); // < 10.
F.forEach(F.lose(c, true, p.curry(10)), F.<Integer>print("", " ")); // >= 10.
Func7onal Programming in Java: Lessons Learned by GridGain Slide 7
8. Lesson 4 ‐ Tuples Reduce Noise POJOs
> An Obvious Design Pa8ern forgoSen in 99% of projects
> Ideal for:
> Returning mul7ple value from the methods or closure
> Ac7ng as a free variable in the closure
for (Object obj : F.t(2, 0.5, "tuple")) {
System.out.println("Tuple element: " + obj);
}
...
GridTuple3<String, Integer, Boolean> t = F.t("gridgain", 1, false);
String s = t.get1();
int i = t.get2();
boolean b = t.get3();
Func7onal Programming in Java: Lessons Learned by GridGain Slide 8
9. Lesson 5 ‐ Collec%ons Comprehension Without Monads
> Java does not have monad support, however...
> ...similar collec7on comprehension can be provided via API
Collection<Integer> nums = new ArrayList<Integer>();
F.forEach(nums, F.<Integer>print("", " "));
int max = F.fold(nums, F.first(nums), new C2<Integer, Integer, Integer>() {
@Override public Integer apply(Integer n, Integer max) { return Math.max(n, max); }
});
int min = F.fold(nums, F.first(nums), new C2<Integer, Integer, Integer>() {
@Override public Integer apply(Integer n, Integer min) { return Math.min(n, min); }
});
int sum = F.fold(nums, 0, new C2<Integer, Integer, Integer>() {
@Override public Integer apply(Integer n, Integer sum) { return sum + n; }
});
...
public static void sayIt(String phrase) throws GridException {
G.grid().run(SPREAD, F.yield(phrase.split(" "), F.<String>printf("%sn")));
}
Func7onal Programming in Java: Lessons Learned by GridGain Slide 9
10. Lesson 6 ‐ Checked Excep%ons Do Not Work (Unfortunately)
> Closures and predicates are abstract classes:
public abstract class GridClosure<E, R> {
public abstract R apply(E e); // Awkward to throw an exception...
public GridOutClosure<R> curry(final E e) {
return new CO<R>() {
@Override public R apply() { return GridClosure.this.apply(e); }
};
}
}
...
GridClosure<Integer, Integer> sqr = new C1<Integer, Integer>() {
@Override public Integer apply(Integer i) { return i * i; }
};
Collection<Integer> c = F.asList(1, 2, 3, 4);
F.transform(c, sqr); // 1, 4, 9, 16
Func7onal Programming in Java: Lessons Learned by GridGain Slide 10
11. Lesson 7 ‐ Accept null As Alterna%ve to Op%on/Maybe
> Op7ons/Maybe is extremely powerful concept in languages like Scala or Haskel
> In Java ‐ direct implementa7on is largely impossible ☹
> Closest thing ‐ accept null collec7on and empty varargs
Scala Java GridGain 3.0
val value = for { public static <T> boolean isAll(@Nullable T t,
row <‐ database fetchRowById 42 @Nullable Iterable<? extends GridPredicate<T>> p) {
key <‐ row get "port_key" if (!isEmpty(p)) {
val <‐ myMap get key assert p != null;
} yield val
for (GridPredicate<T> r : p) {
val result = value getOrElse defaultValue if (r != null && !r.apply(t)) {
return false;
}
}
}
return true;
}
Func7onal Programming in Java: Lessons Learned by GridGain Slide 11
12. Lesson 8 ‐ Last Argument as vararg of Predicates
> Very useful idiom to make ordinary methods powerful:
> You can pass zero predicates (omit parameter)
> You can pass just one predicate
> You can pass null as parameter
> You can pass array as parameter
> You can pass mul%ple predicates... all in one signature (!)
> Used globally in GridGain project
> One of the most radical improvements on API
// Data grid.
forEach(GridInClosure<GridCacheEntry<K, V>> vis, @Nullable K... keys);
forAll(GridPredicate<GridCacheEntry<K, V>> vis, @Nullable K... keys);
reduce(GridReducer<GridCacheEntry<K, V>, R> rdc, @Nullable K... keys);
loadCache(GridPredicate2<K, V> p, long ttl, @Nullable Object... args);
// Closures and tasks on cloud.
call(GridClosureCallMode mode, Callable<R> job, @Nullable GridPredicate<GridRichNode>... p);
execute(String taskName, @Nullable T arg, @Nullable GridPredicate<GridRichNode>... p);
forkjoin(Collection<T> jobs, GridReducer<R1, R2> rdc, @Nullable GridPredicate<GridRichNode>... p);
run(GridClosureCallMode mode, Runnable job, @Nullable GridPredicate<GridRichNode>... p);
send(Object msg, @Nullable GridPredicate<GridRichNode>... p)
Func7onal Programming in Java: Lessons Learned by GridGain Slide 12
13. Lesson 9 ‐ Func%on Factory vs. new
> Reduces Java Generics bloat by type inference
> Widely used despite “broken” Generics and type inference
Compare:
Iterator<Object> iter = new GridTuple3<String, Integer, Boolean>("a", 1, false);
vs.
Iterator<Object> iter = F.t("a", 1, false);
Func7onal Programming in Java: Lessons Learned by GridGain Slide 13
14. Lesson 10 ‐ Learn Scala First!
That is what we did at GridGain...
...and that is the only reason we got it right on Java side.
Func7onal Programming in Java: Lessons Learned by GridGain Slide 14