Java Lambda Expressions - JDK 8

Outline

References:


Simple ActionListener method

Java 8 has added support for a feature called lambda expressions, which, among other cool things, can reduce the size of the listeners a lot:

    jbr.addActionListener (e -> readFile());
    jbd.addActionListener (e -> displayCave ());
    jbs.addActionListener (e -> search ((String)(jcb.getSelectedItem()), jtf.getText()));
       
//         jbr.addActionListener ( new ActionListener () {
//                 public void actionPerformed (ActionEvent e) {
//                     readFile ();
//                 } // end required method
//             } // end local definition of inner class
//         ); // the anonymous inner class
//        
//         jbd.addActionListener ( new ActionListener () {
//                 public void actionPerformed (ActionEvent e) {
//                     displayCave ();
//                 } // end required method
//             } // end local definition of inner class
//         ); // the anonymous inner class
//        
//         jbs.addActionListener ( new ActionListener () {
//                 public void actionPerformed (ActionEvent e) {
//                     search ((String)(jcb.getSelectedItem()), jtf.getText());
//                 } // end required method
//             } // end local definition of inner class
//         ); // the anonymous inner class

Custom JButton

// File: LambdaExampleND.java
// Date: Sep 13, 2015
// Author: Nicholas Duchon
// Purpose: show how to consume a lambda expression
// Note: Motivated by an example by
//    Patrick Smith, CMSC 335, Fall, 2015

import java.util.function.Consumer;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JTextField;

import java.awt.GridLayout;
import java.awt.BorderLayout;

import java.awt.event.ActionEvent;

class ButtonND extends JButton {
   public static final long serialVersionUID = 94385798;
 
   public ButtonND (String n, Consumer<ActionEvent> ae) {
      super (n);
      addActionListener(e -> ae.accept (e));
   } // end constructor
} // end class ButtonND

public class LambdaExampleND extends JFrame {
   public static final long serialVersionUID = 3498;
   JTextField jtf = new JTextField ();
  
   public LambdaExampleND () {
      super("LambdaExampleND");

      String [] options = {
            "a", "b", "c", "d", "e", "f"
            , "g", "h", "i", "j", "k", "l"
            , "m", "n", "o"
            , "Camel", "Dog", "Peacock"
            }; // end String options
     
      JPanel jp = new JPanel();
     
      for (String s: options)
         jp.add (new ButtonND (s, e -> clickN (s)));
  
      jp.setLayout(new GridLayout(0, 3));
     
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      add (jp , BorderLayout.SOUTH);
      add (jtf, BorderLayout.NORTH);
     
      setLocationRelativeTo (null);
      pack ();
      setVisible(true);
   } // end constructor

   void clickN (String n) {
      jtf.setText ("Hit: " + n);
   } // end method clickN

   public static void main(String args[]) {
      new LambdaExampleND ();
   } // end main
} // end class LambdaExampleND

Sorting with lambdas and ArrayList

The image:

// File: Sort002.java
// Author: Nicholas Duchon
// Date: Sep 24, 2015
// Start with MyIFm.java and simplify with lambda expressions
//
// NOW:
//   > MyButton class added to simplify button setup

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.GridLayout;

import java.util.ArrayList;
import java.util.Collections;

interface MKI <X> {
   ArrayList <X> makeRandom (int a, int b);}
 
public class Sort002 <T extends Comparable <T> & MKI <T> > extends JFrame {
   static final long serialVersionUID = -3804044462946113366L;
 
   static int startNumber = 20;
   static int maxNumber = 1000;
   static String colLabel = String.format ("%10s%10s%10s%10s\n", "One", "Two", "Three", "Four");
 
   ArrayList <T> arr; T tint;
 
// input and output text areas
   private JTextField asf    = new JTextField("" + startNumber);
   private JTextField asg    = new JTextField("" + maxNumber);
   private JTextArea  ioArea = new JTextArea (10,10);
 
