在此构造函数中引用字段实例或参数更好吗



我已经编写了这个"CoreException"Exception子类。我在构造函数中似乎有三个选项,它们的行为都相同,因为它们都引用了同一个对象。

*注意:问题是关于编译器和三种不同源代码选项可能的运行时差异。构造的Object可以是任何类。

public class CoreException extends Exception {
private final Class<?> sourceClass;
private final Method sourceMethod;
public CoreException(@NotNull Method method, @NotNull Throwable thr) {
super("this text is irrelevant", thr);
this.setStackTrace(thr.getStackTrace());
this.sourceMethod = method;
this.sourceClass = this.sourceMethod.getDeclaringClass();
}
public Class<?> getSourceClass() { return sourceClass; }
public Method getSourceMethod() { return sourceMethod; }
}

Class<?> sourceClass对象的构造似乎有三个相同的选项:

this.sourceClass = this.sourceMethod.getDeclaringClass();
this.sourceClass = sourceMethod.getDeclaringClass();
this.sourceClass = method.getDeclaringClass();

是否有充分的理由使用一个而不是另一个,也许是因为性能、可靠性/弹性等方面的小幅提高。。?

或者编译器只是简单地将这三个都变成,结果完全相同?

在本例中,this.sourceMethodsourceMethod之间没有区别,生成的字节码将相同。这只是你喜欢的口味问题。有些人喜欢总是使用this.,而另一些人则喜欢只在需要消除歧义时使用this.,如果还有同名的局部变量。

唯一真正的区别是[this.]sourceMethodmethodsourceMethod是对象上的字段,而method是参数。假设method是一个参数,它就在堆栈上,而且它可能比访问对象的字段sourceMethod稍快。然而,总的来说,这种差异可能可以忽略不计,即使不是,JIT编译器也完全有可能以等效的方式对其进行优化。如果你真的需要知道,你应该写一个微观基准来衡量这种差异。

就我个人而言,我认为在使用sourceMethodmethod之间的选择主要是一种意见。

这是个坏主意。您正试图通过API更新来解决您对java这一语言感到不舒服的问题。这是不可行的——绝大多数异常都不会被封装在CoreException中(例如,java核心API本身抛出的任何东西,或者任何第三方库中的任何东西(如JUnit、JDBI等(。

对于其他java程序员来说,您的代码将不再有意义,因为他们不希望通过您的此类重新路由所有异常。

您也将无法编写"适合"现有API(即接口实现(的代码,因为您将被要求编写所有相关异常类型的自己的变体(因为它们需要在层次结构中的某个位置扩展CoreException,而java.*中的异常和任何在例如jdbi.*中编写的异常都不会,并且如果不分叉您使用的每个库,您就无法将它们更新为(。

那我该怎么办

您在异常消息中粘贴的信息已经在纯jane异常中可用,即堆栈跟踪的第一行。在信息中重复这些信息是愚蠢的。

如果你有一些日志记录或错误报告系统,而你目前没有这些信息,并且你希望它,这是一个真正的问题。你只是决定用一种笨拙而不明智的方式来解决它。

相反,更新任何可能的系统,以包括堆栈的第一行。这通常并不难,但取决于让你去的地方:;哦,我真的可以在这里使用方法名称"。

注意,走自己的路有更多的缺点,而不仅仅是"它在现有的API中脱颖而出"。IDE将无法识别这一点,您也无法点击消息中的类+方法名来自动跳转到正确的文件。如果你想要的话,你需要匹配StackTraceElement打印的"风格"。

您的代码也会导致直接的错误结论。当异常从lambda中抛出时,这种方法(具有代表源的Method对象(没有多大意义。

因此,中止计划。无论你想通过将Method sourceMethod作为所有异常状态的一部分来实现什么——你要么不想这样,要么你可以用不同的方式(可能是依靠getStackTrace()[0])来传达它(更好地实现它

public Class<?> getSourceClass() {
return Class.forName(getStackTrace()[0].getClassName());
}

例如,也可以完成这项工作,但请注意,根据异常的来源,此代码可能会失败(抛出ClassNotFoundEx(。并非所有代码都能在"它在这个类和这个方法中"上下文中轻松捕获(核心内容、本地内容、合成方法、桥接器、动态生成代码、lambdas…(

最新更新