Java 集合与映射的迭代

Java 集合与映射的迭代,用户希望对集合或映射进行迭代,使用 java.lang.Iterablejava.util.Map 接口新增的默认方法 forEach。除了使用循环对线性集合(即实现 Collection 或其后代的类)进行迭代外,可以通过 Iterable 接口引入的默认方法 forEach 实现同样的目的。

Java 集合与映射的迭代 问题描述

用户希望对集合或映射进行迭代。

Java 集合与映射的迭代 解决方案

使用 java.lang.Iterablejava.util.Map 接口新增的默认方法 forEach

Java 集合与映射的迭代 具体实例

除了使用循环对线性集合(即实现 Collection 或其后代的类)进行迭代外,可以通过 Iterable 接口引入的默认方法 forEach 实现同样的目的。
根据 Javadoc 的描述,forEach 方法的签名为:

default void forEach(Consumer<? super T> action)

forEach 方法的参数为 Consumer,它是 java.util.function 包引入的一种函数式接口,表示传入一个泛型参数(generic argument)且不返回任何结果的操作。根据 Javadoc 的描述,“Consumer 与大部分函数式接口不同,它在执行时会产生副作用”。

纯函数(pure function)在执行时不会产生副作用。换言之,如果参数相同,则每次返回的结果也相同。函数式编程将其称为引用透明性(referential transparency),即函数可以被它的值所替换。

java.util.CollectionIterable 的子接口,因此 forEach 方法适用于从 ArrayListLinkedHashSet 的所有线性集合,这使得线性集合的迭代易如反掌(如例 5-17 所示)。

例 5-17 对线性集合进行迭代

List<Integer> integers = Arrays.asList(3, 1, 4, 1, 5, 9);

integers.forEach(new Consumer<Integer>() {    ➊
    @Override
    public void accept(Integer integer) {
        System.out.println(integer);
    }
});

integers.forEach((Integer n) -> {             ➋
    System.out.println(n);
});

integers.forEach(n -> System.out.println(n)); ➌

integers.forEach(System.out::println);        ➍
}

❶ 匿名内部类实现
❷ 完整形式的 lambda 代码块
❸ lambda 表达式
❹ 方法引用
在本例中,匿名内部类只是显示为 Consumer 接口的 accept 方法的签名。观察内部类可知,accept 方法传入一个参数并返回 void,本例所用的 lambda 表达式与之兼容。由于两个 lambda 表达式都包含对 System.out.println 方法的单次调用,forEach 方法可以用作方法引用。
Map 接口同样引入 forEach 方法作为默认方法,它传入 BiConsumer

default void forEach(BiConsumer<? super K, ? super V> action)

BiConsumer 也是 java.util.function 包新增的一种接口,表示一个传入两个泛型参数并返回 void 的函数。在实现 Map 接口的 forEach 方法时,参数是 entrySet 方法中 Map.Entry 实例的键和值。
换言之,对 Map 进行迭代现在就像对 ListSet 或其他任何线性集合进行迭代一样简单。示例代码如例 5-18 所示。

例 5-18 对 Map 进行迭代

Map<Long, String> map = new HashMap<>();
map.put(86L, "Don Adams (Maxwell Smart)");
map.put(99L, "Barbara Feldon");
map.put(13L, "David Ketchum");
map.forEach((num, agent) ->
    System.out.printf("Agent %d, played by %s%n", num, agent));

输出如例 5-196 所示。
6例 5-18 和例 5-19 取自美国经典电视剧《糊涂侦探》,这部由梅尔 • 布鲁克斯(Mel Brooks)和巴克 • 亨利(Buck Henry)编导的间谍喜剧在 1965 年到 1970 年间播出。主角麦克斯韦 • 史马特(Maxwell Smart)糅合了詹姆斯 • 邦德与雅克 • 克鲁索(英国电影《糊涂大侦探》主角)的特点,又称特工 86 号(Agent 86)。他的女搭档是特工 99 号(Agent 99),同事是特工 13 号(Agent 13)。

例 5-19 对 Map 迭代后的输出

Agent 99, played by Barbara Feldon
Agent 86, played by Don Adams (Maxwell Smart)
Agent 13, played by David Ketchum

在 Java 8 之前,为了实现对 Map 的迭代,需要首先通过 keySet 方法获取键的 Set,或通过 entrySet 方法获取 Map.Entry 实例。而 Java 8 引入的默认方法 forEach 使迭代操作得以简化。

跳出 for-each 循环并非易事,这一点请谨记在心。为解决这个问题,考虑将流处理代码重写为 filtersorted,并后跟 findFirst

赞(2)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Java 实例