//********************************************************************//
//**************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