Java lambda表达式

1. Java函数式接口

Java实现函数式编程的方式是函数式接口(functional interface),函数式接口简单来说,是只包含一个抽象方法的接口。比如Java标准库中的java.lang.Runnable和 java.util.Comparator都是典型的函数式接口。
java 8提供 @FunctionalInterface作为函数式接口的注解,该注解非强制使用,主要防止团队的其他人员错误地往接口中添加新的方法。

2. lambda表达式

lambda表达式是匿名方法,是函数式接口的匿名实现。
使用lambda表达式实现Runnable例子:

// 使用匿名内部类  
new Thread(new Runnable() {  
    public void run() {  
        System.out.println("Hello world !");  
    }  
}).start();    
// 使用 lambda 表达式
new Thread(() -> System.out.println("Hello world !")).start();

3. lambda语法

(parameters) -> expression
或者
(parameters) -> { statements; }

JButton jb=new JButton();
jb.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("press button");
    }
});
jb.addActionListener((ActionEvent e)->{System.out.println("press button");});
jb.addActionListener((e)->{System.out.println("press button");});
jb.addActionListener((x)->System.out.println("press button"));
jb.addActionListener(x->System.out.println("press button"));

为了更好的支持lambda,Java8引入了一个新包java.util.function,它里面包含了常用的函数式接口,例如:

Predicate——接收T对象并返回boolean
Consumer——接收T对象,不返回值
Function——接收T对象,返回R对象
Supplier——提供T对象(例如工厂),不接收值
UnaryOperator——接收T对象,返回T对象
BinaryOperator——接收两个T对象,返回T对象

在参数为这些接口的地方,我们就可以直接使用lambda表达式了!

4. 方法引用(Method references)

lambda表达式允许我们定义一个匿名方法,并允许我们以函数式接口的方式使用它。我们也希望能够在已有的方法上实现同样的特性。

方法引用和lambda表达式拥有相同的特性(例如,它们都需要一个目标类型,并需要被转化为函数式接口的实例),不过我们并不需要为方法引用提供方法体,我们可以直接通过方法名称引用已有方法。
以下面的代码为例,假设我们要按照name为Person数组进行排序:

class Person {
  private final String name;
  private final int age;

  public int getAge() { return age; }
  public String getName() {return name; }
  ...
}

Person[] people = ...
Comparator byName = Comparator.comparing(p -> p.getName());
Arrays.sort(people, byName);

在这里我们可以用方法引用代替lambda表达式:

Comparator byName = Comparator.comparing(Person::getName);

方法引用的形式
方法引用的标准形式是:类名::方法名。(注意:只需要写方法名,不需要写括号)

有以下四种形式的方法引用:

引用静态方法
引用某个对象的实例方法
引用某个类型的任意对象的实例方法
引用构造方法

  • 引用静态方法
    ContainingClass::staticMethodName
    例子: String::valueOf,对应的Lambda:(s) -> String.valueOf(s)
    比较容易理解,和静态方法调用相比,只是把.换为::
  • 引用特定对象的实例方法
    containingObject::instanceMethodName
    例子: x::toString,对应的Lambda:() -> this.toString()
    与引用静态方法相比,都换为实例的而已
  • 引用特定类型的任意对象的实例方法
    ContainingType::methodName
    例子: String::toString,对应的Lambda:(s) -> s.toString()
    实例方法要通过对象来调用,方法引用对应Lambda,Lambda的第一个参数会成为调用实例方法的对象。
  • 引用构造函数
    ClassName::new
    例子: String::new,对应的Lambda:() -> new String()
    构造函数本质上是静态方法,只是方法名字比较特殊。

写个例子帮本节内容串一下帮助理解:

class Person {
    Integer age;
    public static int compareByAge(Person a,Person b){return a.age.compareTo(b.age);}
    public int compareByAge2(Person b){return age.compareTo(b.age);}

    public static int compareBy18(Person p){return p.age.compareTo(18);}
    public int compareBy14(){return age.compareTo(14);}
}
public void sort(){
    Person [] persons=new Person[10];
    //使用匿名类
    Arrays.sort(persons, new Comparator() {
                public int compare(Person o1, Person o2) {
                    return o1.age.compareTo(o2.age);
                }
     });
    //使用lambda表达式
    Arrays.sort(persons, (o1, o2) -> o1.age.compareTo(o2.age));
    //使用lambda表达式和类的静态方法
    Arrays.sort(persons, (o1, o2) -> Person.compareByAge(o1,o2));
    //使用lambda表达式和实例方法
    Arrays.sort(persons, (o1, o2) -> o1.compareByAge2(o2));

    //使用方法引用
    //引用的是类的静态方法
    Arrays.sort(persons, Person::compareByAge);
    //引用特定类型的任意对象的实例方法
    Arrays.sort(persons, Person::compareByAge2);
    //引用的是类的静态方法
    Arrays.sort(persons,Comparator.comparing(Person::compareBy18));
    //引用特定类型的任意对象的实例方法
    Arrays.sort(persons,Comparator.comparing(Person::compareBy14));
}

`

你可能感兴趣的:(Java lambda表达式)