JavaFX应用程序抛出NullPointerExceptions但仍然运行 [英] JavaFX applications throw NullPointerExceptions but run anyway

查看:205
本文介绍了JavaFX应用程序抛出NullPointerExceptions但仍然运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我运行的每个JavaFX应用程序都会抛出两个NullPointerExceptions。它们不会阻止甚至影响项目的执行,只有在调试模式下运行应用程序时才能看到它们。我甚至遇到了来自Oracle的HelloWorld示例和这个最小程序的问题:

Every JavaFX application I've run throws two NullPointerExceptions. They don't prevent or even affect the execution of the projects, and I can only see them if I run my applications in debug mode. I'm even having this issue with the HelloWorld sample from Oracle and this minimal program:

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);
    }
}

这是第一个错误的堆栈跟踪:

Here is the stack trace of the first error:

 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的实例场景(所以 start()只读 primaryStage.show(); ),不会发生第二个错误。为什么会这样?

What's more, if I remove any instance of iAmRoot and scene (so start() just reads primaryStage.show();), the second error doesn't occur. Why is this happening?

我之前能够找到这个问题( JavaFX应用程序在启动时抛出NullPointerException ),但似乎没有人解决它,并且它在2年前被问过。

I've been able to find this question before (JavaFX application throws NullPointerException at startup), but noone seems to have resolved it, and it was asked over 2 years ago.

如果有帮助,我在Windows 7 Professional上运行Eclipse 4.5.2,我认为我根本不使用FXML。

If it helps, I'm running Eclipse 4.5.2 on Windows 7 Professional, and I don't think I'm using FXML at all.

编辑:

