跳转至

Java 流归约

原文:http://zetcode.com/java/streamreduce/

Java 流归约教程展示了如何对 Java8 流执行缩减操作。

Java 流

Java 流是来自源的支持聚合操作的一系列元素。 流不存储元素。 元素是按需计算的。 元素是从数据源(如集合,数组或 I/O 资源)中消耗的。

Java 流归约

归约是将流聚合为类或原始类型的终端操作。 Java8 流 API 包含一组预定义的归约操作,例如average()sum()min()max()count(),它们通过组合流的元素来返回一个值。

Java 流reduce方法

Stream.reduce()是用于生成自定义归约运算的通用方法。

Optional<T> reduce(BinaryOperator<T> accumulator)

此方法使用关联累加函数对该流的元素进行归约。 它返回一个Optional描述归约的值(如果有)。

T reduce(T identity, BinaryOperator<T> accumulator)

此方法采用两个参数:标识和累加器。 如果流中没有元素,则身份元素既是reduce的初始值,也是默认结果。 累加器函数具有两个参数:约简的部分结果和流的下一个元素。 它返回一个新的部分结果。 Stream.reduce()方法返回归约的结果。

Java 流内置归约

以下示例使用了两个预定义的归约操作。

JavaReduceEx.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()

The sum of values: 72
The number of values: 8

这是输出。

Java reduceOptional

具有一个参数的reduce()方法返回Optional,这是用于null安全的 Java 类。

Car.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

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

该示例创建一个汽车对象列表。 我们计算出最昂贵的汽车。

Optional<Car> car = persons.stream().reduce((c1, c2)
            -> c1.getPrice() > c2.getPrice() ? c1 : c2);

从列表中,我们创建一个流; reduce()方法的累加器会比较汽车的价格并返回价格较高的汽车。

car.ifPresent(System.out::println);

如果返回的归约值不为 null,则将其打印到控制台。

Car{name=Fiat, price=23650}

这是输出。

下一个示例添加了其他用例。

MyUtil.java

package com.zetcode;

public class MyUtil {

    public static int add2Ints(int num1, int num2) {
        return num1 + num2;
    }
}

这是MyUtil类,具有一种将两个整数相加的方法。

JavaReduceEx3.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值的总和。

IntStream.range(1, 10).reduce((x, y) -> x + y).ifPresent(s -> System.out.println(s));

在第一种情况下,我们使用 lambda 表达式进行加法。

IntStream.range(1, 10).reduce(Integer::sum).ifPresent(s -> System.out.println(s));

第二种情况使用内置的Integer::sum方法。

IntStream.range(1, 10).reduce(MyUtil::add2Ints).ifPresent(s -> System.out.println(s));

最后,我们有一个自定义的添加方法。

Java 归约标识

正如我们已经提到的,如果流中没有元素,则标识既是还原的初始值,又是默认结果。

User.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

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

在示例中,我们创建了一个用户列表。 该示例计算最老用户的年龄。

int maxAge = users.stream().mapToInt(User::getAge)
        .reduce(0, (a1, a2) -> a1 > a2 ? a1 : a2);

从列表中,我们创建一个 Java8 流。 使用mapToInt()方法将流映射到IntStream。 最后,reduce()方法提供一个标识值(0)和一个累加器; 累加器将比较年龄值并返回较大的值。

在本教程中,我们已经使用 Java 流归约操作。 您可能也对相关教程感兴趣: Java 流Java 流映射Java 流过滤器Java8 forEach教程



回到顶部