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

如何以响应式方式根据产品名称获取对应ID?求更优实现

响应式编程下根据产品名称获取ID的优化实现

刚接触响应式编程与流处理,目前调用服务获取包含产品及其ID的列表,需要根据产品名称返回对应ID。现有测试代码可正常运行,但希望了解更优的实现方案。

现有实体类

Products类

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
@Builder
public class Products {
    private List<Identifier> products;
}

Identifier类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Identifier {
    private long id;
    private String name;
}

现有测试代码

public class ProductStreamTest {
    private String name = "asdf";
    private Products prods; // 注:原代码类名小写products,建议改为符合Java规范的Products

    @BeforeEach
    void testSetup() {
        prods = new Products();
        prods.setProducts(new ArrayList<>());
        prods.getProducts().add(Identifier.builder().id(1L).name(name).build());
        prods.getProducts().add(Identifier.builder().id(2L).name("asdfqwer").build());
    }

    @Test
    void shouldFilterToMatchingName() {
        Long id = Mono.just(prods)   // 实际代码用ObjectMapper转换响应体
                .filter(products -> products.getProducts().stream().anyMatch(product -> product.getName().equals(name)))
                .map(products -> products.getProducts().get(0).getId())
                .block();   // 仅用于测试

        Assertions.assertThat(id).isEqualTo(1L);
    }

    @Test
    void shouldBeNull() {
        Long id = Mono.just(prods)    // 实际代码用ObjectMapper转换响应体
                .filter(products -> products.getProducts().stream()
                        .anyMatch(product -> product.getName().equals("qwerty")))
                .map(products -> products.getProducts().get(0).getId())
                .block();   // 仅用于测试

        Assertions.assertThat(id).isNull();
    }
}

优化方案与代码

现有实现存在两处明显可优化点:一是对产品列表进行了两次遍历(filter阶段的anyMatch和map阶段的get(0)),二是未充分利用Reactor的响应式操作符特性,代码逻辑不够简洁。以下是优化后的实现:

优化后的测试代码

public class ProductStreamTest {
    private String name = "asdf";
    private Products prods;

    @BeforeEach
    void testSetup() {
        prods = Products.builder()
                .products(List.of(
                        Identifier.builder().id(1L).name(name).build(),
                        Identifier.builder().id(2L).name("asdfqwer").build()
                ))
                .build(); // 用Builder模式简化对象初始化
    }

    @Test
    void shouldFilterToMatchingName() {
        Long id = Mono.just(prods)
                .flatMapIterable(Products::getProducts) // 将列表展开为Flux<Identifier>
                .filter(product -> product.getName().equals(name))
                .map(Identifier::getId)
                .next() // 获取第一个匹配项,无匹配则返回Mono.empty()
                .block();

        Assertions.assertThat(id).isEqualTo(1L);
    }

    @Test
    void shouldBeNull() {
        Long id = Mono.just(prods)
                .flatMapIterable(Products::getProducts)
                .filter(product -> product.getName().equals("qwerty"))
                .map(Identifier::getId)
                .next()
                .block();

        Assertions.assertThat(id).isNull();
    }
}

优化说明

  • 减少遍历次数:通过flatMapIterable直接将Products中的列表转为Flux<Identifier>,后续的过滤、映射操作仅遍历一次集合,提升效率。
  • 响应式风格更纯粹:利用Reactor的操作符链式处理,避免在Mono层面手动操作集合,代码可读性和维护性更强。
  • 避免潜在异常:原代码中get(0)在列表为空时会抛出IndexOutOfBoundsException,优化后的next()在无匹配项时返回Mono.empty(),block()后为null,更安全。
  • 简化对象初始化:使用Builder模式替代手动set操作,代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 09:27:51