首页 > 解决方案 > 在 Java8 中清理数据列表

问题描述

为了清理数据列表,我创建了一个接受数据列表和要执行的清理操作列表的方法。

public <T> List<T> cleanData(List<T> data, List<Function<T, T>> cleanOps) {
    List<T>dataNew=data.stream().map((str) -> {
        T cleanData = str;
        for(Function<T,T> function:cleanOps) {
            cleanData=function.apply(cleanData);
        }
        return cleanData;
    }).collect(Collectors.toList());
    return dataNew;
}

这里的问题是我们再次创建整个列表作为Collectors.toList()返回一个新列表。我们可以在不使用额外空间的情况下获得相同的结果吗?

下面是调用代码:

public void processData() {
    List<Function<String, String>> cleanOps = new ArrayList<>();
    cleanOps.add(String::toLowerCase);
    cleanOps.add(str -> str.replaceAll(" ", ""));
    List<String> data = new ArrayList<>();
    data.add("John Doe");
    data.add("Jane Doe");
    System.out.println(Arrays.toString(cleanData(data, cleanOps).toArray()));
}

标签: javajava-8functional-programmingjava-stream

解决方案


如果允许就地修改列表,您可以使用

public <T> List<T> cleanData(List<T> data, List<Function<T, T>> cleanOps) {
    cleanOps.stream().reduce(Function::andThen).ifPresent(f -> data.replaceAll(f::apply));
    return data;
}

andThen组合两个Function实例,如果至少存在一个函数,即cleanOps列表不为空,则生成的组合函数将应用于所有列表元素和被结果替换的元素,使用replaceAll.

不幸的是,replaceAll需要 aUnaryOperator<T>而不是 a Function<T,T>,尽管在功能上是等效的,所以我们必须使用适配器f::apply

由于这些函数类型是等价的,我们可以将列表更改为List<UnaryOperator<T>>,但是,我们必须面对一个事实,即没有专门andThen的实现UnaryOperator,所以我们需要:

public <T> List<T> cleanData(List<T> data, List<UnaryOperator<T>> cleanOps) {
    cleanOps.stream()
        .reduce((f1,f2) -> t -> f2.apply(f1.apply(t)))
        .ifPresent(data::replaceAll);
    return data;
}

调用者的源更改为

List<UnaryOperator<String>> cleanOps = new ArrayList<>();
cleanOps.add(String::toLowerCase);
cleanOps.add(str -> str.replaceAll(" ", ""));
List<String> data = new ArrayList<>();
data.add("John Doe");
data.add("Jane Doe");
System.out.println(cleanData(data, cleanOps));

然后。

作为旁注,不需要像这样的构造

System.out.println(Arrays.toString(cleanData(data, cleanOps).toArray()));

因为 a 的toString()方法List产生完全相同的输出。由于该println(Object)方法隐式调用toString(),您可以使用

System.out.println(cleanData(data, cleanOps));

推荐阅读