继续lamdba,上篇Java8 Lamdba表达式 002讲了使用lamdba对集合元素进行排序,本篇讲述使用lamdba对集合元素过滤,示例代码沿用上篇:
001
public class SortingPlayer {
public static void main(String[] args) {
List<Player> playerList = new ArrayList<>();
playerList.add(new Player("Black", "White", 9));
playerList.add(new Player("John", "Hello", 2));
playerList.add(new Player("Machicel", "Jackson", 7));
playerList.add(new Player("Ani", "Hessius", 4));
playerList.add(new Player("Mark", "Towns", 3));
playerList.add(new Player("Huge", "Nana", 6));
}
}
class Player{
//类定义参考上篇
}
如001所示 创建一个集合 并在集合中添加几条元素。名字,分数。现在要对集合中的元素进行过滤,比如我要获取所有分数大于等于5的元素把它们放到另一个集合中,打印出符合条件的元素个数。
002
/**
* Specifying Filter Criteria on a Collection of Data
*/
List<Player> bigGoals = new ArrayList<>();
playerList.stream().filter(
p -> p.getGoals() >= 5)
.forEach(element -> bigGoals.add(element));
System.out.println("Number of Players Matching Criteria: " + bigGoals.size());
002中新建一个集合用来保存符合条件的元素,使用stream由于它包含易用的过滤功能。根据playerList生成stream然后在上面调用过滤功能,过滤的处理使用了lamdba表达式。lamdba表达式传递一个Player对象作为参数,然后根据条件goals>=5进行过滤,如果符合则往新建的集合添加这个元素。
通过以上的学习,我们应该对lamdba表达式有着深刻的印象了,它声明一个功能接口,也就是只有一个抽象方法的接口,并用lamdba表达式实现。或者使用Function<argument,return>定义,并实现。在传统的Java类中,也有着只有一个抽象方法的接口,比如新建一个线程java.util包下的Runnable接口,它里面只有一个run抽象方法。现在我们考虑使用lamdba表达式实现Runnable接口,并跟传统的实现进行比较。
003
public class RunnableCompare {
public static void main(String[] args) {
Runnable oldRunnable = new Runnable() {
@Override
public void run() {
int x = 5 * 3;
System.out.println("The variable using the old way equals: " + x);
}
};
Runnable lambdaRunnable = () -> {
int x = 5 * 3;
System.out.println("The variable using the lambda equals: " + x);
};
oldRunnable.run();
lambdaRunnable.run();
}
}
由于java.util.Runnable是一个功能接口,实现接口之类的样板式的代码可以使用lamdba替换。Runnable里的抽象方法是无参数所以 参数列表是一对空的括号().
Runnable assignment = () -> {expression or statements};
如果你写过JavaSE的界面或者写过Android的代码,你可能会知道点击一个按钮的时候时候处理的方法里面有定义一个匿名的内部类,并对其中的方法进行实现,来处理按钮点击触发的动作。接下来我们讲讲如何用lamdba表达式来取代这个繁冗的内部类实现代码。
003
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
public class ReplacingAnonymousInnerClasses {
public static void main(String[] args) {
Button btn = new Button();
/**
* typical
*/
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
System.out.println("Do something... typical");
}
});
/**
* lambda
*/
btn.setOnAction(e ->{
System.out.println("Do something... lambda");
});
}
}
003示例中:我们定义了一个按钮,为按钮btn设置点击事件。setOnAction,里面对按钮点击操作处理。新建一个匿名类,然后实现其中的handle方法,非常复杂,而接下来的示例中看到我们可以使用lamdba轻松搞定。
Lamdba表达式还能作为参数传递到方法中使用;
比如我要计算一个集合List<Double>每个元素的乘积,通过以上的学习我们我们可以很容易的写出这个功能:
004
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class Test {
private static Double multiplyNum = 1d;
public static void main(String[] args) {
Function<List<Double>, Double> multiply = doubleList -> {
doubleList.stream().forEach(num -> multiplyNum *= num);
return multiplyNum;
};
List<Double> list = new ArrayList<>();
list.add(12.3);
list.add(25.6);
list.add(38.4);
multiply.apply(list);
System.out.println(multiplyNum.intValue());
}
}
ps:上面使用Function定义了Lamdba表达式用以计算集合元素的乘积,这里有一点注意,如果 multiplyNum定义在Main中,而不是在类的局部变量,那这里就会报错,Lamdba中在一个封闭范围内的变量必须是final或者表现是final的,你不能更改它的值。
Ok,写好了计算的方法,我们定义一个函数用以接收一个Lamdba表达式,以及要计算的元素集,然后返回计算的结果,方法如下:
005
public Double calculate(Function<List<Double>, Double> f1,Double[] args){
Double returnValue;
List<Double> varList = new ArrayList<>();
int idx = 0;
while (idx < args.length){
varList.add(args[idx]);
idx++;
}
returnValue = f1.apply(varList);
return returnValue;
}
接下来加上Lamdba的实现并测试吧!
public class PassingLambdaFunctions {
public Double calculate(Function<List<Double>, Double> f1,Double[] args){
//见005,此处省略
}
public static void main(String[] args) {
double x = 16.0;
double y = 30.0;
double z = 4.0;
Function<List<Double>, Double> volumeCalc = list -> {
if (list.size() == 3) {
return list.get(0) * list.get(1) * list.get(2);
} else {
return Double.valueOf("-1");
}
};
Double[] argList = new Double[3];
argList[0] = x;
argList[1] = y;
argList[2] = z;
Function<List<Double>, Double> areaCalc = list -> {
if (list.size() == 2) {
return list.get(0) * list.get(1);
} else {
return Double.valueOf("-1");
}
};
Double[] argList2 = new Double[2];
argList2[0] = x;
argList2[1] = y;
PassingLambdaFunctions p1 = new PassingLambdaFunctions();
System.out.println("The volume is: " + p1.calculate(volumeCalc, argList));
System.out.println("The area is: " + p1.calculate(areaCalc, argList2));
}
}
任何类型的功能都可以使用Lamdba实现然后传递给不同的对象使用。这样可以更加提高代码的复用性&可维护性。Lamdba就讲到这。如果不觉得这些还不能满足你的需求,可以到官网去查找更详情的代码,或者搜索你想要的内容。
ps:本文示例引自 Josh Juneau所著 Java 8 Recipes, 2nd Edition
mission completed!
O(∩_∩)O~