确定罪魁祸首的记录-编码实践

时间:2019-06-18 13:47:17

标签: java java-stream

方法链接好吗?

我不是反对使用很多方法链接的函数式编程,而是反对人们无意识地追赶新事物的羊群思想。

示例,如果我正在使用流编程处理项目列表,并且需要找出导致抛出NullPointerException的确切行。

private void test() {
    List<User> aList = new ArrayList<>();
    // fill aList with some data
    aList.stream().forEach(x -> doSomethingMeaningFul(x.getAddress()));
}

private void doSomethingMeaningFul(Address x)   {
     // Do something
}

因此,在上面的示例中,如果列表中的任何对象为null,则在调用NullPointerException时将导致x.getAddress()并退出,而没有给我们提供钩子来标识存在此问题的用户记录

在流编程中,我可能缺少提供此功能的功能,感谢您的帮助。

编辑1: NPE只是一个示例,但是可能还会发生其他几种RuntimeException。编写过滤器实质上意味着根据我正在执行的操作检查每个RTE条件。而且检查所有操作都会很痛苦。

要更好地了解我的意思,下面是使用较旧方法的代码段;我找不到与流/函数式编程方法同等的东西。

List<User> aList = new ArrayList<>();
// Fill list with some data
int counter = 0;
User u = null;

try {
      for (;counter < aList.size(); counter++) {
          u = aList.get(counter);
          u.doSomething();
          int result = u.getX() / u.getY();
      }
} catch(Exception e)  {
  System.out.println("Error processing at index:" + counter + " with User record:" + u);
  System.out.println("Exception:" + e);
}

This will be a boon during the maintenance phase(longest phase) pointing exact data related issues which are difficult to reproduce.
**Benefits:**
- Find exact index causing issue, pointing to data
- Any RTE is recorded and analyzed against the user record
- Smaller stacktrace to look at

4 个答案:

答案 0 :(得分:1)

  

方法链接好吗?

通常,简单的答案是:取决于情况。

当您

  • 知道你在做什么
  • 非常 确保元素永远不会为空,因此在这种构造中使用NPE的机会是(接近)0
  • 呼叫链接可提高可读性

然后确定,连锁电话。

如果没有明确满足上述任何条件,请考虑不这样做。

无论如何,将您的方法调用分布在新行上可能会有所帮助。像IntelliJ这样的工具实际上会为您提供每一行的高级类型信息(嗯,并非总是如此,请参阅我自己的question;)

从不同的角度来看:对于编译器,链接调用并不重要。这实际上仅对人类重要。为了提高可读性,或者在调试过程中。

答案 1 :(得分:0)

在您的test()函数中,您正在创建一个空列表List<User> aList = new ArrayList<>();

在上面做每个。首先向

添加一些元素
  

aList

如果您要处理空值,可以在foreach之前添加.filter(x-> x != null),这样会过滤掉所有空值

下面是代码

private void test() {
        List<User> aList = new ArrayList<>();

        aList.stream().filter(x-> x != null).forEach(x -> doSomethingMeaningFul(x.getAddress()));
}

private void doSomethingMeaningFul(Address x)   {
        // Do something
}

答案 2 :(得分:0)

您可以在流中编写黑色代码。而且,您可以找到可能导致 NullPointerException 的列表项。我希望这段代码对您有所帮助

private void test() {
    List<User> aList = new ArrayList<>();
    aList.stream().forEach(x -> {
        if(x.getAddress() != null)
            return doSomethingMeaningFul(x.getAddress())
        else
            system.out.println(x+ "doesn't have address");
    });
}

private void doSomethingMeaningFul(Address x)   {
 // Do something
}

如果需要,可以在 部分中抛出 NullPointerException 或诸如 AddressNotFoundException 之类的自定义专有内容

答案 3 :(得分:0)

这有几个方面。

1)空值

最好永远不要分配null来避免检查null的问题。无论是否进行函数式编程,这都适用。不幸的是,许多库代码确实暴露了返回空值的可能性,但是试图通过在一个地方处理它来限制对此值的暴露。

不管您是否正在执行FP,如果您在调用自己的方法时都不必编写null检查,您会发现沮丧的程度会减少,因为您自己的方法永远不会返回null。

可能为null的变量的替代方法是使用Java 8的Optional类。

代替:

public String myMethod(int i) {
     if(i>0) {
          return "Hello";
     } else {
          return null;
     }
}

要做:

public Optional<String> myMethod(int i) {
     if(i>0) {
          return Optional.of("Hello");
     } else {
          return Optional.empty();
}

查看Optional Javadoc,以了解这如何迫使调用者考虑发生Optional.empty()响应的可能性。

作为“ null代表不存在”和“ Optional.empty()代表不存在”之间的桥梁,可以使用Optional.ofNullable(val),当Empty时返回val == null。但是请记住,Optional.empty()Optional.of(null)是不同的值。

2)例外

的确,在流处理程序中引发异常不是很好。异常不是非常适合FP的机制。 FP友好的替代方案是Either,它不是Java的标准组成部分,但易于编写或在第三方库中找到:Is there an equivalent of Scala's Either in Java 8?

public Either<Exception, Result> meaningfulMethod(Value val) {
    try {
       return Either.right(methodThatMightThrow(val));
    } catch (Exception e) {
       return Either.left(e);
    }
}

...然后:

List<Either<Exception, Result>> results = listOfValues.stream().map(meaningfulMethod).collect(Collectors.toList());

3)索引

在使用List制成的流时,您想知道流元素的索引吗?参见Is there a concise way to iterate over a stream with indices in Java 8?