Java8:當 forEach 須要索引

Java8:當 forEach 須要索引
上一篇文章 中,咱們討論瞭如何使用 Java8Map 添加的新方法 computeIfAbsent 來統計集合中每一個元素出現的全部位置,代碼以下:

public static Map<String, List<Integer>> getElementPositions(List<String> list) {
    Map<String, List<Integer>> positionsMap = new HashMap<>();

    for (int i = 0; i < list.size(); i++) {
        positionsMap.computeIfAbsent(list.get(i), k -> new ArrayList<>(1)).add(i);
    }

    return positionsMap;
}
複製代碼

至少有兩點須要探討: 一、若是 list 不是基於數組的(即不是 RandomAccess 的),而是基於鏈表的,那麼 list.get(int index) 方法的效率就值得思考了; 二、既然都有了 Lambda(即當前平臺爲 Java8),咱們爲何還要一次次去寫傳統的 for 循環呢?java

Java8 中,爲 Iterable 接口添加了默認的 forEach 方法:git

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();
}

複製代碼

運行結果: github

forEach 運行示例

那若是咱們在遍歷的時候須要使用到元素的索引呢(相似 getElementPositions 方法那樣)? 很惋惜,Java8Iterable 並無提供一個帶索引的 forEach 方法。不過本身動手,豐衣足食——讓咱們本身寫一個帶索引的 forEach 方法:面試

import java.util.Objects;
import java.util.function.BiConsumer;

/**
 * Iterable 的工具類
 */
public class Iterables {

    public static <E> void forEach(
            Iterable<? extends E> elements, BiConsumer<Integer, ? super E> action) {
        Objects.requireNonNull(elements);
        Objects.requireNonNull(action);

        int index = 0;
        for (E element : elements) {
            action.accept(index++, element);
        }
    }
}
複製代碼

forEach 方法第一個參數爲要遍歷的 Iterable,第二個參數爲 BiConsumerBiConsumer 的輸入參數第一個即索引,第二個爲元素。算法

咱們測試下這個 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));
}

複製代碼

運行結果: segmentfault

測試 Iterables.forEach 方法的運行結果

結果和預期的一致。數組

如今咱們使用 Iterables.forEach 改寫 getElementPositions方法:bash

public static Map<String, List<Integer>> getElementPositions(List<String> list) {
    Map<String, List<Integer>> 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, List<Integer>> elementPositions = getElementPositions(list);
    System.out.println(elementPositions);
}
複製代碼

運行結果和原來一致: 微信

使用 computeIfAbsent 和 Iterable.forEach 的運行結果

真的不明白這麼簡單且實用的方法,Java8 爲何不在 Iterable 中提供一個默認實現(此處應有黑人問號)。

原文做者:mizhoux 原文地址:segmentfault.com/a/119000000…

推薦

大廠筆試內容集合(內有詳細解析) 持續更新中....

ProcessOn是一個在線做圖工具的聚合平臺~

文末

歡迎關注我的微信公衆號:Coder編程 歡迎關注Coder編程公衆號,主要分享數據結構與算法、Java相關知識體系、框架知識及原理、Spring全家桶、微服務項目實戰、DevOps實踐之路、每日一篇互聯網大廠面試或筆試題以及PMP項目管理知識等。更多精彩內容正在路上~ 新建了一個qq羣:315211365,歡迎你們進羣交流一塊兒學習。謝謝了!也能夠介紹給身邊有須要的朋友。

文章收錄至 Github: github.com/CoderMerlin… Gitee: gitee.com/573059382/c… 歡迎關注並star~

微信公衆號
相關文章
相關標籤/搜索