   public Sort002 (T t) {
      tint = t;
      fillArray(startNumber);
      setSize (500,500);
  
   // TextArea always get auto scrolls
      ioArea.setEditable (true);
      ioArea.setFont (new java.awt.Font ("Monospaced", java.awt.Font.PLAIN, 12));
      JScrollPane spTextIO = new JScrollPane (ioArea);
  
   // create and add buttons to control panel
      JPanel textIObp = new JPanel (new GridLayout (2, 4)); // button panel
      textIObp.add(asf);
      asf.addActionListener (e -> fillArray (asf.getText()));
      textIObp.add(asg);
      asg.addActionListener (e -> fillArray (asf.getText(), asg.getText()));
      textIObp.add(new MyButton002 ("New Array"    , e -> fillArray (asf.getText())));
      textIObp.add(new MyButton002 ("Shuffle Array", e -> {Collections.shuffle(arr); display();}));
      textIObp.add(new MyButton002 ("Sort on one"  , e -> sortMe (1)));
      textIObp.add(new MyButton002 ("Sort on two"  , e -> sortMe (2)));
      textIObp.add(new MyButton002 ("Sort on three", e -> sortMe (3)));
      textIObp.add(new MyButton002 ("Sort on four" , e -> sortMe (4)));
  
      add (spTextIO, BorderLayout.CENTER);
      add (textIObp, BorderLayout.SOUTH);
      setLocationRelativeTo (null);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setVisible (true);
  
      display();
   } // end T constructor
  
   public void sortMe (int i) {
      MyRecord002.column = i;
      Collections.sort (arr);
      display ();
   } // end sortMe
 
   void fillArray (int size) {
      // interface method cannot be static, thus the dummy tint.
      arr = tint.makeRandom (size, maxNumber);
   } //end method fillArray
 
   void fillArray (String st) {
      try {
         fillArray (Integer.parseInt(st.trim()));
         display();
      }
      catch (NumberFormatException ex) {
         ioArea.setText ("Bad number format");
      } // end try/catch
   } //end method fillArray
 
   void fillArray (String st, String su) {
      try {
         maxNumber = Integer.parseInt(su.trim());
         fillArray (st);
      }
      catch (NumberFormatException ex) {
         ioArea.setText ("Bad number format");
      } // end try/catch
   } //end method fillArray
 
   public void display () {
      ioArea.setText (colLabel);
      for (T m: arr)
         ioArea.append(m + "\n");
      ioArea.append ("done!");
      ioArea.setCaretPosition (0);
   } // end method display
  
   public static void main (String args[]) {
      Sort002 <MyRecord002> m = new Sort002 <> (new MyRecord002(1,1,1,1));
   } // end main
 
} // end class MyIFm

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

class MyRecord002 implements Comparable <MyRecord002>, MKI <MyRecord002> {
   static java.util.Random rn = new java.util.Random();
   static int column = 1;
 
   int one, two, three, four;
 
   public MyRecord002 (int p1, int p2, int p3, int p4) {
      one    = p1;
      two    = p2;
      three  = p3;
      four   = p4;
   } // end 4 int parameter constructor
  
   public ArrayList <MyRecord002> makeRandom (int size, int max) {
      ArrayList <MyRecord002> arr = new ArrayList <> (size);
      for (int i = 0; i < size; i++)
         arr.add (new MyRecord002 (i, rn.nextInt(max), rn.nextInt(max), rn.nextInt(max)));
      return arr;
   } // end method makeRandom
  
   public int compareTo (MyRecord002 m) {
      switch (column) {
         case 2:
            return two - m.two;
         case 3:
            return three - m.three;
         case 4:
            return four - m.four;
         case 1:
         default:
            return one - m.one;
      }
   } // end compareTo
  
   public String toString () {
      return String.format ("%10d%10d%10d%10d", one, two, three, four);
   } // end method toString
 
} // end class MyRecord
 
class MyButton002 extends JButton {
   public static final long serialVersionUID = 92349873;

   public MyButton002 (
          String ps ,       // the String parameter, the label of the button
                           // the following is the second parameter
                           // the function to call when this button is pressed
                           // note that each button in the definitions above calls a different method
          java.util.function.Consumer
            < java.awt.event.ActionEvent > ae
          ) {
      super (ps);          // tells the parent class what to use as the label for this button
                           // the following is the lambda expression used to call the method
                           // parameter.

      addActionListener(e -> ae.accept (e));
   } // end MyButton constructor

} // end class MyButton


The :: operator - action listeners

As the Oracle Language Specification points out, this operator can be used to reference the invocation of a method without actually performing the invocation.
There are lots of examples in section 15.13, and here are a few that seem interesting in our classes.

This code uses the class FrameND.java to create the basic JFrame:

