Java8foreach指南.md 3.7 KB
Newer Older
K
Kou Shuang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
> 本文由 JavaGuide 翻译,原文地址:https://www.baeldung.com/foreach-java

## 1 概述

在Java 8中引入的*forEach*循环为程序员提供了一种新的,简洁而有趣的迭代集合的方式。

在本文中,我们将看到如何将*forEach*与集合*一起*使用,它采用何种参数以及此循环与增强的*for*循环的不同之处。

## 2 基础知识

```Java
public interface Collection<E> extends Iterable<E>
```

Collection 接口实现了 Iterable 接口,而 Iterable 接口在 Java 8开始具有一个新的 API:

```java
void forEach(Consumer<? super T> action)//对 Iterable的每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。
```

使用*forEach*,我们可以迭代一个集合并对每个元素执行给定的操作,就像任何其他*迭代器一样。*

例如,迭代和打印字符串集合*的*for循环版本:

```java
for (String name : names) {
    System.out.println(name);
}
```

我们可以使用*forEach*写这个 :

```java
names.forEach(name -> {
    System.out.println(name);
});
```

## 3.使用forEach方法

### 3.1 匿名类

我们使用  *forEach*迭代集合并对每个元素执行特定操作。**要执行的操作包含在实现Consumer接口的类中,并作为参数传递给forEach 。**

所述*消费者*接口是一个功能接口(具有单个抽象方法的接口)。它接受输入并且不返回任何结果。

Consumer 接口定义如下:

```java
@FunctionalInterface
public interface Consumer {
    void accept(T t);
}
```
任何实现,例如,只是打印字符串的消费者:

```java
Consumer<String> printConsumer = new Consumer<String>() {
    public void accept(String name) {
        System.out.println(name);
    };
};
```

可以作为参数传递给*forEach*

```java
names.forEach(printConsumer);
```

但这不是通过消费者和使用*forEach* API 创建操作的唯一方法。让我们看看我们将使用*forEach*方法的另外2种最流行的方式:

### 3.2 Lambda表达式

Java 8功能接口的主要优点是我们可以使用Lambda表达式来实例化它们,并避免使用庞大的匿名类实现。

由于 Consumer 接口属于函数式接口,我们可以通过以下形式在Lambda中表达它:

```java
(argument) -> { body }
name -> System.out.println(name)
names.forEach(name -> System.out.println(name));
```

### 3.3 方法参考

我们可以使用方法引用语法而不是普通的Lambda语法,其中已存在一个方法来对类执行操作:

```java
names.forEach(System.out::println);
```

## 4.forEach在集合中的使用

### 4.1.迭代集合

**任何类型Collection的可迭代  - 列表,集合,队列 等都具有使用forEach的相同语法。**

因此,正如我们已经看到的,迭代列表的元素:

```java
List<String> names = Arrays.asList("Larry", "Steve", "James");
 
names.forEach(System.out::println);
```

同样对于一组:

```java
Set<String> uniqueNames = new HashSet<>(Arrays.asList("Larry", "Steve", "James"));
 
uniqueNames.forEach(System.out::println);
```

或者让我们说一个*队列*也是一个*集合*

```java
Queue<String> namesQueue = new ArrayDeque<>(Arrays.asList("Larry", "Steve", "James"));
 
namesQueue.forEach(System.out::println);
```

### 4.2.迭代Map - 使用Map的forEach

Map没有实现Iterable接口,但它**提供了自己的forEach 变体,它接受BiConsumer*** 

```java
Map<Integer, String> namesMap = new HashMap<>();
namesMap.put(1, "Larry");
namesMap.put(2, "Steve");
namesMap.put(3, "James");
namesMap.forEach((key, value) -> System.out.println(key + " " + value));
```

### 4.3.迭代一个Map - 通过迭代entrySet

```java
namesMap.entrySet().forEach(entry -> System.out.println(entry.getKey() + " " + entry.getValue()));
```