首页 > 解决方案 > Java Streams - 将两个字符串行分别映射到一个对象

问题描述

假设我们有一个包含(product name, price)对的文本文件。每对在文本文件中占据两行,其中第一行对应产品名称,第二行对应该产品的价格。我们可以假设文本文件的格式正确(并且行数是偶数)

例子:

Ice Cream
$3.99
Chocolate
$5.00
Nice Shoes
$84.95
...

现在我有一个简单的类来表示这样的对:

public class Product {
    private final String name;
    private final int price;

    public Product(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return this.name;
    }

    public int getPrice() {
        return this.price;
    }
}

我们读取了包含对的文件,现在有一个包含所有单独行的字符串数组。我需要使用 Streams将每两行映射到一个 type 对象Product

如何将两条线分别分组,然后将它们映射到一个Product?如果有一种简单的方法,它是否仍然适用于并行流?

标签: javajava-stream

解决方案


您可以制作自己的Collector临时存储前一个元素/字符串。当前元素以 a 开头时$,产品名称存储在 中prev。现在您可以将价格转换为双倍并创建对象。

private class ProductCollector {

    private final List<Product> list = new ArrayList<>();

    private String prev;

    public void accept(String str) {
        if (prev != null && str.startsWith("$")) {
            double price = Double.parseDouble(str.substring(1));
            list.add(new Product(prev, price));
        }
        prev = str;
    }

    public List<Product> finish() {
        return list;
    }

    public static Collector<String, ?, List<Product>> collector() {
        return Collector.of(ProductCollector::new, ProductCollector::accept, (a, b) -> a, ProductCollector::finish);
    }
}

由于您需要依赖序列(价格行跟随名称行),因此无法并行处理流。以下是使用自定义收集器的方法:

String[] lines = new String[]{
        "Ice Cream", "$3.99",
        "Chocolate", "$5.00",
        "Nice Shoes", "$84.95"
};

List<Product> products = Stream.of(lines)
        .sequential()
        .collect(ProductCollector.collector());

请注意,您的价格不是整数,这就是我使用双精度来正确表示它们的原因。


推荐阅读