從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);
這樣做,測試了一下,效率提升了好幾倍
參考: