Summary
Functional interfaces
- interface with a single method, no ambiguity about which function is being implemented
- acts as templates for lambda functions
- java.util.function are some base functional interfaces
java
@FunctionalInterface
interface Producer<T> {
T produce();
}
class A<T> {
T get(Producer<? extends T> prod) { // method that accepts and evaluates a producer
return prod.produce(); // prod is not a function, but an implementation of the functional interface
}
}
A<Integer> a = A<>();
Integer i = a.get(() -> 2); // nullary lambda function
i; // 2
Method reference
java
class A {
A() {
// constructor
}
static int foo() {
// static method
return 1;
}
int boo() {
return 2;
}
int hoo(int x) {
return x + 2;
}
}
// reference to constructor
A::new // Supplier<A> () -> new A();
// reference to static method
A::foo // Supplier<Integer> () -> A.foo();
// reference to instance method of instance
A a = new A();
a::boo // Supplier<Integer> () -> a.boo(); captures local variable a
a::hoo // Function<Integer, Integer> x -> a.hoo(x);
// reference to instance method of arbitrary object of specific type
A::boo // Function<A, Integer> a -> a.boo();
A::hoo // BiFunction<A, Integer, Integer> (a, x) -> a.hoo(x);
java
// say
int a = 1;
int b = 2;
int add(int x, int y) {
return x + y;
}
add(a, b);
// BiFunction implementation
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
add.apply(a, b);
// Curried Function implementation
Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y;
add.apply(a).apply(b);
useful for lazy evaluation, inner lambda can be evaluated later
Concept
Pure functions
- does not depend on anything extrinsic of the function
- function has a deterministic return value, that only depends on the input, ie.
void
functions are non-pure - function has no side-effects, ie. throwing exceptions or printing
Side effects
- write to files
- throw exceptions
- change variables
- modify values of the arguments
- cross barrier state manipulators
java
() -> code // Nullary
x -> code // Single parameter
(x, y) -> code // Multiple parameters
x -> { code; return code; } // Multiline
Anonymous classes of a functional interface
java
Supplier<Integer> s = () -> 1; // is the same as
Supplier<Integer> s = new Supplier<>() { public Integer get() { return 1; } };
- lambdas as closure, stores the surrounding local variables, allowing for delayed computation
- procastinate to compute only if absolutely necessary
- memoize to avoid recomputing, pure functions should return the same value everytime
Comparable and sort
java
// implements Comparable<T>
int compare(T o1, T o2) // returns -ve if o1 < o2
// from List<T>
list::sort(Comparator<T> cmp) // sorts the list in ascending order wrt to comparator
Application
Square
java
// Anonymous class
Transformer<Integer, Integer> sq = new Transformer<>() {
@Override
public Integer transform(Integer x) {
return x * x;
}
};
// Lambda
Transformer<Integer, Integer> sq = x -> x * x;
Pure functions
java
int square(int i) {
return i * i;
}
int add(int i, int j) {
return i + j; // overflow is not an error in Java
}
Impure functions
java
int div(int i, int j) {
return i / j; // may throw an exception
}
int incrCount(int i) {
return this.count + i; // assume that count is not final.
// this may give diff results for the same i.
}
void incrCount(int i) {
this.count += i; // does not return a value
// and has side effects on count
}
int addToQueue(Queue<Integer> queue, int i) {
queue.enq(i); // has side effects on queue
}