原因
之前写过一篇关于Lambda表达式的文章 ,最近又回头看了看,觉得不太满意,从新思考了一下,再写篇新的。
本文参考《Java8实战》 ,作者:[英] Raoul-Gabriel Urma [意] Mario Fusco [英] Alan Mycroft
一、不断变化的需求
第一天:产品经理来找你,说:“我这里有一堆苹果,我要把绿的拿出来”
好了,于是我写了下边的代码:
苹果类:
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Apple {
private String color;
private long weight;
}
获取绿色苹果:
public static List<Apple> findGreenApple(List<Apple> apples){
List<Apple> list = new ArrayList<>();
for (Apple apples1 : apples){
if (apples1.getColor().equals("green")){
list.add(apples1);
}
}
return list;
}
测试类:
public static void main(String[] args){
List<Apple> list= Arrays.asList(new Apple("green",1L ),new Apple("red",2L),new Apple("red",1L),new Apple("yellow",3L));
List<Apple> greenApple = findGreenApple(list);
System.out.println(greenApple);
}
结果:
第二天:产品经理说:“我不要绿苹果了,我要红苹果,你给我改成把红苹果拿出来”
好,改。
public static List<Apple> findRedApple(List<Apple> apples){
List<Apple> list = new ArrayList<>();
for (Apple apples1 : apples){
if (apples1.getColor().equals("red")){
list.add(apples1);
}
}
return list;
}
green->red不就可以了嘛!
第三天:产品经理说,“我不要按颜色取了,你把重量1斤以上的苹果都给我取出来!”
好,再改。
public static List<Apple> findAppleByWeight(List<Apple> apples){
List<Apple> list = new ArrayList<>();
for (Apple apples1 : apples){
if (apples1.getWeight()>1){
list.add(apples1);
}
}
return list;
}
第四天:产品经理说,“再改改,你把重量1斤以上的红苹果都给我取出来!”
你就说,你想不想揍他。
这时候怎么办?还改代码?
以后产品经理可能还会告诉你,“把X斤以上绿苹果取出来”
当我们频繁的改动代码,或程序中出现了大量的重复代码时,作为owner,我们需要警觉了。
二、有什么处理方式才能应对这种不断变化的需求呢?
我们可以用策略模式。
但是像这种绿苹果、红苹果、红绿苹果等等,每加个需求就加个策略,难免出现很多重复的代码。
这时候我们可以考虑 Lambda表达式
三、 Lambda表达式
Java8以后支持行为参数化,即可以在参数中传递方法(个人理解)。
首先,我新建一个泛型接口,接口中方法test返回值为boolean类型,参数为任意类型。
@FunctionalInterface
public interface AppleTest<T> {
boolean test(T t);
}
然后,在getAppleByCorlorOrWeight方法中把接口传进去
//一个参数返回Boolean
public static List<Apple> getAppleByCorlorOrWeight(List<Apple> apples , AppleTest<Apple> p){
List<Apple> result = new LinkedList<>();
for (Apple apple :apples){
if (p.test(apple)){
result.add(apple);
}
}
return result;
}
最后,运用lambda,我可以任意获得任何颜色或者重量的苹果。
public static void main(String[] args){
List<Apple> list= Arrays.asList(new Apple("green",1L ),new Apple("red",2L),new Apple("red",1L),new Apple("yellow",3L));
System.out.println(getAppleByCorlorOrWeight(list,apple -> apple.getColor().equals("red")));
System.out.println(getAppleByCorlorOrWeight(list,apple -> apple.getWeight() > 1L));
}
那么,我要获得某颜色某重量的苹果怎么办呢?
四、函数式接口
新建接口BiAppleTest,允许抽象方法传递两个参数
@FunctionalInterface
public interface BiAppleTest<T,U> {
boolean test(T t, U u);
}
新建getAppleByCorlorAndWeight方法调用
//两个参数返回Boolean
public static List<Apple> getAppleByCorlorAndWeight(List<Apple> apples,BiAppleTest<String,Long> p){
List<Apple> result = new LinkedList<>();
for (Apple apple:apples){
if (p.test(apple.getColor(), apple.getWeight())){
result.add(apple);
}
}
return result;
}
测试:
public static void main(String[] args){
List<Apple> list= Arrays.asList(new Apple("green",1L ),new Apple("red",2L),new Apple("red",1L),new Apple("yellow",3L));
System.out.println(getAppleByCorlorAndWeight(list,(c,w)->c.equals("red") && w>1L));
}
结果:
那么问题又来了,我要获取符合某些条件的苹果,建立了两个函数式接口AppleTest、BiAppleTest,那如果我以后找符合某些条件的梨、香蕉、香蕉梨…难道都要去建立相应的函数式接口吗?
当然不用!Java8为我们提供了四大函数式接口,我建立的AppleTest、BiAppleTest分别对应着java8提供的Predicate、BiPredicate,以上代码可以换成:
//一个参数返回Boolean
public static List<Apple> getAppleByCorlorOrWeight(List<Apple> apples , Predicate<Apple> p){
List<Apple> result = new LinkedList<>();
for (Apple apple :apples){
if (p.test(apple)){
result.add(apple);
}
}
return result;
}
//两个参数返回Boolean
public static List<Apple> getAppleByCorlorAndWeight(List<Apple> apples, BiPredicate<String,Long> p){
List<Apple> result = new LinkedList<>();
for (Apple apple:apples){
if (p.test(apple.getColor(), apple.getWeight())){
result.add(apple);
}
}
return result;
}
AppleTest、BiAppleTest并不需要自己去建立。
java8还为我们提供了很多函数式接口,都在rt.jar里,有兴趣的可以玩一玩。
来源:CSDN
作者:淘小笛
链接:https://blog.csdn.net/zjy15203167987/article/details/104039594