// File: Colons001.java
// Date: Nov 9, 2017
// Author: Nicholas Duchon
// Purpose: experiments with :: operator
//    method reference expressions and how to use them

import java.awt.Color;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Colons001 extends FrameND {
   public static final long serialVersionUID = 123; // ND: junk
  
   JButton jbA = new JButton ("Press me A");
   JButton jbB = new JButton ("Press me B");
   JButton jbC = new JButton ("Press me C");
  
   One one = new One ();
  
   public Colons001 () {
      super (":: Experiments", 200, 300);
      JPanel jp = new JPanel ();
      jp.setBackground (Color.yellow);
      jp.add (jbA);
      jp.add (jbB);
      jp.add (jbC);
      add (jp, BorderLayout.CENTER);
     
      jbA.addActionListener (e -> System.out.println ("hi"));
      jbB.addActionListener (this::fun   ); // object::function format
      jbC.addActionListener (one ::funOne); // object::function format
     
      validate ();
  
} // end constructor
 
  // Since addActionListener is an interface defing ONE method
  // and that method has a parameter of type ActionEvent
  // the following method MUST have the same parameter list
  // in order to use the this::fun protocol
   void fun (java.awt.event.ActionEvent e) {
      System.out.println (" - Having fun");
   } // end method run
  
   public static void main (String [] args) {
      Colons001 c = new Colons001 ();
  
} // end main
} // end class Colons001

class One {
   void funOne (java.awt.event.ActionEvent e) {
      System.out.println ("Event: " + e.toString().replace (",", "\n"));
  
} // end funOne
} // end class One


Notes:


The :: operator - sorting

Here's some confusing code:

// File: Colons002.java
// Date: Nov 9, 2017
// Author: Nicholas Duchon
// Purpose: sorting with method references

import java.util.Arrays;

// class MyComp implements java.lang.Comparable <String> {
//    public int compareTo (String s) {
//       return ((String)this).compareTo (s);
//    } // end compare method
// } // end class MyComp

// the following does not seem to work at all
// class MyComp implements java.util.Comparator <String> {

class MyComp { // (1) this works with (1) below,
   public static int compare (String s, String t) {
      return t.replace ("t", "g").compareTo(s.replace("t", "g"));
   } // end compare method
} // end class MyComp

public class Colons002 {

   public static void main (String [] args) {
      System.out.println (Arrays.deepToString (list).replace(",", "\n"));

// (1) the following is ok, but note that MyComp is NOT implementing Comparator!  
// Come  to think of it, it is not clear why the following works either
// Since MyComp does not implement Comparable, which is supposedly the requirement
// for the Arrays.sort method
// --- sort is a static method, so putting this code into an instance context doesn't
// change the need for static declaration of MyComp.compare
      Arrays.sort (list, MyComp::compare);

// The attempts to use classes the implement Comparator and Comparable are
// annoying failures, with compiler errors related to not being
// able to resolve the types of various references
// or not being able to find MyComp.compare (String, String)

// After some more thought, it is hard to understand why the compareTo (T, T)
// method of Comparable <T> is not static - what sense does c make in c.compareTo (T a, T b)?

//       Arrays.sort (list, (x, y) -> myComp (x, y)); // ok
//       Arrays.sort (list, (x, y) -> y.compareTo (x));
//       Arrays.sort (list, (x, y) -> MyComp.compare (x, y));

// Note that the following is not (?) using the implements Comparable interface in the String class
// but the definition of the Arrays.sort method says it requires a Comparator <? super T>
// as the second parameter, and I don't see how this gets past the compiler
//       Arrays.sort (list, String::compareTo);
  
      System.out.println ("-------- sorted ------------");
      System.out.println (Arrays.deepToString (list).replace(",", "\n"));
  
} // end main.
  
   static int myComp (String a, String b) {
      return b.compareTo (a);
  
} // end myComp
  
   static String [] list = {"this",   "is", "a", "discussion", "for", "students", "to", "ask", "the",
   "professor", "questions", "note", "your", "posts", "will", "be", "visible", "to", "your", "classmates",
   "if", "you", "have", "a", "specific", "question", "about", "your", "coursework", "or", "your",
   "grade", "please", "use", "the", "professor", "preferred", "method", "of", "contact"};

} // end class Colons002

Notes?


End - Sep 13, 2015