从list中查找符合条件的元素是一个很常见的需求,有很多办法可以做到,详见参考链接。本文讨论的点是如何把这个过程封装成一个方法,这样做的好处如下:
1.简化调用
2.容易替换成不同的实现
3.可以做一些统一的处理
这就是抽象的好处吧
假设List中保存的元素是Item,定义如下:
public class Item {
private Integer id;
private Integer weight;
public Item(Integer id, Integer weight) {
this.id = id;
this.weight = weight;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
}
抽象后的方法如下:
public static <T extends Object>
T getElem(List<T> objs, Integer id, Class<?> clazz) {
try {
Method getIdFunc = clazz.getMethod("getId");
for (T obj : objs) {
Integer rId = (Integer)getIdFunc.invoke(obj);
if (rId.equals(id)) {
return obj;
}
}
} catch (Exception e) {
LogUtil.LOG_BASE.error("getElem异常", e.getMessage(), e);
}
return null;
}
调用起来如下:
public Item getItemById(int id) {
return Util.getEle(items, 1, Item.class);
}
// 测试代码
List<Item> items = new ArrayList<>();
items.add(new Item(1, 50));
items.add(new Item(2, 50));
items.add(new Item(3, 50));
Item item = getItemById(items);
是挺简洁的,但是这么做的缺点是这里使用了反射,反射的问题在于效率,对于调用不太频繁的方法还好,但是对于这种过于频繁的方法,显然就不是很合适了,因此继续思考,有了如下方法。
方法二是基于java 8 Stream API实现,没有抽象前,查找代码如下:
Customer james = customers.stream()
.filter(customer -> "James".equals(customer.getName()))
.findAny()
.orElse(null);
抽象以后,有了如下方法:
public static <T extends Object>
T getEle(List<T> objs, Predicate<T> predicate) {
return objs.stream()
.filter(predicate)
.findAny()
.orElse(null);
}
这样查找调用就变成了
public Item getItemById(int id) {
return Util.getEle(items, item -> item.getId() == id);
}
List<Item> items = new ArrayList<>();
items.add(new Item(1, 50));
items.add(new Item(2, 50));
items.add(new Item(3, 50));
Item item = Util.getEle(items, item -> item.getId() == id);
这样做,测试了一下,效率提升了好几倍
参考: