最好在此构造函数中引用字段实例或参数?
Better to reference field instance or parameter in this constructor?
我已经写了这个 'CoreException' Exception
subclass。我似乎在构造函数中有三个选项,它们的行为都相同,因为它们都引用同一个对象。
*注意:问题是关于编译器和三种不同源代码选项可能存在的运行时差异。构造的对象可以是任何 class.
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();
是否有合理的理由使用其中一个而不是其他的,也许是因为性能、可靠性/弹性等方面的边际提高?
或者编译器只是将所有这三个变成完全相同的结果?
这是个坏主意。您正在尝试通过 API 更新来解决您对 java 语言感到不舒服的问题。这行不通——绝大多数异常不会被包装在 CoreException 中(例如 java 核心 API 本身抛出的任何东西,或任何第三方库中的任何东西,如 JUnit、JDBI等等)。
您的代码将不再对其他 java 程序员有意义,他们不需要通过您的 class 重新路由所有异常。
您也无法在现有的 API 中编写 'fits' 的代码(即接口的实现),因为您将需要编写所有相关异常的自己的变体类型(因为它们需要在层次结构中的某个地方扩展 CoreException
,而 java.*
中的异常和任何写在例如 jdbi.*
中的东西都不会,你不能将它们更新为没有分叉你使用的每个库)。
那我该怎么办?
您在该异常消息中粘贴的信息已经在简单的简异常中可用 - 堆栈跟踪的第一行。在消息中重复此信息是愚蠢的。
如果您有一些日志记录或错误报告系统,而您目前没有这些信息,而您又想要它,那就是一个真正的问题。您刚刚决定以一种笨拙且不可取的方式解决它。
相反,更新该系统可能包含堆栈跟踪的第一行。这通常不难,但这取决于让你去的地方:“哦,我真的可以在这里使用方法名称”。
请注意,走自己的路比 'it stands out in existing APIs like a sore thumb' 有更多的缺点。 IDE 将无法识别这一点,您将无法单击消息中的 class+ 方法名来自动跳转到正确的文件。如果需要,您需要匹配 StackTraceElement 打印的 'style'。
您的代码也会直接导致错误的结论。当从 lambda 中抛出异常时,这种方法(具有代表源的 Method
对象)没有多大意义。
因此,中止计划。无论您想通过使 Method sourceMethod
成为所有异常状态的一部分来完成什么——您要么不想要它,要么您可以用不同的方式更好地完成它(并且可能依靠 getStackTrace()[0])
传达它。
public Class<?> getSourceClass() {
return Class.forName(getStackTrace()[0].getClassName());
}
也可以完成这项工作,例如,但请注意,此代码可能会失败(抛出 ClassNotFoundEx),具体取决于异常的来源。并非所有代码都可以在 'it is in this class and in this method' 上下文中轻松捕获(核心内容、本机内容、合成方法、桥接程序、动态生成的代码、lambdas...)
示例中,this.sourceMethod
和sourceMethod
没有区别,生成的字节码是一样的。这只是您喜欢的口味问题。有些人喜欢总是使用 this.
,而其他人则喜欢只在有必要消除歧义时使用 this.
,如果还有一个同名的局部变量。
唯一真正的区别是[this.]sourceMethod
和method
:sourceMethod
是对象上的一个字段,而method
是一个参数。鉴于 method
是一个参数,它在堆栈上,并且它可能比访问对象的字段 sourceMethod
稍微快一些。然而,在宏伟的计划中,这种差异可能可以忽略不计,即使不是,JIT 编译器也完全有可能以它们等效的方式优化它。如果你真的需要知道,你应该写一个微基准来衡量这种差异。
就个人而言,我会考虑使用 sourceMethod
或 method
之间的选择主要是一种意见。
我已经写了这个 'CoreException' Exception
subclass。我似乎在构造函数中有三个选项,它们的行为都相同,因为它们都引用同一个对象。
*注意:问题是关于编译器和三种不同源代码选项可能存在的运行时差异。构造的对象可以是任何 class.
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();
是否有合理的理由使用其中一个而不是其他的,也许是因为性能、可靠性/弹性等方面的边际提高?
或者编译器只是将所有这三个变成完全相同的结果?
这是个坏主意。您正在尝试通过 API 更新来解决您对 java 语言感到不舒服的问题。这行不通——绝大多数异常不会被包装在 CoreException 中(例如 java 核心 API 本身抛出的任何东西,或任何第三方库中的任何东西,如 JUnit、JDBI等等)。
您的代码将不再对其他 java 程序员有意义,他们不需要通过您的 class 重新路由所有异常。
您也无法在现有的 API 中编写 'fits' 的代码(即接口的实现),因为您将需要编写所有相关异常的自己的变体类型(因为它们需要在层次结构中的某个地方扩展 CoreException
,而 java.*
中的异常和任何写在例如 jdbi.*
中的东西都不会,你不能将它们更新为没有分叉你使用的每个库)。
那我该怎么办?
您在该异常消息中粘贴的信息已经在简单的简异常中可用 - 堆栈跟踪的第一行。在消息中重复此信息是愚蠢的。
如果您有一些日志记录或错误报告系统,而您目前没有这些信息,而您又想要它,那就是一个真正的问题。您刚刚决定以一种笨拙且不可取的方式解决它。
相反,更新该系统可能包含堆栈跟踪的第一行。这通常不难,但这取决于让你去的地方:“哦,我真的可以在这里使用方法名称”。
请注意,走自己的路比 'it stands out in existing APIs like a sore thumb' 有更多的缺点。 IDE 将无法识别这一点,您将无法单击消息中的 class+ 方法名来自动跳转到正确的文件。如果需要,您需要匹配 StackTraceElement 打印的 'style'。
您的代码也会直接导致错误的结论。当从 lambda 中抛出异常时,这种方法(具有代表源的 Method
对象)没有多大意义。
因此,中止计划。无论您想通过使 Method sourceMethod
成为所有异常状态的一部分来完成什么——您要么不想要它,要么您可以用不同的方式更好地完成它(并且可能依靠 getStackTrace()[0])
传达它。
public Class<?> getSourceClass() {
return Class.forName(getStackTrace()[0].getClassName());
}
也可以完成这项工作,例如,但请注意,此代码可能会失败(抛出 ClassNotFoundEx),具体取决于异常的来源。并非所有代码都可以在 'it is in this class and in this method' 上下文中轻松捕获(核心内容、本机内容、合成方法、桥接程序、动态生成的代码、lambdas...)
示例中,this.sourceMethod
和sourceMethod
没有区别,生成的字节码是一样的。这只是您喜欢的口味问题。有些人喜欢总是使用 this.
,而其他人则喜欢只在有必要消除歧义时使用 this.
,如果还有一个同名的局部变量。
唯一真正的区别是[this.]sourceMethod
和method
:sourceMethod
是对象上的一个字段,而method
是一个参数。鉴于 method
是一个参数,它在堆栈上,并且它可能比访问对象的字段 sourceMethod
稍微快一些。然而,在宏伟的计划中,这种差异可能可以忽略不计,即使不是,JIT 编译器也完全有可能以它们等效的方式优化它。如果你真的需要知道,你应该写一个微基准来衡量这种差异。
就个人而言,我会考虑使用 sourceMethod
或 method
之间的选择主要是一种意见。