1 lambda 介绍
The most notable new feature in JDK 8 is the Lambda Expression, which provides a concise notation to construct an instance implementing a "Single-Abstract-Method Interface". In JDK 8, a "Single-Abstract-Method Interface" (i.e., an interface containing only one abstract method) is known as a "Functional Interface".
JDK 8 also retrofitted the Collection framework, with Lambda expression, functional interfaces and the introduction of streams API, to support chaining and aggregate operations (or filter-map-reduce) in functional programming.
举例1
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CounterLambda extends JFrame {
JTextField tfCount;
int count = 0;
public CounterLambda() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(new JLabel("Counter"));
tfCount = new JTextField(count + "", 8);
tfCount.setEditable(false);
cp.add(tfCount);
// Using an anonymous inner class as ActionEvent handler
JButton btnUp = new JButton("Count Up");
cp.add(btnUp);
btnUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tfCount.setText(++count + "");
}
});
// Using a Lambda Expression to return an instance of ActionListener
JButton btnDown = new JButton("Count Down");
cp.add(btnDown);
btnDown.addActionListener(e -> tfCount.setText(--count + ""));
setSize(400, 100);
setVisible(true);
}
public static void main(String[] args) {
// Using Lambda Expression to return a Runnable instance
SwingUtilities.invokeLater(() -> new CounterLambda());
}
}
The Runnable
interface contains a single abstract
method, defined as follows:
@FunctionalInterface
public interface Runnable {
void run(); // public abstract
}
We can create a Runnable
object via anonymous inner class (Pre-JDK 8) or Lambda Expression (JDK 8), as follows:
| |
举例 3: Functional Interface for Binary Operators
Let's define a Functional Interface to denote a binary operator (such as add or subtract), as follows:
@FunctionalInterface public interface MyIntBinaryOperator { int applyAsInt(int left, int right); }
In the following class, the method operate()
takes 2 int
's and an object of the above Functional Interface as parameters, and carries out the binary operation.
public class MyMathBinaryOperation { // Define instances of IntBinaryOperator for add, subtract, multiply and divide public MyIntBinaryOperator add = (a, b) -> a + b; public MyIntBinaryOperator sub = (a, b) -> a - b; public MyIntBinaryOperator mul = (a, b) -> a * b; public MyIntBinaryOperator div = (a, b) -> a / b; // Carry out the binary operation public int operate(int left, int right, MyIntBinaryOperator op) { return op.applyAsInt(left, right); } // Test Driver public static void main(String args[]){ MyMathBinaryOperation op = new MyMathBinaryOperation(); // Use pre-defined IntBinaryOperator System.out.println("8 + 9 = " + op.operate(8, 9, op.add)); System.out.println("8 - 9 = " + op.operate(8, 9, op.sub)); System.out.println("8 x 9 = " + op.operate(8, 9, op.mul)); System.out.println("8 / 9 = " + op.operate(8, 9, op.div)); // Use a custom IntBInaryOperator System.out.println("2 ^ 5 = " + op.operate(2, 5, (a, b) -> (int)Math.pow(a, b))); } }
2 最核心的语法解释:
Syntax and Usage of Lambda Expressions
Prior to JDK 8, to construct an instance that implements a Functional Interface requires many lines of codes. Lambda Expression provides a shorthand notation. Moreover, you can pass a lambda expression as a method argument (treating code as data), as shown in the above example.
Lambda Expression defines the "sole" method of a Functional Interface. It consists of 2 parts: parameters and method body, separated by ->
. The parameters are separated by commas and enclosed by parentheses. The parentheses can be omitted if there is only one parameter. The method body could be a statement or a block. The method name is omitted, as it is the sole abstract method of the Functional Interface. The parameters' type and the return type are also optional, as they can be inferred from the method signature.
The syntax is:
(arguments) -> (body)
For examples:
() -> statement // No argument and one-statement method body
arg -> statement // One argument (parentheses can be omitted) and method body
(arg1, arg2, ...) -> {
body-block
} // Arguments separated by commas and block body
(Type1 arg1, Type2 arg2, ...) -> {
method-body-block;
return return-value;
} // With arguments and block body
In other languages that support function variables or function objects (such as C++ and Python), Lambda is used to define an anonymous function. However, in JDK 8, Lambda expression is used to define the method implementation of an instance of a Single-Abstract-Method Interface?!
In fact, if you try to write:
int i = () -> 5;
// error: incompatible types: int is not a functional interface
But,
// Using Lambda expression to construct a Runnable instance.
// In other words, Lambda expression returns an instance of Function Interface
Runnable r1 = () -> System.out.println("run run()");
// Runnable is a functional interface
// Lambda expression is used to define the implementation of the abstract method run()
// Using Lambda expression to construct an ActionListener instance
ActionListener lis = e -> System.out.println("run actionPerformed()");
Java is an Object-oriented Programming language. Everything in Java are objects (except primitives for simplicity). Functions are not objects in Java (but part of an object), and hence, they cannot exist by themselves. Unlike other languages (such as C++, Python and JavaScript) functions can exist by themselves, and you can pass a function as a funtion's argument, and return a function from a funtion.
JDK 8's Functional Interface and Lambda Expression allow us to construct a "Function Object" in a one-liner (or a fewer lines of codes). However, it can be used only for objects with one method.