//********************************************************************//
//**************Lambda Expressions - November 4th, 2016**************//
//******************************************************************//
-To recap: iterators "decouple" the iteration of a data structure from said structure's internal details, and are implemented via the "Iterable" interface.
-Java 8 added "Lambda expressions," which are so new that you probably will still find professional programmers who don't use them yet.
-Let's go back to Comparators. Let's say we only use the Comparator interface in ONE PLACE- we can just create and implement a new interface implementation right there by making an ANONYMOUS INNER CLASS:
e.g.:
"..., new Comparator<Trooper>() {
public int Compare(Trooper a, Trooper b) {
if(a.hasMustache() && !b.hasMustache()) {
return 1;
} else if(b.hasMustache() && !a.hasmustache()) {
return -1;
} else {return a.compareTo(b)}
}
}"
-"ANONYMOUS" since it doesn't have a name
-BEFORE we get to Lambda expressions, though, we have "Functional Interfaces" - interfaces with just a SINGLE, ABSTRACT method (not counting inherited methods).
-Occasionally abbreviated "SAM" - single abstract method type
-Like @Override, we can use "@FunctionalInterface" to have the compiler check if something is a functional interface
Functional Interfaces are nice because they're easy to define via Anoymous Inner Classes, but we can do even better: a LAMBDA EXPRESSION
-A LAMBDA EXPRESSION is a shortcut Java gives us to define the abstract method of a functional interface AND instantiates an abstract class for it
-Defined like THIS:
(T1 x1, T2 x2, ... , Tn xn) -> {method_body}
-This is useful because, over time, it gets rid of a LOT of boilerplate code
-However, (for now), they're just "syntax sugar" - they don't let us do anything new, they just make it easier to type
-If the "method body" is just ONE LINE, we can ommit the curly braces
-Let's say we have a method:
static interface Bar {
int compare (Trooper a, Trooper b);
}
static void foo(Bar b) {...}
-We can put the lambda expression INSIDE the call for Foo, e.g.:
"foo((Trooper a, Trooper b) -> {
if...(same code as for AIC example)...
});"
-This creates an instance of the "Bar" interface using the lambda expression
-How does Java know it's a "Bar"? Because the TARGET TYPE of "foo"'s method header ONLY takes Bar, the compiler uses TARGET TYPING to figure out that the Lambda Expression has to be a Bar
-If we had, say, 2 "foo()" methods that both took 1 parameter with different types, then Java couldn't figure out which type the Lambda Expression should be and would throw an error
-Could get around this by actually casting the Lambda Expression itself to "Bar"
-Could also bind the Lambda Expression to a variable with the desired type, e.g.:
Comparator<Trooper> compy = (Trooper a, Trooper b) -> 1;
-So, a Lambda Expression is fundamentally a notation for creating an AIC as quickly as possible
-A METHOD REFERENCE (need to look this up)
-Let's say we have a functional interface "foo" with a method "String bar(object x);"
e.g. doo(System.out::println) IS THE SAME AS doo(x -> System.out.println(x))
-3 kinds of method references:
-"object"::"instanceMethod"
-
-
-By using method references in combination with existing methods, it's possible to get EXTREMELY condensed, very nice-reading code (example in slides)
-SIDE NOTE:
-Top-Down Development:
-Define the broad structure of the program (e.g. method headers), then implement all the methods / pieces to get it actually working
-Bottom-Up Development
-Make all the pieces, then stitch them together
-Different projects/ languages are more suited for each