TODAY WE WILL
======
*   announcements
*   a BIT more on Java types -- segueing
    to Java INTERFACES

*   [oh, and intro to Java try-catch blocks!]

*   STARTING lambda expressions...

*   prep for next class

Reading
=======
*   currently:
    *   Chapter 4 - Objects and Classes
    *   Chapter 5 - Inheritance
    *   Chapter 6 - 6.1 - Interfaces
    *               6.2 - Lambda Expressions

*   Sorry that Homework 3 is delayed...! I will let you know
    what's next there when I know;

=====
*   so: what about Java interfaces!

    *   Java class can have ONLY one parent/superclass

        public class SpecialWidget extends Widget

    *   BUT any class can also IMPLEMENT multiple INTERFACES
        *   somewhat class-like! There are method headers involved!

        *   NOT a class, BUT a set of REQUIREMENTS for classes that
	    want to CONFORM to that interface;

        *   HOW does a class implement an interface?

            STEP 1: add "implements" clause to class header!

            public class MyNextClass implements DesiredInterface1, DesInt2, ...

            and a subclass can also implement interfaces:

	    public class SpecialWidget extends Widget implements Int1, Int2, ...

            STEP 2: that class now needs to IMPLEMENT all the requirements
	    of that interface!

       *   why do I WANT to do this?
           *   because whan a class implements an interface,
	       objects of that class now have ANOTHER type --
	       they are now also consider to have that interface as one
	          of their types

    *   if I wanted to make a GameDie instance also of type Comparable,

        public class GameDie implements Comparable
	{
            ...

            int compareTo(T o)
	    {
	        ...
	    }
        }

        and now the types for

	GameDie myDie;

        would include: GameDie, Comparable, and Object

=====
OOPS, an ASIDE:

try-catch blocks - catching EXCEPTIONS!

*   consider:

    that the Integer wrapper class (for primitive type int)
     and the Double wrapper class (for primitive type double)

    have some useful STATIC methods for converting appropriate
       String instances into int or double, respectfully

       *  static: means the classic way to call them is with the
          class name where the object name would go

        Integer.parseInt(String anIntString)
	and tries to return an int version of that String

        Double.parseDouble(String aDoubleString)
	and tries to return a double version of that String

        ...and these each can THROW an exception,
	   NumberFormatException,
	   if given an inappropriate String argument


*   SO - a method can THROW an exception.

    A method can CATCH an exception as well,
    and act based on it,
    using a try-catch block

    try
    {
        statements that MIGHT throw an exception
    }
    catch (ExceptionType1 exc)
    {
        action if ExceptionType1 is thrown
    }
    catch (ExceptionType2 exc)
    {
        action if ExceptionType2 is thrown
    }
    ... as many catch blocks as you'd like
    finally /* this is optional */
    {
         actions to be done whether an exception occurred or not
    }
    
    IF an exception occurs in try block,
    control passes IMMEDIATELY to the FIRST catch block
        whose exception type matches the exception thrown

    and then any finally-block actions are done
    then continue with whatever code follows

=====
*   starting to LAMBDA expressions (Java-style!)

    *   Horstmann's definition:
        p. 322: "A lambda expression is a block of code
	        that you can pass around so it can be executed
		later, once or multiple times"

                ^ I've always thought of a lambda expression
		  as an anonymous function, BUT then again Java
		  is not supposed to have functions, so maybe that's why
		  he defines it differently...

        p. 323: it is a block of code, together with the specification
	        of any variables that must be passed to the code

    *   p. 323: a first example:

        this is an expression:

        (String first, String second) -> first.length() - second.length()

    *   but if your lambda carries out a computation that need more statements,
        then you NEED { } and a return...

        a second example:

        (String alpha, String beta) ->
	    {
	        if (alpha.length() < beta.length())
		    return -1;
		else if (alpha.length() > beta.length())
		    return 1;
		else
		    return 0;
            }

    *   no parameters for your lambda?
        ...still need empty () before the ->

        () -> {
	          for (int i=100; i >=0; i--)
		  {
		      System.out.println(i);
		  }
              }