多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# Java 流归约 原文:http://zetcode.com/java/streamreduce/ Java 流归约教程展示了如何对 Java8 流执行缩减操作。 ## Java 流 Java 流是来自源的支持聚合操作的一系列元素。 流不存储元素。 元素是按需计算的。 元素是从数据源(如集合,数组或 I/O 资源)中消耗的。 ## Java 流归约 归约是将流聚合为类或原始类型的终端操作。 Java8 流 API 包含一组预定义的归约操作,例如`average()`,`sum()`,`min()`,`max()`和`count()`,它们通过组合流的元素来返回一个值。 ## Java 流`reduce`方法 `Stream.reduce()`是用于生成自定义归约运算的通用方法。 ```java Optional<T> reduce(BinaryOperator<T> accumulator) ``` 此方法使用关联累加函数对该流的元素进行归约。 它返回一个`Optional`描述归约的值(如果有)。 ```java T reduce(T identity, BinaryOperator<T> accumulator) ``` 此方法采用两个参数:标识和累加器。 如果流中没有元素,则身份元素既是`reduce`的初始值,也是默认结果。 累加器函数具有两个参数:约简的部分结果和流的下一个元素。 它返回一个新的部分结果。 `Stream.reduce()`方法返回归约的结果。 ## Java 流内置归约 以下示例使用了两个预定义的归约操作。 `JavaReduceEx.java` ```java package com.zetcode; import java.util.Arrays; public class JavaReduceEx { public static void main(String[] args) { int vals[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; int sum = Arrays.stream(vals).sum(); System.out.printf("The sum of values: %d%n", sum); long n = Arrays.stream(vals).count(); System.out.printf("The number of values: %d%n", n); } } ``` 我们有一个整数数组。 我们使用`Arrays.stream()`从数组创建一个流,并执行两个归约:`sum()`和`count()`。 ```java The sum of values: 72 The number of values: 8 ``` 这是输出。 ## Java `reduce`和`Optional` 具有一个参数的`reduce()`方法返回`Optional`,这是用于`null`安全的 Java 类。 `Car.java` ```java package com.zetcode; public class Car { private final String name; private final int price; public Car(String name, int price) { this.name = name; this.price = price; } public int getPrice() { return price; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Car{name=").append(name).append(", price=") .append(price).append("}"); return builder.toString(); } } ``` 这是`Car`类。 `JavaReduceEx2.java` ```java package com.zetcode; import java.util.Arrays; import java.util.List; import java.util.Optional; public class JavaReduceEx2 { public static void main(String[] args) { List<Car> persons = Arrays.asList(new Car("Skoda", 18544), new Car("Volvo", 22344), new Car("Fiat", 23650), new Car("Renault", 19700)); Optional<Car> car = persons.stream().reduce((c1, c2) -> c1.getPrice() > c2.getPrice() ? c1 : c2); car.ifPresent(System.out::println); } } ``` 该示例创建一个汽车对象列表。 我们计算出最昂贵的汽车。 ```java Optional<Car> car = persons.stream().reduce((c1, c2) -> c1.getPrice() > c2.getPrice() ? c1 : c2); ``` 从列表中,我们创建一个流; `reduce()`方法的累加器会比较汽车的价格并返回价格较高的汽车。 ```java car.ifPresent(System.out::println); ``` 如果返回的归约值不为 null,则将其打印到控制台。 ```java Car{name=Fiat, price=23650} ``` 这是输出。 下一个示例添加了其他用例。 `MyUtil.java` ```java package com.zetcode; public class MyUtil { public static int add2Ints(int num1, int num2) { return num1 + num2; } } ``` 这是`MyUtil`类,具有一种将两个整数相加的方法。 `JavaReduceEx3.java` ```java package com.zetcode; import java.util.stream.IntStream; public class JavaReduceEx3 { public static void main(String[] args) { IntStream.range(1, 10).reduce((x, y) -> x + y) .ifPresent(s -> System.out.println(s)); IntStream.range(1, 10).reduce(Integer::sum) .ifPresent(s -> System.out.println(s)); IntStream.range(1, 10).reduce(MyUtil::add2Ints) .ifPresent(s -> System.out.println(s)); } } ``` 我们创建三个不同的累加器函数来计算`1..10`值的总和。 ```java IntStream.range(1, 10).reduce((x, y) -> x + y).ifPresent(s -> System.out.println(s)); ``` 在第一种情况下,我们使用 lambda 表达式进行加法。 ```java IntStream.range(1, 10).reduce(Integer::sum).ifPresent(s -> System.out.println(s)); ``` 第二种情况使用内置的`Integer::sum`方法。 ```java IntStream.range(1, 10).reduce(MyUtil::add2Ints).ifPresent(s -> System.out.println(s)); ``` 最后,我们有一个自定义的添加方法。 ## Java 归约标识 正如我们已经提到的,如果流中没有元素,则标识既是还原的初始值,又是默认结果。 `User.java` ```java package com.zetcode; import java.time.LocalDate; import java.time.chrono.IsoChronology; public class User { private String name; private LocalDate dateOfBirth; public User(String name, LocalDate dateOfBirth) { this.name = name; this.dateOfBirth = dateOfBirth; } public String getName() { return name; } public void setName(String name) { this.name = name; } public LocalDate getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(LocalDate dateOfBirth) { this.dateOfBirth = dateOfBirth; } public int getAge() { return dateOfBirth.until(IsoChronology.INSTANCE.dateNow()) .getYears(); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("User{name=").append(name).append(", dateOfBirth=") .append(dateOfBirth).append("}"); return builder.toString(); } } ``` 这是`User`类。 除了常用的属性,获取器和设置器之外,我们还有`getAge()`方法,该方法使用 Java8 日期 API 返回用户的年龄。 `JavaReduceEx4.java` ```java package com.zetcode; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; public class JavaReduceEx4 { public static void main(String[] args) { List<User> users = new ArrayList<>(); users.add(new User("Frank", LocalDate.of(1979, 11, 23))); users.add(new User("Peter", LocalDate.of(1985, 1, 18))); users.add(new User("Lucy", LocalDate.of(2002, 5, 14))); users.add(new User("Albert", LocalDate.of(1996, 8, 30))); users.add(new User("Frank", LocalDate.of(1967, 10, 6))); int maxAge = users.stream().mapToInt(User::getAge) .reduce(0, (a1, a2) -> a1 > a2 ? a1 : a2); System.out.printf("The oldest user's age: %s%n", maxAge); } } ``` 在示例中,我们创建了一个用户列表。 该示例计算最老用户的年龄。 ```java int maxAge = users.stream().mapToInt(User::getAge) .reduce(0, (a1, a2) -> a1 > a2 ? a1 : a2); ``` 从列表中,我们创建一个 Java8 流。 使用`mapToInt()`方法将流映射到`IntStream`。 最后,`reduce()`方法提供一个标识值(0)和一个累加器; 累加器将比较年龄值并返回较大的值。 在本教程中,我们已经使用 Java 流归约操作。 您可能也对相关教程感兴趣: [Java 流](/lang/java/streams), [Java 流映射](/java/streammap/), [Java 流过滤器](/java/streamfilter)和 [Java8 `forEach`教程](/articles/java8foreach/)。