它的价值,我找不到第二个错误的源代码,但我找到了抛出第一个错误的方法的JavaFX代码(第81行:

for what it's worth, I can't find the source code for the second error, but I found JavaFX's code for the method which throws the first error (line 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 }


推荐答案

免责声明



这个问题是1岁,但我觉得还是非常相关。这就是为什么我回答这个问题(详细说明)。

Disclaimer

This question is 1 year old, but i feel like still very relevant. That's why i answer this question (in length).

我会尽力回答这个问题

JavaFX有一些古怪的代码行,这些异常是由它们引起的。所有这些都可以追溯到JavaFX中的某些行,它会错过检查或使用未经检查的部分。

JavaFX has some quirky code-lines and the exceptions are cause by those. All can be traced back to some line in JavaFX, which misses a check or uses an unchecked part.


我运行的每个JavaFX应用程序抛出两个NullPointerExceptions。它们不会阻止甚至影响项目的执行,如果我在调试模式下运行应用程序,我只能看到它们。

Every JavaFX application I've run throws two NullPointerExceptions. They don't prevent or even affect the execution of the projects, and I can only see them if I run my applications in debug mode.



< h1>第一个NullPointerException

您显示的第一个例外位于:

First NullPointerException

The first Exception you shown is located at:


SystemProperties.setVersions()行:81 [局部变量不可用]

SystemProperties.setVersions() line: 81 [local variables unavailable]

您已经发布了相关代码。为了形象化,我将再次发布。问题中的线是:

You already posted the correlating code. To visualize this, i'll post this again. The Line in Problem is:

InputStream is =
            SystemProperties.class.getResourceAsStream(versionResourceName);
try  {
    size = is.available(); // InputStream "is" = null
    ...
} catch (Exception ignore) {
}

这很容易解释。 getResourceAsStream 方法返回以下内容(来自 JavaDoc ):

This is pretty easy explained. The getResourceAsStream method returns the following (from the JavaDoc):


返回:A InputStream对象,如果没有找到具有此名称的资源,则返回null

Returns: A InputStream object or null if no resource with this name is found

这意味着,该资源(您已经发布的资源)找不到/ com / sun / javafx / runtime / resources / version.properties

This means, that the resource (that you again already posted) "/com/sun/javafx/runtime/resources/version.properties" is not found.

然而这是<强>没有处理,但只是被忽略了。这个例外是因为没有打印,但仍然被抛出。它是由调试器捕获的,但就是这样。因此只能由调试器识别。

This however is not handled, but simply ignored. This exception is therefor not printed, but still is thrown. It is catched by the debugger, but that's it. Therefor only identifiable by the debugger.

为什么不能很好地识别。一种可能性是JDK不包含资源。在我对JDK-10(我目前使用的)的测试中,包com.sun.javafx.runtime存在,但子包资源不存在。这不是真正可重现的,因为com.sun包似乎没有记录。 javafx的基础api记录在这里,但com.sun.javafx包不是。如果您使用的是复杂的IDE(例如IntelliJ),您可以查看它。我的JDK-8确实包含它。我在Ubuntu 18.04.1上使用Oracle JDK。

The why is not really well identifiable. One possibility might be that the JDK does not contain the resource. In my tests of the JDK-10 (which i currently use), the package com.sun.javafx.runtime exists, but the sub-package resources does not. This is not really reproducible, since the com.sun package appears to not be documented. The base api of javafx is documented here, but the com.sun.javafx package is not. You can look at it, if you are using a sophisticated IDE (like IntelliJ for example). My JDK-8 does contains it. I use the Oracle JDK on Ubuntu 18.04.1.

一种可能性是,包裹已经被丢弃了。也许有人认为,通过软件包引用资源并不是那么好并将其放在资源路径中,但由于异常被吞没,所以从未检测到此错误。

One possibility might be, that the package has been ditched along the way. Maybe someone thought, that referencing the resource through packages is not that great and put it within the resources path, but since the exception is swallowed into nothing, this error has never been detected.

注意:此潜在修复未经过彻底测试

如果手动引入资源,则可能会修复此问题。考虑到您发布的代码(可以在 SystemProperties.setVersions 方法中找到),您必须在软件包com中创建一个名为version.properties的文件。 sun.javafx.runtime.resources。这个versions.properties应该是这样的:

This issue might be fixed, if you manually introduce the resource. Considering the code you posted (and that can be found within the SystemProperties.setVersions method), you would have to create a file called "version.properties" within the package com.sun.javafx.runtime.resources. This versions.properties should look like something like this:

release=1
full=1

这些是您必须测试的任意值。

Those are arbitrary values which you would have to test.

第二个NullPointer根植于行 PropertyHelper.lambda $ getBooleanProperty $ 514(字符串)行:39 。此方法如下所示:

The second NullPointer is rooted within the line PropertyHelper.lambda$getBooleanProperty$514(String) line: 39. This method looks like this:

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 为null,由来自System.getProperty的JavaDoc

This leads to the conclusion, that the propVal is null, which is backed by the JavaDoc from System.getProperty


返回:系统属性的字符串值,如果没有具有该键的属性,则返回null。

Returns: the string value of the system property, or null if there is no property with that key.

这意味着, propName 。但是 propName 是方法参数。那么,什么是 propName ?这也可以在堆栈跟踪中找到。该行:

This means, the propName is not found. But propName is the method argument. So, what is the propName? This again can be found within the stacktrace. The line:


父。()行:87

Parent.() line: 87

定义应该找到的属性。它读取以下内容:

defines the property that should be found. It reads the following:

private static final boolean warnOnAutoMove = PropertyHelper.getBooleanProperty("javafx.sg.warn");

因此,之前说明的方法试图找到SystemPropertyjavafx.sg.warn,但是不检查它是否存在。这再次没有被处理,因此只能在调试器中看到。

So, the method stated before tries to find the SystemProperty "javafx.sg.warn", but does not check whether or not it exists. This again is not handled and therefor only visible within the debugger.

如果toLowerCase调用被删除,则不会发生此异常。

This Exception would not occur if the "toLowerCase" call would be erased.

您可以通过在引用Parent类之前引入以下代码来简单地修复此异常以任何方式:

You can simply fix this exception, by introducing the following code before referencing the Parent class in any way:

System.setProperty("javafx.sg.warn", "true");

必须在任何引用之前完成,因为此属性是静态的。因此,如果在代码中以任何方式引用此类,则会加载它。一种可能性是,向主类添加一个包含此代码的静态块。另一种方法是将以下添加到命令行

It has to be done before any reference, because this attribute is static. So, if this class is referenced in any way in code, it is loaded. One possibility would be, to add a static block to your main class, which contains this code. Another way would be to add the following to the command line:


-Djavafx.sg.warn =true

-Djavafx.sg.warn="true"

这将消除在引用之前调用代码的需要。当然,你可以换取其他任何东西。但有了这个,属性就存在了,问题行也不会抛出NullPointerException。

This would erase the need to call the code before references. Of course you can exchange true for anything else. But with that, the property exists and the problem line will not throw a NullPointerException.

这很简单。在JavaFx中,要显示的任何元素都是节点 rel =noreferrer>场景图。每个节点可能有这是Node的子类。几乎所有类都扩展了Parent, StackPane ,但不是舞台。通过引用StackPane,您可以引用Parent,它会触发属性的加载。如果未设置StackPane,则不引用Parent类,这意味着您不会触发加载属性。所以没有抛出异常。

This is pretty simple. In JavaFx any element to display is a Node within the Scene graph. Every Node may have a Parent, which is a subclass of Node. Nearly all classes extend Parent, so does the StackPane, but not the Stage. By referencing the StackPane, you reference Parent, which triggers the loading of the property. If you do not set a StackPane, you do not reference the Parent class, which means you do not trigger the loading of the property. So no Exception is thrown.

由于javafx背后的团队似乎忽略了那些例外,你也可以。我不是说这是一种好的做法,或者您应该以这种方式编写代码,但修复那些不会阻止您运行此应用程序并且不会改变行为的问题可能会花费更多的时间而不是它的价值。

Since the team behind javafx appears to ignore those exception, you can too. I do not say that this is good practice or you should code in this way, but fixing those issues, that do not prevent you from running this application and that do not change the behavior may cost more time than it is worth.

这个答案解释了原因为什么,但我想把两分钱给真正的问题。请注意,这只是我的意见!如果你的想法不同,那就完全可以了。不再直接需要回答这个问题。

This answer explained the raw "why", but i want to give my two cents to the real issue. Please note that this is just my opinion! If you do think differently, that's totally okay. It is no longer directly necessary to answer the question.

所有这一切的根源(在我看来)javafx api中有许多代码味道。从所有部分中的魔术字符串开始,通过所有向下转换 .com / teamfx / openjfx-10-dev-rt / blob / master / modules / javafx.graphics / src / main / java / com / sun / javafx / scene / ParentHelper.javarel =noreferrer> ParentHelper.ParentAccessor JavaFX组件内的实现,通过许多大类(甚至可能是上帝类),最后以不恰当的亲密关系结束。抽象本来可以更好,并且(例如)Node类的大小是巨大的。

This root of all of this is (in my opinion) the many many code smells within the javafx api. From magic strings within all parts, over downcasting within all ParentHelper.ParentAccessor implementations within the components of JavaFX, passing by many Large-Classes (maybe even god classes) and finally ending in Inappropriate intimacy. The abstraction could have been much better and the size of (for example) the Node class is way to enormous.

使用新发布周期,我希望他们花时间消除至少部分代码闻起来,但我担心他们只是建立在那些代码气味的基础上,这意味着在某个时候,必须建立一个新的(现代的)GUI-API。

With the new release cycle, my hopes are high that they take their time to eliminate at least some of those code smells, but i fear that they just build upon those code smells, which means that at some time, a new ("modern") GUI-API has to be build.

祝你有愉快的一天!

这篇关于JavaFX应用程序抛出NullPointerExceptions但仍然运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