CSC447

Concepts of Programming Languages

Nested Classes

Instructor: James Riely

Nested Classes

  • Added in Java 1.1 (1997)
  • Improved in Java 1.8 (2014)
  • Used in, for example:
    • Graphical User Interfaces
    • Concurrency APIs
    • Collections processing

Java Graphics 1.0


public class Swing1 extends Frame {
  public static void main (String[] args) { new Swing1 (); }
  int count = 0;
  public Swing1 () {
    setSize (200, 100); setLayout (new FlowLayout ());
    Button button = new Button ("Go"); add (button);
    Label out = new Label ("000", Label.CENTER); add (out);   
    button.addActionListener (new MyActionListener(this, out));
    setVisible (true);
  }
}

class MyActionListener implements ActionListener {
  private Swing1 parent;
  private Label out;
  public MyActionListener (Swing1 parent, Label out) { this.parent = parent; this.out = out; }
  public void actionPerformed (ActionEvent e) {
    parent.count += 1;
    out.setText (String.format ("%03d", parent.count));
    out.repaint ();
  }
}

Java Graphics 1.1


public class Swing2 extends Frame {
  public static void main (String[] args) { new Swing2 (); }
  int count = 0;
  public Swing2 () {
    setSize (200, 100); setLayout (new FlowLayout ());
    Button button = new Button ("Go"); add (button);
    Label out = new Label ("000", Label.CENTER); add (out);   
    button.addActionListener (new ActionListener() {
      public void actionPerformed (ActionEvent e) {
        count += 1;
        out.setText (String.format ("%03d", count));
        out.repaint ();
      }
    });
    setVisible (true);
  }
}

Java Graphics 1.8


public class Swing3 extends Frame {
  public static void main (String[] args) { new Swing3 (); }
  int count = 0;
  public Swing3 () {
    setSize (200, 100); setLayout (new FlowLayout ());
    Button button = new Button ("Go"); add (button);
    Label out = new Label ("000", Label.CENTER); add (out);   
    button.addActionListener (e -> {
      count += 1;
      out.setText (String.format ("%03d", count));
      out.repaint ();
    });
    setVisible (true);
  }
}

Java Threads 1.0


class Run1 {
    public static void main (String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread (new MyRunnable (i)).start ();
        }
    }
}

class MyRunnable implements Runnable {
    private int x;
    public MyRunnable (int x) { this.x = x; }
    public void run () {
        while (true) 
            System.out.print (x);
    }
}

3331100000000000000000000000000022222222222222224444222...
          

Java Threads 1.1


class Run2 {
  public static void main (String[] args) {
    for (int i = 0; i < 5; i++) {
      int x = i;
      new Thread (new Runnable () {
          public void run () {
            while (true) 
              System.out.print (x);
         }
        }).start ();
    }
  }
}

3331100000000000000000000000000022222222222222224444222...
          

Java Threads 1.8


class Run3 {
  public static void main (String[] args) {
    for (int i = 0; i < 5; i++) {
      int x = i;
      new Thread (() -> {
            while (true) 
              System.out.print (x);
          }).start ();
    }
  }
}

3331100000000000000000000000000022222222222222224444222...
          

Java Threads 1.8


class Run4 {
  public static void main (String[] args) {
    for (int i = 0; i < 5; i++) {
      new Thread (() -> {
            while (true) 
              System.out.print (i);
          }).start ();
    }
  }
}

Run4.java:6: error: local variables referenced from a lambda expression must be final or effectively final
              System.out.print (i);
                                ^
          

Java Threads 1.1


class Run5 {
  public static void main (String[] args) {
    for (int i = 0; i < 5; i++) {
      new Thread (new Runnable () {
          public void run () {
            while (true) 
              System.out.print (i);
         }
        }).start ();
    }
  }
}

Run5.java:7: error: local variables referenced from an inner class must be final or effectively final
              System.out.print (i);
                                ^
          

Some languages allows this

Python


import threading

for i in range(5):
  def worker():
    while True: 
      print(i, end="")

  threading.Thread(target=worker).start()
          

4444444444444444444444444444444444444444444444444444444...
          

