在 上一篇文章 中,我們討論瞭如何使用 Java8 中 Map 添加的新方法 computeIfAbsent 來統計集合中每個元素出現的所有位置,代碼如下:
public static Map<string>> getElementPositions(List<string> list) {
Map<string>> positionsMap = new HashMap<>();
for (int i = 0; i < list.size(); i++) {
positionsMap.computeIfAbsent(list.get(i), k -> new ArrayList<>(1)).add(i);
}
return positionsMap;
}
/<string>/<string>/<string>
至少有兩點需要探討:
1、如果 list 不是基於數組的(即不是 RandomAccess 的),而是基於鏈表的,那麼 list.get(int index) 方法的效率就值得思考了;
2、既然都有了 Lambda(即當前平臺為 Java8),我們為什麼還要一次次去寫傳統的 for 循環呢?
在 Java8 中,為 Iterable 接口添加了默認的 forEach 方法:
很好理解,遍歷當前 Iterable 中所有的元素,使用每個元素作為參數調用一次 action。而 Collection 接口繼承了 Iterable 接口,所以所有的繼承自 Collection 的集合類都可以直接調用 forEach 方法。比如:
public static void main(String[] args) throws Exception {
List<string> list = Arrays.asList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");
list.forEach(str -> System.out.print(str + " "));
System.out.println();
}
/<string>
運行結果:
那如果我們在遍歷的時候需要使用到元素的索引呢(類似 getElementPositions 方法那樣)?
很可惜,Java8的 Iterable 並沒有提供一個帶索引的 forEach 方法。不過自己動手,豐衣足食——讓我們自己寫一個帶索引的 forEach 方法:
import java.util.Objects;
import java.util.function.BiConsumer;
/**
* Iterable 的工具類
*/
public class Iterables {
public staticvoid forEach(
Iterable extends E> elements, BiConsumer<integer> action) {
Objects.requireNonNull(elements);
Objects.requireNonNull(action);
int index = 0;
for (E element : elements) {
action.accept(index++, element);
}
}
}
/<integer>
該 forEach 方法第一個參數為要遍歷的 Iterable,第二個參數為 BiConsumer。BiConsumer 的輸入參數第一個即索引,第二個為元素。
我們測試下這個 forEach 方法:
public static void main(String[] args) throws Exception {
List<string> list = Arrays.asList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");
Iterables.forEach(list, (index, str) -> System.out.println(index + " -> " + str));
}
/<string>
運行結果:
結果和預期的一致。
現在我們使用 Iterables.forEach 改寫 getElementPositions方法:
public static Map<string>> getElementPositions(List<string> list) {
Map<string>> positionsMap = new HashMap<>();
Iterables.forEach(list, (index, str) -> {
positionsMap.computeIfAbsent(str, k -> new ArrayList<>(1)).add(index);
});
return positionsMap;
}
public static void main(String[] args) throws Exception {
List<string> list = Arrays.asList("a", "b", "b", "c", "c", "c", "d", "d", "d", "f", "f", "g");
System.out.println("使用 computeIfAbsent 和 Iterable.forEach:");
Map<string>> elementPositions = getElementPositions(list);
System.out.println(elementPositions);
}
/<string>/<string>/<string>/<string>/<string>
運行結果和原來一致:
真的不明白這麼簡單且實用的方法,Java8 為什麼不在 Iterable 中提供一個默認實現(此處應有黑人問號)。
文末
歡迎關注個人公眾號:Coder編程
歡迎關注Coder編程公眾號,主要分享數據結構與算法、Java相關知識體系、框架知識及原理、Spring全家桶、微服務項目實戰、DevOps實踐之路、每日一篇互聯網大廠面試或筆試題以及PMP項目管理知識等。更多精彩內容正在路上~
閱讀更多 Coder編程 的文章