Slide navigation: Forward with space bar, → arrow key, or PgDn. Backwards with ← or PgUp.
Arrays.sort
sorts an array if the element class conforms to the Comparable
interface.public interface Comparable { int compareTo(Object other); // automatically public }
compareTo
method.public class Employee implements Comparable { public int compareTo(Object otherObject) { Employee other = (Employee) otherObject; return Double.compare(salary, other.salary); } . . . }
compareTo
method returns:
otherObject
should come before this object.Comparable
interface:
class Employee implements Comparable<Employee> { public int compareTo(Employee other) { return Double.compare(salary, other.salary); } . . . }
if (a[i].compareTo(a[j]) > 0) { // rearrange a[i] and a[j] . . . }
a[i].compareTo(a[j])
is valid?a
is declared to be Comparable[]
, then a[i]
has a compareTo
method:
public static void sort(Comparable[] a)
x = new Comparable(. . .); // Error
Comparable x; // OK
x = new Employee(. . .); // OK provided Employee implements Comparable
instanceOf
check:
if (anObject instanceof Comparable) { . . . }
public interface Moveable { void move(double x, double y); } public interface Powered extends Moveable { double milesPerGallon(); }
public interface Moveable { . . . double SPEED_LIMIT = 95; // automatically public static final }
public class Employee implements Comparable, Moveable { ... }
Comparable
into an abstract class?
abstract class Comparable // why not? { public abstract int compareTo(Object other); }
Employee
would simply extend it:
class Employee extends Comparable // why not? { public int compareTo(Object other) { . . . } }
Employee
already has a superclass?
class Employee extends Person, Comparable // Error
Collection
/Collections
, Path
/Paths
Paths
has a factory method get
to make a Path
object.Path
interface:
public interface Path { public static Path get(String first, String... more) { return FileSystems.getDefault().getPath(first, more); } . . . }
public interface Comparable<T> { default int compareTo(T other) { return 0; } // By default, all elements are the same }
public interface MouseListener { default void mouseClicked(MouseEvent event) {} default void mousePressed(MouseEvent event) {} ... }
public interface Collection { int size(); // An abstract method default boolean isEmpty() { return size() == 0; } . . . }
Collection
interface that has been in the JDK for many years.Bag
implementing Collection
.Collection
. (This actually happened with the stream
method in JDK 8.)Bag
no longer compiles—the change is not source compatible.Bag
class still works, as long as nobody calls the new method. (Otherwise, an AbstractMethodError
occurs.)default
method solves both problems.interface Person { default String getName() { return "John Q. Public"; }; } interface Named { default String getName() { return getClass().getName() + "_" + hashCode(); } }
getName
method.class Student implements Person, Named { public String getName() { return Person.super.getName(); } . . . }
Named.getName
is abstract, you must provide Student.getName
.abstract
.Person
is a superclass and Named
is an interface:
class Student extends Person implements Named { . . . }
Named.getName
is ignored.private
and private static
methods.default
, static
, private
, or private static
default
and static
methods of the same interface.public interface ActionListener { void actionPerformed(ActionEvent event); }
actionPerformed
method:
class TimePrinter implements ActionListener { public void actionPerformed(ActionEvent event) { System.out.println("At the tone, the time is " + new Date()); Toolkit.getDefaultToolkit().beep(); } }
ActionListener listener = new TimePrinter(); Timer t = new Timer(10000, listener); t.start();
Arrays.sort
sorts an array of Comparable
objects.
Comparable
?Arrays.sort
accepts a comparator:
public interface Comparator<T> { int compare(T first, T second); }
class LengthComparator implements Comparator<String> { public int compare(String first, String second) { return first.length() - second.length(); } }
Arrays.sort
:
String[] friends = { "Peter", "Paul", "Mary" }; Arrays.sort(friends, new LengthComparator());
Employee original = new Employee("John Public", 50000); Employee copy = original; copy.raiseSalary(10); // oops--also changed original
clone
method.Cloneable
interface indicates that a class provides a safe clone
method.Employee
is cloneable, then you can call
Employee copy = original.clone(); copy.raiseSalary(10); // OK--original unchanged
Cloneable
is an interface without methods:
public interface Cloneable {}
clone
method is a protected method of the Object
class.Object.clone
makes a “shallow” copy: a new object with the same fields.class Employee implements Cloneable { . . . public Employee clone() throws CloneNotSupportedException { Employee cloned = (Employee) super.clone(); cloned.hireDay = (Date) hireDay.clone(); return cloned; } }
CloneNotSupportedException
in a final clone
method. compare
method had to be called repeatedly to compute
first.length() - second.length()
(String first, String second) -> first.length() - second.length()
class LengthComparator implements Comparator<String> { public int compare(String first, String second) { return first.length() - second.length(); } }
(parameters) -> expression
{ }
and a return
statement:
(String first, String second) -> { if (first.length() < second.length()) return -1; else if (first.length() > second.length()) return 1; else return 0; }
() -> Toolkit.getDefaultToolkit().beep();
Comparator<String> comp = (first, second) -> first.length() - second.length();
ActionListener listener = event -> Toolkit.getDefaultToolkit().beep();
ActionListener
, Comparator
Arrays.sort(words, (first, second) -> first.length() - second.length()); Timer t = new Timer(1000, event -> { System.out.println("At the tone, the time is " + new Date()); Toolkit.getDefaultToolkit().beep(); });
java.util.function
package defines generic functional interfaces:
public interface Predicate<T> { boolean test(T t); . . . } public interface BiFunction<T, U, R> { R apply(T t, U u); }
ArrayList
has a removeIf
method that takes a predicate:
list.removeIf(e -> e == null);
Timer t = new Timer(1000, event -> System.out.println(event));
Timer t = new Timer(1000, System.out::println);
Arrays.sort(words, String::compareToIgnoreCase)
object::instanceMethod
Class::staticMethod
Class::instanceMethod
Person::new
is a reference to a Person
constructor.
s -> new Person(s)
Person
objects:
ArrayList<String> names = . . .;
Stream<Person> stream = names.stream().map(Person::new
);
List<Person> people = stream.collect(Collectors.toList());
map
method turns a stream of strings into a stream of Person
objects.int[]::new
is the same as the lambda expression n -> new int[n]
new T[n]
Person[] people = stream.toArray(Person[]::new);
public static void repeatMessage(String text, int delay) { ActionListener listener = event -> { System.out.println(text); Toolkit.getDefaultToolkit().beep(); }; new Timer(delay, listener).start(); }
repeatMessage("Hello", 1000); // Prints Hello every 1,000 milliseconds
text
variable is not defined in the lambda expression. repeatMessage
returns!public static void countDown(int start, int delay) { ActionListener listener = event -> { start--; // Error: Can't mutate captured variable System.out.println(start); }; new Timer(delay, listener).start(); }
public static void repeat(String text, int count) { for (int i = 1; i <= count; i++) { ActionListener listener = event -> System.out.println(i + ": " + text); // Error: Cannot refer to changing i new Timer(1000, listener).start(); } }
n
times:
repeat(10, () -> System.out.println("Hello, World!"));
public static void repeat(int n, Runnable action) { for (int i = 0; i < n; i++) action.run(); }
java.util.function
package:
public static void repeat(int n, IntConsumer action) { for (int i = 0; i < n; i++) action.accept(i); }
repeat(10, i -> System.out.println("Countdown: " + (9 - i)));
Comparator
interface has useful methods for creating and composing comparators.comparing
makes a comparator from a key extractor function:
Arrays.sort(people, Comparator.comparing(Person::getName));
comparingInt
or comparingDouble
to avoid boxing:
Arrays.sort(words, Comparator.comparingInt(String::length));
thenComparing
chains comparators:
Arrays.sort(people, Comparator.comparing(Person::getLastName) .thenComparing(Person::getFirstName));
public class TalkingClock { private int interval; private boolean beep; public TalkingClock(int interval, boolean beep) { . . . } public void start() { . . . } public class TimePrinter implements ActionListener // an inner class { . . . } }
TalkingClock
object does not have a TimePrinter
inside.public class TimePrinter implements ActionListener { public void actionPerformed(ActionEvent event) { System.out.println("At the tone, the time is " + new Date()); if (beep) Toolkit.getDefaultToolkit().beep(); } }
beep
?beep
field of the TalkingClock
object that created this TimePrinter
object..this
:
if (TalkingClock.this.beep) . . .
.
InnerClass outside the outer class.TalkingClock jabberer = . . .; TalkingClock.TimePrinter listener = jabberer.new TimePrinter();
TimePrinter
class in a single method.public void start() { class TimePrinter implements ActionListener { public void actionPerformed(ActionEvent event) { System.out.println("At the tone, the time is " + new Date()); if (beep) Toolkit.getDefaultToolkit().beep(); } } ActionListener listener = new TimePrinter(); Timer t = new Timer(interval, listener); t.start(); }
public void start(int interval, boolean beep)
public void start(int interval, boolean beep) { ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent event) { System.out.println("At the tone, the time is " + new Date()); if (beep) Toolkit.getDefaultToolkit().beep(); } }; Timer t = new Timer(interval, listener); t.start(); }
new SuperType(construction parameters) { inner class methods and fields }
class ArrayAlg { public static class Pair { public double first; public double second; } . . . public static Pair minmax(double[] values) { . . . return new Pair(min, max); // no creating object } }
ArrayAlg.Pair p = ArrayAlg.minmax(data);