Java 流中的异常处理 背景

Java 流中的异常处理 背景,java,functional-programming,vavr,Java,Functional Programming,Vavr,我一直着迷于处理异常的模型:有一个侧通道,所有坏的东西都将在那里处理,好的东西保持在主轨道上。下图: 问题 日常代码中出现的常见模式如下: 有一个数据列表 验证它们中的每一个 验证可以引发异常 问题: 如何以类似于上面讨论的面向铁路的模型的方式执行此操作。处理“侧轨”上异常的简单方法是使用Vavr提供的peek Left方法,该方法使用任择.Left()侧。我们可以将异常处理逻辑插入其中,并将或.right()的内容很好地放在主轨道上,而不会有任何问题 我很确定这是可以改进的,我也很想知道

我一直着迷于处理异常的模型:有一个侧通道,所有坏的东西都将在那里处理,好的东西保持在主轨道上。下图:

问题 日常代码中出现的常见模式如下:

  • 有一个数据列表
  • 验证它们中的每一个
  • 验证可以引发异常
问题:
如何以类似于上面讨论的面向铁路的模型的方式执行此操作。

处理“侧轨”上异常的简单方法是使用Vavr提供的
peek Left
方法,该方法使用
任择.Left()
侧。我们可以将异常处理逻辑插入其中,并将
或.right()
的内容很好地放在主轨道上,而不会有任何问题

我很确定这是可以改进的,我也很想知道如何改进

List errors=new ArrayList();
@试验
公共void composeExceptions(){
List valids=IntStream.range(0,11).boxed()
.map(this::validate)//引发异常
.peek(this::handleExceptions)//进程左侧/异常侧
.flatMap(Value::toJavaStream)//flatMap是基于右键的
.collect(Collectors.toList());
System.out.println(“===================好的===========”);
系统输出打印项次(valids);
System.out.println(“================坏的===========”);
errors.forEach(System.out::println);
}
公共无效句柄异常(任一){
.peekleet(e->errors.add(e.getMessage());//这是一个单体绑定吗???
}
公共或验证(整数i){
if(i%2==0)返回其中一个。右(i);
返回任意一个.left(新的IllegalArgumentException(“奇数1's out:+i));
}

[Somjit's][1]的答案显示了正确的方法,但它使用外部变量(
errors
)来累积错误。一般来说,这是不鼓励的,因为我们应该避免全球/外部状态

您可以使用vavr的[
分区
][2]方法将流分成两部分:一部分有错误,另一部分有已验证的整数。它们都被放入一个元组中:

public void composeExceptions() {
   final Tuple2<Stream<Either<IllegalArgumentException, Integer>>, Stream<Either<IllegalArgumentException, Integer>>> both = Stream.range(1, 11)
            .map(this::validate)
            .partition(Either::isLeft);

   both._1.map(Either::getLeft).forEach(e -> System.out.println("Got error: " + e.getMessage()));
   both._2.map(Either::get).forEach(i -> System.out.println("Validated correctly: " + i));
}

美好的似乎目前只在alpha版本中。希望我们能在一般版本中看到它soon@Somjit链接是到alpha版本的,但它也包含在基本分支中。这是基本功能之一。
Stream
   .range(1, 11)
   .map(this::validate)
   .toJavaStream()
   .collect(Collectors.teeing(
      Collectors.filtering(Either::isLeft, toList()),
      Collectors.filtering(Either::isRight, toList()),
      (errors, ints) -> new Tuple2<>(errors.stream().map(Either::getLeft), ints.stream().map(Either::get))));
Stream
   .range(1, 11)
   .map(this::validate)
   .collect(
      () -> new Tuple2<>(List.<RuntimeException>empty().asJavaMutable(), List.<Integer>empty().asJavaMutable()),
      (tuple, either) -> {
         either.peekLeft(tuple._1::add);
         either.peek(tuple._2::add);
      },
      (t1, t2) -> {
         t1._1.addAll(t2._1);
         t1._2.addAll(t2._2);
      }
    )
       .map((exceptions, integers) -> new Tuple2<>(List.ofAll(exceptions), List.ofAll(integers)));```

which uses vavr API only but underneath uses java `List` since a mutable structure is required here.

  [1]: https://stackoverflow.com/a/67556075/542270
  [2]: https://www.javadoc.io/doc/io.vavr/vavr/latest/io/vavr/collection/Traversable.html#partition(java.util.function.Predicate)