5. 新增Lambda表达式(函数式编程)

2014年oracle发布了jdk 8,在里面增加了lambda模块。于是java程序员又多了一种新的编程方式:函数式编程,也就是lambda表达式。

在JDK8之前,Java是不⽀持函数式编程的,所谓的函数编程,即可理解为将⼀个函数(也称为“行为”)作为一个参数进⾏传递,⾯向对象编程是对数据的抽象(各种各样的POJO类),而函数式编程则是对行为的抽象(将行为作为一个参数进行传递)。

5.1. Lambda表达式

5.1.1. 案例一:创建线程

public static void main(String[] args) {
//1. 普通方式创建线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("普通线程");
}
}).start();

//2. lambda方式创建线程
new Thread(()->System.out.println("Lambda线程")).start();
}

Runnable接口源码:

@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}

5.1.2. 案例二:集合容器排序

// 1. 普通方式
List<String> strList = Arrays.asList("b", "a", "c", "d");
Collections.sort(strList, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
for (String s : strList) {
System.out.print(s + ",");// a,b,c,d,
}

// 2. lambda方式
List<String> strList2 = Arrays.asList("b", "a", "c", "d");
Collections.sort(strList2, (s1, s2) -> s1.compareTo(s2));//或用以下注释方式
// Collections.sort(strList2, (s1, s2) -> {
// return s1.compareTo(s2);
// });
for (String s : strList2) {
System.out.print(s + ",");// a,b,c,d,
}

Comparator接口源码:

@FunctionalInterface
public interface Comparator<T> {
/**
*
* @param o1 the first object to be compared.
* @param o2 the second object to be compared.
* @return a negative integer, zero, or a positive integer as the
* first argument is less than, equal to, or greater than the
* second.
* @throws NullPointerException if an argument is null and this
* comparator does not permit null arguments
* @throws ClassCastException if the arguments' types prevent them from
* being compared by this comparator.
*/
int compare(T o1, T o2);

//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
//其他非泛型T方法、static方法、default方法,这里省略
}

5.2. 自定义Lambda接口编程

函数式接口(Functional Interface) 是Java 8对一类特殊类型的接口的称呼。这类接口只定义了唯一的抽象方法的接口(除了隐含的Object对象的公共方法,因此最开始也就做SAM类型的接口(Single Abstract Method)。定义函数式接口的原因是在Java Lambda的实现中,开发组不想再为Lambda表达式单独定义一种特殊的Structural函数类型,称之为箭头类型(arrow type,依然想采用Java既有的类型(class, interface, method等)。原因是增加一个结构化的函数类型会增加函数类型的复杂性,破坏既有的Java类型,并对成千上万的Java类库造成严重的影响。权衡利弊,因此最终还是利用SAM 接口作为 Lambda表达式的目标类型。另外对于函数式接口来说@FunctionalInterface并不是必须的,只要接口中只定义了唯一的抽象方法的接口那它就是一个实质上的函数式接口,就可以用来实现Lambda表达式。

自定义Lambda接口:

@FunctionalInterface
public interface CalculateFunction<R, T> {

/**
* 操作o1和o2
* @param o1 操作数1
* @param o2 操作数2
* @return
*/
R operator(T o1, T o2);

}

直接匿名内部类方式调用:

CalculateFunction<Integer, Integer> cal = new CalculateFunction<Integer, Integer>() {
@Override
public Integer operator(Integer o1, Integer o2) {
return o1-o2;
}
};
Integer res = cal.operator(10, 12);
System.out.println(res);//-2

定义中间函数,间接调用:

public static void main(String[] args) {
//匿名内部类方式调用
int x = calculate(10, 12, new CalculateFunction<Integer, Integer>() {
@Override
public Integer operator(Integer o1, Integer o2) {
return o1-o2;
}
});
System.out.println(x);//-2

//Lambda方式调用
int calRes = calculate(10, 12, (a, b)-> a-b);
System.out.println(calRes);//-2
int calRes2 = calculate(10, 12, (a, b)-> a*b);
System.out.println(calRes2);//120
}

/**
* 操作o1和o2
* @param o1 操作数1
* @param o2 操作数2
* @param cal 自定义的Lambda接口
* @return
*/
public static int calculate(int o1, int o2,
CalculateFunction<Integer, Integer> cal) {
return cal.operator(o1, o2);
}

Lambda表达式必须先定义接口,创建相关方法之后才可使用,这样做十分不便,其实java8已经内置了许多接口,所以一般很少会有用户去定义新的函数式接口。