我运行的每个JavaFX应用程序都会抛出两个NullPointerExceptions。它们不会阻止甚至影响项目的执行,只有在调试模式下运行应用程序时才能看到它们。我甚至遇到了来自Oracle的HelloWorld示例和这个最小程序的问题:
public class JavaFXTSample extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
StackPane iAmRoot = new StackPane();
Scene scene = new Scene(iAmRoot, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main (String[] args) {
launch(args);
}
}
这是第一个错误的堆栈跟踪:
Thread [main] (Suspended (exception NullPointerException))
SystemProperties.setVersions() line: 81 [local variables unavailable]
SystemProperties.lambda$static$28() line: 67
30621981.run() line: not available
AccessController.doPrivileged(PrivilegedAction<T>) line: not available [native method]
SystemProperties.<clinit>() line: 64
LauncherImpl.startToolkit() line: 668
LauncherImpl.launchApplicationWithArgs(String, String, String[]) line: 337
LauncherImpl.launchApplication(String, String, String[]) line: 328
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available
Method.invoke(Object, Object...) line: not available
LauncherHelper$FXHelper.main(String...) line: not available
这是第二个:
Thread [JavaFX Application Thread] (Suspended (exception NullPointerException))
PropertyHelper.lambda$getBooleanProperty$514(String) line: 39
7164036.run() line: not available
AccessController.doPrivileged(PrivilegedAction<T>) line: not available [native method]
PropertyHelper.getBooleanProperty(String) line: 37
Parent.<clinit>() line: 87
JavaFXTSample.start(Stage) line: 16
LauncherImpl.lambda$launchApplication1$162(AtomicBoolean, Application) line: 863
2266602.run() line: not available
PlatformImpl.lambda$runAndWait$175(Runnable, CountDownLatch) line: 326
32251660.run() line: not available
PlatformImpl.lambda$null$173(Runnable) line: 295
11305869.run() line: not available
AccessController.doPrivileged(PrivilegedAction<T>, AccessControlContext) line: not available [native method]
PlatformImpl.lambda$runLater$174(Runnable, AccessControlContext) line: 294
30052382.run() line: not available
InvokeLaterDispatcher$Future.run() line: 95
WinApplication._runLoop(Runnable) line: not available [native method]
WinApplication.lambda$null$148(int, Runnable) line: 191
32126786.run() line: not available
Thread.run() line: not available
更重要的是,如果我删除iAmRoot
和scene
的任何实例(因此start()
只读primaryStage.show();
),则不会发生第二个错误。为什么会这样?
我之前能够找到这个问题(JavaFX application throws NullPointerException at startup),但似乎没有人解决它,并且在2年前被问过。
如果有帮助,我在Windows 7 Professional上运行Eclipse 4.5.2,我认为我根本不使用FXML。
编辑:
为了它的价值,我找不到第二个错误的源代码,但是我找到了抛出第一个错误的方法的JavaFX代码(第81行):
58 private static final String versionResourceName =
59 "/com/sun/javafx/runtime/resources/version.properties";
...
78 private static void setVersions() {
79 int size;
80 InputStream is =
81 SystemProperties.class.getResourceAsStream(versionResourceName);
82 try {
83 size = is.available();
84
85 byte[] b = new byte[size];
86 int n = is.read(b);
87 String inStr = new String(b, "utf-8");
88 SystemProperties.setFXProperty("javafx.version",
89 getValue(inStr, "release="));
90
91 SystemProperties.setFXProperty("javafx.runtime.version",
92 getValue(inStr, "full="));
93
94 } catch (Exception ignore) {
95 }
96 }
答案 0 :(得分:8)
这个问题已经有1年历史了,但我仍然觉得非常相关。这就是为什么我回答这个问题(长度)。
我将尽我所能回答这个问题
JavaFX具有一些古怪的代码行,并且异常是由这些代码行引起的。所有这些都可以追溯到JavaFX中的某些行,该行错过了检查或使用了未经检查的部分。
我运行的每个JavaFX应用程序都抛出两个NullPointerExceptions。它们不会阻止甚至影响项目的执行,只有在调试模式下运行应用程序时,我才能看到它们。
您显示的第一个异常位于:
SystemProperties.setVersions()行:81 [本地变量不可用]
您已经发布了相关代码。为了可视化,我将再次发布。问题所在的行是:
InputStream is =
SystemProperties.class.getResourceAsStream(versionResourceName);
try {
size = is.available(); // InputStream "is" = null
...
} catch (Exception ignore) {
}
这很容易解释。 getResourceAsStream
方法返回以下内容(来自JavaDoc):
返回:一个InputStream对象;如果找不到具有该名称的资源,则为null
这意味着找不到资源(您已经再次发布)"/com/sun/javafx/runtime/resources/version.properties"
。
这是未处理的,只是被忽略了。因此未打印此异常,但仍抛出该异常。它被调试器捕获,仅此而已。因此只能由调试器识别。
原因尚不清楚。一种可能是JDK不包含资源。在我对JDK-10的测试中(我目前正在使用),包com.sun.javafx.runtime存在,但子包资源不存在。由于com.sun软件包似乎没有记录,因此这实际上不是可重复的。 here记录了Javafx的基本api,但没有com.sun.javafx软件包。如果您使用的是复杂的IDE(例如IntelliJ),则可以查看一下。我的JDK-8确实包含它。我在Ubuntu 18.04.1。上使用Oracle JDK。
一种可能是包装已沿途抛弃。也许有人认为,通过包引用资源不是那么好,并将其放在资源路径中,但是由于该异常被吞没了,因此从未检测到该错误。
注意:此潜在修补程序尚未经过全面测试
如果您手动引入该资源,则可能会解决此问题。考虑到您发布的代码(可以在SystemProperties.setVersions
方法中找到),您必须在com.sun.javafx.runtime.resources包中创建一个名为“ version.properties”的文件。此版本。属性应如下所示:
release=1
full=1
这些是必须测试的任意值。
第二个NullPointer植根于行PropertyHelper.lambda$getBooleanProperty$514(String) line: 39
中。此方法如下所示:
static boolean getBooleanProperty(final String propName) {
try {
boolean answer = AccessController.doPrivileged((java.security.PrivilegedAction<Boolean>) () -> {
String propVal = System.getProperty(propName);
return "true".equals(propVal.toLowerCase()); // Line 39
});
return answer;
} catch (Exception any) {
}
return false;
}
这得出结论,propVal
为空,并得到JavaDoc from System.getProperty的支持
返回:系统属性的字符串值;如果没有带有该键的属性,则返回null。
这意味着找不到propName
。但是propName
是方法参数。那么,propName
是什么?再次可以在堆栈跟踪中找到。该行:
Parent。()第87行:
定义应找到的属性。它显示以下内容:
private static final boolean warnOnAutoMove = PropertyHelper.getBooleanProperty("javafx.sg.warn");
因此,前面所述的方法尝试找到SystemProperty“ javafx.sg.warn”,但不检查它是否存在。再次无法处理,因此仅在调试器中可见。
如果删除“ toLowerCase”调用,则不会发生此异常。
您可以通过以下任何一种方式简单地解决此异常,只需引入以下代码即可之前以任何方式引用Parent类:
System.setProperty("javafx.sg.warn", "true");
它必须在任何引用之前完成,因为此属性是静态的。因此,如果以任何方式在代码中引用了此类,则将加载它。一种可能是在您的主类中添加一个静态块,其中包含此代码。另一种方法是添加以下to the command line:
-Djavafx.sg.warn =“ true”
这将消除在引用之前调用代码的需要。当然,您可以将True换成其他任何东西。但是,有了该属性,问题行将不会抛出NullPointerException。
Stage.show
,为什么不引发第二个异常?这很简单。在JavaFx中,要显示的任何元素都是Scene graph中的Node
。每个节点可能有一个Parent
,which is a subclass of Node。几乎所有类都扩展了父级so does the StackPane,但扩展了not the Stage。通过引用StackPane,您引用了Parent,这触发了属性的加载。如果未设置StackPane,则不会引用Parent类,这意味着您不会触发属性的加载。因此不会引发异常。
由于javafx背后的团队似乎忽略了这些异常,因此您也可以这样做。我并不是说这是一种好习惯,也不应该以这种方式编写代码,但是要解决这些问题,这些问题不会阻止您运行此应用程序,并且不会更改行为,因此可能会花费更多的时间。
这个答案解释了原始的“为什么”,但是我想为真正的问题付两美分。请注意,这只是我的意见!如果您确实有不同的想法,那完全可以。不再需要直接回答这个问题。
所有这些的根源(在我看来)是javafx api中许多代码的味道。从JavaFX组件中所有downcasting实现中的ParentHelper.ParentAccessor到所有部分的魔术字符串,经过许多大型类(甚至是上帝类),最后以不适当的亲密关系结束。本来可以更好地进行抽象,并且(例如)Node类的大小可以达到巨大的目的。
我对new release cycle寄予厚望,希望他们花费时间消除至少一些代码异味,但是我担心它们只是建立在这些代码异味的基础上,这意味着在某个时候,必须构建新的(“现代”)GUI-API。
祝你有美好的一天!