带有四个字符串列表和 if-else 条件的 Lambda 函数

时间:2021-07-01 15:01:37

标签: java lambda java-8 stream java-stream

我收到技术负责人的请求,要求重写此代码并用通用 lambda 替换 for 循环。我怀疑这会导致更简单、更具可读性和可维护性的代码。

请问有什么好的办法吗?

问题是关于如何将当前的 for 循环转换为 lambda 函数。项目数据结构的更改完全超出范围。参见循环 - 它是状态列表的一部分,同时检查同一索引处的 addressType 值。

如何使用 lambda 来做到这一点,它实际上会简化代码吗?

List<String> states = Arrays.asList(item.getState().split(","));
List<String> addressType = Arrays.asList(item.getAddressType().split(","));
List<String> mailingStates = new ArrayList<>();
List<String> physicalStates = new ArrayList<>();


for(int i = 0; i<states.size(); i++){
    if(Constants.MAILING.equals(addressType.get(i))){
        mailingStates.add(states.get(i));
    } else {
        physicalStates.add(states.get(i));
    }
}

不得不说 - 仅限 Java 8

3 个答案:

答案 0 :(得分:0)

代码将相同,所以我不知道重点是什么,但它将使用 lambda 表达式块。

List<String> states = Arrays.asList(item.getState().split(","));
List<String> addressType = Arrays.asList(item.getAddressType().split(","));
List<String> mailingStates = new ArrayList<>(), physicalStates = new ArrayList<>();


        IntStream.range(0, states.size()).forEach(i -> {
            if (Constants.MAILING.equals(addressType.get(i))) {
                mailingStates.add(states.get(i));
            } else {
                physicalStates.add(states.get(i));
            }
        });

答案 1 :(得分:0)

您要做的是浏览两个同名列表。这个操作的通用名称是“zip”——当你通过两个(或有时更多)数组/列表/流/等并对每个元素做一些事情时。

您可以从此处选择流的实现:Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip) 现有库中也已经实现了许多实现。如果您的项目中已经有这样的库,您只需要导入即可使用它。

为了便于说明,我假设有一个可用于 this signature 的实现:

<A, B, C> Stream<C> zip(Stream<? extends A> a,
                        Stream<? extends B> b,
                        BiFunction<? super A, ? super B, ? extends C> zipper)

此外,一个很好的简单通用实用程序是具有两个值的 Pair 类。有许多现有的实现。我将使用此签名进行实现:

class Pair<LEFT, RIGHT> {
    Pair(LEFT left, RIGHT right);
    LEFT getLeft();
    RIGHT getRight();
}

这将保存相关的状态和地址类型。但是您也可以考虑创建一个特定的对象来封装给定的状态和地址类型。

使用这些通用帮助程序,您的代码可以如下所示:

Stream<String> states = Arrays.stream(item.getState().split(","));
Stream<String> addressType = Arrays.stream(item.getAddressType().split(","));

Map<Boolean, List<String>> splitStates = zip(states, addressTypes, 
    (state, addressType) -> new Pair<String, String>(state, addressType))
    .collect(
      Collectors.partitioningBy(pair -> Constants.MAILING.equals(pair.getRight()), 
        collectors.mapping(pair -> pair.getLeft())
      )
    );

List<String> mailingStates = split.get(true);
List<String> physicalStates = split.get(false);

如果 lambdas 被替换为方法引用并在可能的情况下进行一些小的重新排列,那么您会得到:

private static final Predicate<Pair<String, String> IS_Mailing = 
    pair -> Constants.MAILING.equals(pair.getRight());

/* ... */

Stream<String> states = Arrays.stream(item.getState().split(","));
Stream<String> addressType = Arrays.stream(item.getAddressType().split(","));

Map<Boolean, List<String>> splitStates = zip(states, addressTypes, Pair::new)
    .collect(Collectors.partitioningBy(IS_MAILING), 
        collectors.mapping(Pair::getLeft()));

List<String> mailingStates = split.get(true);
List<String> physicalStates = split.get(false);

如果你实现一个类而不是通用的 Pair 类:

class StateData {
    private String state;
    private String addressType;

    public StateData(String state, String addressType) {
        this.state = state;
        this.addressType = addressType;
    }

    public String getState() { return this.state; } 
    public String getAddressType() { return this.addressType; } 
    public boolean isMailing() { 
        return Constants.MAILING.equals(this.getAddressType()); 
    }
}

代码变得更加语义化:

Stream<String> states = Arrays.stream(item.getState().split(","));
Stream<String> addressType = Arrays.stream(item.getAddressType().split(","));

Map<Boolean, List<String>> splitStates = zip(states, addressTypes, StateData::new)
    .collect(Collectors.partitioningBy(StateData::isMailing), 
        collectors.mapping(StateData::getState()));

List<String> mailingStates = split.get(true);
List<String> physicalStates = split.get(false);

最后一个考虑是为 addressType 创建一个枚举,而不是与常量进行比较。

答案 2 :(得分:0)

您可以使用 partitioningBy 根据 Constants.MAILING.equals(addressType.get(i)) 条件分隔出项目。

Map<Boolean, List<Integer>> map 
    = IntStream.range(0, states.size())
               .boxed()
               .collect(Collectors.partitioningBy(i -> Constants.MAILING.equals(addressType.get(i))));

List<String> mailingStates = map.get(true);
List<String> physicalStates = map.get(false);