sad

Some languages allows this

Python


import threading

for i in range(5):
  def worker():
    x = i
    while True: 
      print(x, end="")

  threading.Thread(target=worker).start()
          

3331100000000000000000000000000022222222222222224444222...
          

Some languages allows this

Perl


use threads;
my $i;
for ($i = 0; $i < 5; $i++) {
  my $th = threads->create (sub {
    while (1) { print $i; } 
  });
  $th->detach();
}
sleep (1);
          

5555555555555555555555555555555555555555555555555555555...
          

sad

Some languages allows this

Perl


use threads;
my $i;
for ($i = 0; $i < 5; $i++) {
  my $x = $i
  my $th = threads->create (sub {
    while (1) { print $x; } 
  });
  $th->detach();
}
sleep (1);
          

3331100000000000000000000000000022222222222222224444222...
          

Some languages allows this

Scala


for i <- (1 to 4).toList do
  new Thread (() => {
    while true do print (i) 
  }).start 
          

3331100000000000000000000000000022222222222222224444222...
          

Implementing Nested Classes

  • javac (the compiler) supports nested classes
  • java (the JVM) does not
  • Compiler creates new classes with $ in name

Implementing Nested Classes


    for (int i = 0; i < 5; i++) {
      int x = i;
      new Thread (new Runnable () {
          public void run () {
            while (true) 
              System.out.print (x);
         }
        }).start ();
    }
          

$ javac Run2.java 
$ javap -private 'Run2$1' 
Compiled from "Run2.java"
final class Run2$1 implements java.lang.Runnable {
  final int val$x;
  Run2$1(int);
  public void run();
}
          

Recall the 1.0 implementation


    for (int i = 0; i < 5; i++) {
      new Thread (new MyRunnable (i)).start ();
    }

class MyRunnable implements Runnable {
    private int x;
    public MyRunnable (int x) { this.x = x; }
    public void run () {
        while (true) 
            System.out.print (x);
    }
}

Java Functional Interface

  • Java 8 introduced lambda expressions
  • How to integrate this new feature with older APIs?

    button.addActionListener (new ActionListener() {
      public void actionPerformed (ActionEvent e) {
        count += 1;
        out.setText (String.format ("%03d", count));
        out.repaint ();
      }
    });
          

    button.addActionListener (e -> {
      count += 1;
      out.setText (String.format ("%03d", count));
      out.repaint ();
    });
          

Java Functional Interface

  • Java reference types marked as
    This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
  • @FunctionalInterface annotation

Java Functional Interface


@FunctionalInterface
interface Function<T,R> { 
  public R apply (T x);
}
          

Function<Integer,Integer> f = new Function<> () {
  public Integer apply (Integer x) {
    return x + 1;
  }
};
          

Function<Integer,Integer> f = x -> x + 1;
          

Collections Processing

  • Java map method takes a Function

package java.util.stream;

interface Stream<T> {
  ...
  // Returns a stream consisting of the results of applying
  // the given function to the elements of this stream
  <R> Stream<R> map (Function<? super T,? extends R> mapper);
  ...
}
          

Collections Processing

  • Provide Stream view of List in order to use map

public class Nested {
  public static void main (String[] args) {
    List<Integer> l = new ArrayList<> ();
    Stream<Integer> s = l.stream();
    l.add (1); l.add (2); l.add (3);
    s.map (x -> x + 1)
     .collect (Collectors.toList ())
     .forEach (x -> System.out.format ("%2d ", x));
  }
}
          

 2  3  4
          

Nonfunctional interfaces in Java

  • Some event interfaces have multiple methods
  • Can't use lambda notation

@FunctionalInterface
interface MouseListener { /* from java.awt.event */
  void mouseClicked (MouseEvent e);
  void mouseEntered (MouseEvent e);
  void mouseExited (MouseEvent e);
  void mousePressed (MouseEvent e);
  void mouseReleased (MouseEvent e);
}
          

MouseListener.java:1: error: Unexpected @FunctionalInterface annotation
@FunctionalInterface
^
  MouseListener is not a functional interface
    multiple non-overriding abstract methods found in interface MouseListener