如何获取行';Java stacktraces中的列号

如何获取行';Java stacktraces中的列号,java,stack-trace,Java,Stack Trace,在某些语言中,可以获取stacktrace中一行的列号,但是在Java中,我们只有行号 举个例子,用另一种语言,我们可以: Error at <anonymous>:2:2 at Object.InjectedScript._evaluateOn (<anonymous>:641:39) at Object.InjectedScript._evaluateAndWrap (<anonymous>:580:52) at Objec

在某些语言中,可以获取stacktrace中一行的列号,但是在Java中,我们只有行号

举个例子,用另一种语言,我们可以:

Error
    at <anonymous>:2:2
    at Object.InjectedScript._evaluateOn (<anonymous>:641:39)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:580:52)
    at Object.InjectedScript.evaluate (<anonymous>:495:21)"
这导致行
88
,其中包含

URI=uriInfo.getBaseUriBuilder().path(objectA.path(objectB.build())

使用stacktrace,我无法检查是哪个
.path
调用导致了异常。所以我的问题是,有没有什么解决方案可以让我获得专栏的引用

(为了避免一些可能的替代答案,我们需要一个解决方案来获取列号,其他答案(如如何单步执行调试器或重构每个构建器模式等)不会回答这个问题)

这是不可能的

通过以这种方式格式化代码,您可以绕过它:

URI uri = uriInfo
           .getBaseUriBuilder()
           .path(objectA)
           .path(objectB)
           .build();

在OracleJava8中,您可以编写

public static void main(String... ignored) {
    List<String> s = new ArrayList<>();
    s.add("hello");

    Predicate<? super String> predicate1 = (t) -> t.length() > 0;
    Predicate<? super String> predicate2 = (t) -> t.length() < 8;
    Predicate<? super String> predicate3 = null;

    List<String> collect = s.stream()
            .filter(predicate1) // 16
            .filter(predicate2) // 17
            .filter(predicate3) // 18
            .collect(Collectors.toList());
}

对于OracleJDK来说,这似乎只适用于Java8,而不是Java7。

对Java进行反向工程将是非常痛苦的。从理论上讲,您可以分析原始源代码,并找出哪些表达式可能引发此类异常

如果您有这个问题,很可能您的线路太复杂/密集。大多数IDE使重构表达式以提取部分代码变得非常容易。这将为您提供更多异常抛出位置的解决方案


这个特定问题的另一个解决方案是使用@NotNull的方法,IDE可以检测哪些参数可以为null,但永远不应该为null

URI uri = uriInfo.getBaseUriBuilder().path(objectA)
                                     .path(/*highlighted*/objectB).build();
IDE可以警告您正在将一个变量传递给一个不能接受
null
的方法。如果这样做,您将更早地发现这些错误,从而更容易修复。(IDE附带了一些快速修复)

注意:一般来说,如果参数传递不正确,API应该抛出一个NullPointerException IMHO,但是通常会抛出一个不一致的IllegalArgumentException

在我看来,IllegalArgumentException的一个论点是:

  • IllegalArgumentException是您可能期望应用程序捕获的内容。捕捉NullPointerException真的很难闻
  • 无效
    null
    的处理应与其他不正确参数(如长度-1)相同

null
传递给不接受
null
的方法是一个编程错误,不是提供错误输入的问题。

您无法从堆栈跟踪中获取列

您可以使用中间变量,使每个方法调用位于不同的行上:

UriBuilder builder = uriInfo.getBaseUriBuilder();
builder = builder.path(objectA);
builder = builder.path(objectB);
URI uri = builder.build();

这很痛苦,但它可以暂时帮助您找到问题,然后您可以将其恢复原状。

类文件的标准行调试信息不包含列号。解决这个问题最简单的方法是在链式调用之间插入换行符。我认为这是不可能的,真的没有自动完成这项工作的工具吗?例如,我使用EclEmma进行代码覆盖,或多或少插入某种隐藏标记,以查看代码到达的位置-应该是可能的,不是吗?我想您可以编写自己的Java编译器。除此之外,我认为你运气不好。嗯,有一些自动源代码格式化工具,可以配置它们来完成这项任务。但是为你搜索一个工具并不是stackoverflow的范围。很长一段时间以来,我一直梦想着一个更好的行号替代品。IDK,可能是一些标记或表达式索引。除了解决这个问题,一旦行号和列号变得无关紧要,我们可以用一些规范格式保存源代码,并且在IDE支持下,每个开发人员都可以使用自己喜欢的格式样式。我不确定这是否总是有效。我经常看到第一行被责怪。我刚刚测试了这一点,实际上这指向了编译器依赖的第一行(这里使用Oracle Java 7),即
javac
生成的代码会责怪第一行,而eclipse则会按预期做。IMHO,报告实际行会更好,所以我记得我很失望@user1066946:Eclipse确实配备了自己的java编译器,它的性能最好。@hiergiltdiestfu我同意:)嗯,这只是一种发现问题的方法。然后可以将代码放回其原始形式。不管怎样,NPE是一个编程错误,正确的
IllegalArgumentException
s不需要如此痛苦的解决方法。一般来说,如果传递的null参数不正确,API应该抛出一个NullPointerException IMHO——我完全不同意。如果
null
作为参数是非法的,那么
IllegalArgumentException
就非常有意义,应该使用它。@Joffrey我同意。NPE总是在我的评论员头上打出“他/她没有正确处理那个案子,缺少一些警卫”的标志。当合同意味着防止null时,应始终使用IAE或ISE(如果某些参数的有效性取决于之前对该对象所做的更改,即状态),则ISE可以有效使用。
IllegalArgumentException
NullPointerException
都表示编程错误。如果参数为
null
,jre类更喜欢NPE,因此我建议遵循该模式。@user1066946简言之,使用多行,Java 8或eclipse应该可以工作。@Holger都表示编程错误——我同意,但IMHO,NPE是被调用代码中的编程错误,而IAE是调用代码中的一个编程错误。我同意JRE经常用NPE代替IAE,但我不同意这个决定。好吧,我想这只是一个意见问题,不应该在这里讨论,但在那里:
URI uri = uriInfo.getBaseUriBuilder().path(objectA)
                                     .path(/*highlighted*/objectB).build();
UriBuilder builder = uriInfo.getBaseUriBuilder();
builder = builder.path(objectA);
builder = builder.path(objectB);
URI uri = builder.build();