如何以响应式方式根据产品名称获取对应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
相关产品推荐
相关产品推荐

