Functional Java 1
First Class Data We have learned how to manipulate data with programs We can pass data to methods via arguments We can return data from methods via return types We can encapsulate data into objects / classes The object can be accessed by its reference variable The object can be acted on by its methods Because we handle data so easily, data is a first class citizen in the Java world 2
Functions have been Second Class We know how to define a function, but we don t know (yet) how to manipulate a function Can we pass a function as an argument? Can we return a function as a parameter? How do we encapsulate and reference a function? Closest we come is polymorphism One function invocation invokes different methods Or single method Interfaces 3
Examples of Manipulating Functions Starting a GUI, we needed to add a function to the event loop to start things off the run method We created an object that was an instance of a class The class implemented the Runnable interface We passed that object to the invokelater method as data The invokelater eventually invoked objref.run() That invoked the run method in our class Whew that was complicated 4
Examples of Manipulating Functions When we registered an actionlistener callback We changed our class to implement the ActionListener interface We added an ActionPerformed method to our class We then registered by invoking addactionlistener The parameter to addactionlistener was not the callback function, but an object (data) The convention is, when an action is performed, find the data registered to that action, and invoke the object.actionperformed method Whew 5
Anonymous Inner Classes Sometimes we don t want to modify the class we are working on to accommodate interfaces to pass functions One alternative is to create a different class, but there is a lot of overhead New Java file, New class, new fields, new creator It would be nice to reduce the overhead Put the class definition in the current file Define the class inside the current class Leave the name off we are only going to use this once 6
Single file, multiple classes The java compiler will allow more than one class in a single file Account.java package mypacakge; class Account { public Account() { class Transactions { public Transactions() { Account.class Transaction.class 7
Inner Classes Java even allows the definition of a class INSIDE another class public class Account { public Account() { private class Transaction { public Transaction() { Can access fields in Account class! 8
Anonymous Inner Classes An inner class with no name Since it has no name, we must combine the DEFINITION of the class with the INSTANTIATION of the class Note that even though the class does not have a NAME, it can still have a TYPE (that looks like a name) AnonInner innerref = new AnnonInner() { public void innermethod() { ; innerref.innermethod(); innerref is our only way to access the AnnonInner class 9
Using an Interface as a Type Instead of using a new type name, just use an Interface name Runnable runref = new Runnable() { void run() { ; javax.swing.swingutilities.invokelater(runref)); 10
Bypass the reference variable javax.swing.swingutilities.invokelater( new Runnable() { void run() { ; ); 11
Anonymous Inner Classes for functions With anonymous inner classes, we can ALMOST make it look like we are actually passing a function to invokelater. Really, it s just syntactic trickery. We are really still passing a reference to an object in a class that supports the Runnable interface, and so has a run method that can be invoked 12
Another example of function We made Account comparable by adding a compareto method Sort uses compareto to determine how two objects in the same class are related (<, =, >) What about a class that does not implement Comparable? What if we could write some code OUTSIDE the class to tell sort how two objects are related? 13
Functional Needs We need a function that compares two items, and returns an integer If functions were first class citizens, we could define such a function and send it as an argument Or we could come up with an object whose class has such a function 14
The Comparator Interface Used to compare two objects Supports a generic type Comparator<T> Requires one method int compare(t obj1,t obj2) Reference to the comparator object passed as a parameter to sort When sort has objects A and B, it invokes compref.compare(a,b) to figure out whether A<B, A==B, or A>B Confused? Let s do an example. 15
java.awt.geom.ellipse2d.double An ellipse has fields: x, y, width, and height (x, y) width height Slides 6 16
Let s sort arrays of ellipses by area Area = π width height 4 17
Make a class that supports comparator import java.awt.geom.ellipse2d; import java.util.comparator; public class MyEllipseComp implements Comparator<Ellipse2D.Double> { @Override public int compare(ellipse2d.double arg0, Ellipse2D.Double arg1) { int retval = 0; double area0 = Math.PI*arg0.width*arg0.height/4; double area1 = Math.PI*arg1.width*arg1.height/4; if(area0 < area1) retval = -1; else if(area0 > area1) retval = 1; return retval; 18
Make an array of ellipses (circles) Ellipse2D.Double[ ] circles = { new Ellipse2D.Double(4, 7, 12, 12), new Ellipse2D.Double(5, 11, 16, 16), new Ellipse2D.Double(2, 65, 10, 10), new Ellipse2D.Double(7, 12, 1, 1), new Ellipse2D.Double(12, 6, 15, 15), new Ellipse2D.Double(34, 2, 14, 14) ; 19
Sort the array with a comparator Arrays.sort(circles, new MyEllipseComp()); for(ellipse2d e : circles) { System.out.print(e.getWidth() + " "); System.out.println(); Prints: 1.0 10.0 12.0 14.0 15.0 16.0 20
Note common factors import java.awt.geom.ellipse2d; import java.util.comparator; public class MyEllipseComp implements Comparator<Ellipse2D.Double> { @Override public int compare(ellipse2d.double arg0, Ellipse2D.Double arg1) { int retval = 0; double area0 = Math.PI*arg0.width*arg0.height/4; double area1 = Math.PI*arg1.width*arg1.height/4; if(area0 < area1) retval = -1; else if(area0 > area1) retval = 1; return retval; 21
Simplify remove common factors import java.awt.geom.ellipse2d; import java.util.comparator; public class MyEllipseComp implements Comparator<Ellipse2D.Double> { @Override public int compare(ellipse2d.double arg0, Ellipse2D.Double arg1) { int retval = 0; double area0 = arg0.width*arg0.height; double area1 = arg1.width*arg1.height; if(area0 < area1) retval = -1; else if(area0 > area1) retval = 1; return retval; 22
Example Anonymous Inner Class Comparator<Ellipse2D.Double> comp = new Comparator<Ellipse2D.Double>() { @Override public int compare(ellipse2d.double arg0, Ellipse2D.Double arg1) { int retval=0; double area0 = arg0.width*arg0.height; double area1 = arg1.width*arg1.height; if(area0 < area1) retval = -1; else if(area0 > area1) retval = 1; return retval; Arrays.sort(circles, comp); 23
Or, skip the reference variable Arrays.sort(circles, new Comparator<Ellipse2D.Double>() { @Override public int compare(ellipse2d.double arg0, Ellipse2D.Double arg1) { int retval=0; double area0 = arg0.width*arg0.height; double area1 = arg1.width*arg1.height; if(area0 < area1) retval = -1; else if(area0 > area1) retval = 1; return retval; ); 24
Data Orientation When all you have is a hammer, everything looks like a nail When all you have is data, everything looks like an int 25
Functions as a First Class Citizen If there was just some way of packaging the compare function And then passing that function as an argument to sort Then we wouldn t need an object We wouldn t need a Comparitor interface We wouldn t need an anonymous inner class or an explicit class We wouldn t need to pass data to the sort method But how can we package a function? 26