You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 11嵌套for循环转Stream:构建Location后地址赋值方法疑问

将嵌套for循环的Java代码转换为Java 11 Stream实现

问题描述

需要将下面的嵌套for循环Java代码转换成Java 11 Stream实现:

private static List<Location> extractLocation(List<Location> locations){
        List<Location> locationList = new ArrayList<>();
        for(Location l : locations){
            if(l!=null){
                final Location location = Location.builder()
                        .id(l.getId())
                        .build();
                for(Address address: l.getAddresses()){
                    if(address.getType().equals("primary")){
                        location.setPrimaryAddress(address);
                    }
                    else{
                        location.setBillingAddress(address);
                    }
                }
                locationList.add(location);
            }
        }
        return locationList;
    }

目前已写出部分Stream代码,但在构建完Location对象后,不清楚用哪种Stream方法处理地址赋值逻辑:

private static List<Location> extractLocationStream(List<Location> locations){
        return locations.stream()
                .filter(location -> location!=null)
                .map(location ->
                {
                    Location l = Location.builder()
                        .id(location.getId())
                        .build();
                    location.getAddresses().stream()
                            .filter(address -> address.getType().equals("primary")).// what to do now
                })

                .collect(Collectors.toList());
    }

相关实体类定义:

@Data
@AllArgsConstructor
class Address{
    private int id;
    private String type;
}

@Data
@AllArgsConstructor
@Builder
class Location{
    private int id;
    private List<Address> addresses;
    private Address primaryAddress;
    private Address billingAddress;

}

解决方案

你可以通过直接遍历地址完成赋值,或者先按地址类型分组再赋值,以下是两种符合需求的完整Stream实现:

方案一:基于forEach的直观实现

这种方式和原for循环逻辑完全对齐,直接遍历地址完成Builder赋值:

import java.util.Objects;
import java.util.List;
import java.util.stream.Collectors;

private static List<Location> extractLocationStream(List<Location> locations) {
    return locations.stream()
            .filter(Objects::nonNull)
            .map(originalLoc -> {
                // 初始化Location Builder
                Location.LocationBuilder locBuilder = Location.builder()
                        .id(originalLoc.getId());
                
                // 遍历地址,给Builder设置对应字段
                originalLoc.getAddresses().forEach(address -> {
                    if ("primary".equals(address.getType())) {
                        locBuilder.primaryAddress(address);
                    } else {
                        locBuilder.billingAddress(address);
                    }
                });
                
                return locBuilder.build();
            })
            .collect(Collectors.toList());
}

方案二:基于分组的高效实现

如果地址列表中存在多个同类型地址(比如多个primary),这种方式会保留最后一个匹配的地址(和原for循环后续地址覆盖旧值的逻辑一致):

import java.util.Map;
import java.util.Objects;
import java.util.List;
import java.util.stream.Collectors;

private static List<Location> extractLocationStream(List<Location> locations) {
    return locations.stream()
            .filter(Objects::nonNull)
            .map(originalLoc -> {
                // 按地址类型分组,保留最后一个匹配的地址
                Map<String, Address> addressMap = originalLoc.getAddresses().stream()
                        .collect(Collectors.toMap(
                                Address::getType,
                                addr -> addr,
                                (oldAddr, newAddr) -> newAddr // 新地址覆盖旧地址
                        ));
                
                return Location.builder()
                        .id(originalLoc.getId())
                        .primaryAddress(addressMap.get("primary"))
                        .billingAddress(addressMap.getOrDefault("", addressMap.get(null))) // 匹配非primary的地址
                        .build();
            })
            .collect(Collectors.toList());
}

关键说明

  1. 用Objects::nonNull方法引用替代location -> location != null,代码更简洁规范。
  2. 直接基于Location的Builder操作,避免先构建空对象再调用setter,更符合Builder模式的设计初衷。
  3. 两种方案都完全复刻原for循环的业务逻辑:过滤空Location、提取ID、按地址类型赋值对应字段。

内容的提问来源于stack exchange,提问作者nanosoft

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 01:57:44