自从有了Lambda,基本上就不会再写for循环,突然就有个想法,那以前没有Lambda的时候为什么每次操作集合的时候经常需要for循环呢?为什么就不封装一下呢?有了想法,那就想实现一下,参照Lambda的使用,写了一个过滤集合的实现,如下:
class ListUtil {
/** 从集合中过滤出满足指定条件的元素 */
public static <T> List<T> filter(List<T> list, Condition<T> condition) {
List<T> resultList = new ArrayList<>();
for (T item : list) {
if (condition.isWant(item)) {
// 如果此item是我们想要的,就加入到结果列表中
resultList.add(item);
}
}
return resultList;
}
}
/** 条件 */
interface Condition<T> {
/** 判断指定的item是否是我们想要的,如果是想要的就返回true,否则返回false */
boolean isWant(T item);
}
没错,就是这么简单,一个工具类方法filter,一个接口类Condition,有了这两个东西,以后需要从集合中过滤元素的时候就再也不用写循环了,只需调用filter函数,传入一个集合,再传入一个过滤条件即可,过滤条件的功能就是用于指定你想要过滤什么样的元素,比如:有一个Person的列表,我想要过获取列表中所有姓张的人,代码如下:
public class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
List<Person> personList = new ArrayList<>();
personList.add(new Person("张三", 18));
personList.add(new Person("李四", 23));
personList.add(new Person("张小虎", 16));
personList.add(new Person("王五", 28));
如上代码,这是一个Person类,没什么好说的,我们还创建了一个Person的集合。接下来我们想过滤出这个集合中所有姓张的人,代码如下:
List<Person> resultList = ListUtil.filter(personList, new Condition<Person>() {
@Override
public boolean isWant(Person item) {
return item.name.startsWith("张");
}
});
System.out.println(resultList);
输出结果如下:
[Person{name='张三', age=18}, Person{name='张小虎', age=16}]
OK,成功实现我们需要的功能。接下来,我想找出所有年龄大于20岁的人,也不需要再写for循环了,代码如下:
List<Person> resultList = ListUtil.filter(personList, new Condition<Person>() {
@Override
public boolean isWant(Person item) {
return item.age > 20;
}
});
System.out.println(resultList);
输出结果如下:
[Person{name='李四', age=23}, Person{name='王五', age=28}]
OK,完美!不论过滤什么,我们都不需要再写循环语句了,只是写起来麻烦了一点,每次要创建一个Predicate对象,其实我们真正需要的就是一个判断语句而已,如:item.age > 20,所以在jdk1.8的时候出来的函数式接口就非常好用了,使用函数式接口修改如上代码,如下:
List<Person> resultList = ListUtil.filter(personList, item -> item.age > 20)
舒服!!当然,使用jdk1.8之后 我们就不需要自己去写filter函数,集合类中已经自带此函数。
有了这个经验,我们就可以实现更多的功能,比如从集合中查找满足指定条件的一个元素,代码如下:
class ListUtil {
/** 从集合中找出满足指定条件的第一个元素 */
public static <T> T find(List<T> list, Condition<T> condition) {
for (T item : list) {
if (condition.isWant(item)) {
// 如果此item是我们想要的,就返回
return item;
}
}
return null;
}
}
接下来,我们使用之前的personList集合,第一个年龄18岁的人,代码如下:
Person person = ListUtil.find(personList, new Condition<Person>() {
@Override
public boolean isWant(Person item) {
return item.age == 18;
}
});
System.out.println(person);
输出如下:
Person{name='张三', age=18}
所以在没有Lambda的年代,我们没有这种思想,就经常做很多重复工作,其实这个模式不就是经典的策略设计模式么?相同的逻辑只写一次,不同的逻辑交由接口完成。以后在开发的时候,如果发现好几个地方代码好多重复的,但是有有一小部分不太一样,这时候就要使用策略模式了(不一定是for循环的代码),把不同的部分抽取成接口,相同的代码只写一次。