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...
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> {
...
<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 { |
| 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