为什么javafx忽略main的返回,仍然启动应用程序?

为什么javafx忽略main的返回,仍然启动应用程序?,java,javafx,return,main,Java,Javafx,Return,Main,我有以下代码 public static void main(String[] args) { if (!ArgumentsHandler.handle(args)) { return; } Storage.getInstance().load(); if (!Storage.getInstance().isLoadSuccessful()) { launch(args); } else

我有以下代码

public static void main(String[] args)
{
    if (!ArgumentsHandler.handle(args))
    {
        return;
    }

    Storage.getInstance().load();

    if (!Storage.getInstance().isLoadSuccessful())
    {
        launch(args);
    }
    else
    {
        System.err.println("Unable to load configurations.");
    }
}
我已经明确指出if语句中的条件使其失败,并且我可以在调试器中清楚地看到它没有执行启动方法,但应用程序窗口仍在显示

我还注意到,在main方法中使用return语句没有任何效果——应用程序仍然继续执行。它只响应System.exit0

为什么会这样

更新:

按照您的要求,这里是ArgumentsHandler的一个片段。在这里,我没有使用线程,至少是有意的

public static boolean handle(String[] args)
{
    //handle args
    if (args.length > 0)
    {
        switch (args[0])
        {
            //createRepository
            case "-c":
                configure(args);
                break;
            case "-r":
            case "--repository":
                repository(args);
                break;
            default:
                help();
                break;
        }

        return false;
    }

    return true;
}

private static void configure(String[] args)
{
    if (args.length > 1)
    {
        boolean isRandom = false;

        switch (args[1])
        {
            case "true":
            case "1":
                isRandom = true;
                break;
            case "false":
            case "0":
                //valid input, ignored
                break;
            default:
                System.err.println("Invalid arguments. Possible values: [--configuration] [1/0].");
                return;
        }

        Storage.configure(isRandom); //creates a bunch of json files (uses NIO).
        return;
    }
    else
    {
        System.err.println("Invalid arguments. Possible values: -c [1/0].");
    }
}
储藏

public void load()
{
    isLoadSuccessful = false;

    //load configuration
    app = loadConfiguration(appFilePath);

    if (app == null)
    {
        System.err.println("Unable to load app configuration.");
        return;
    }

    //load company
    company = loadCompany(app.getCompanyFilePath());

    if (company == null)
    {
        System.err.println("Unable to load company configuration.");
        return;
    }

    repository = loadRepository(app.getRepositoryFilePath());

    if (repository == null)
    {
        System.err.println("Unable to load repository configuration.");
        return;
    }

    isLoadSuccessful = true;
}

private static App loadConfiguration(String filePath)
{
    return (App) Utility.load(filePath, App.class);
}
loadConfiguration、loadCompany和loadRepository实际上是相同的。将来,它们不会读取简单的json文件,而是访问复杂的归档文件,这就是为什么我已经创建了几个几乎相同的方法

公用事业负荷

public static Object load(String path, Type type)
{
    try
    {
        JsonReader reader = new JsonReader(new FileReader(path));
        Gson gson = new Gson();
        Object obj = gson.fromJson(reader, type);
        reader.close();

        return obj;
    }
    catch (IOException ex)
    {
        ex.printStackTrace();
        return null;
    }
}

只是从文件中反序列化对象。

根据您调用launchargs的方式,我假设,稍后您会看到,main方法位于应用程序的子类中。我相信这就是你问题的原因

正如您所注意到的,有许多看似特定于JavaFX的线程正在运行。具体地说,非守护进程JavaFX应用程序线程正在运行,至少在Java10中是非守护进程。即使主线程退出,该线程也会使JVM保持活动状态。这是Java的正常行为:

java.lang.Thread

当Java虚拟机启动时,通常有一个非守护进程线程,该线程通常调用某个指定类的main方法。Java虚拟机将继续执行线程,直到发生以下任一情况:

类运行时的exit方法已被调用,并且安全管理器已允许执行exit操作。 所有不是守护进程线程的线程都已死亡,要么是通过调用run方法返回,要么是通过抛出传播到run方法之外的异常。 但是,为什么JavaFX应用程序线程在您故意不调用Application.launch的情况下启动呢?我只是在这里猜测,但这可能与JavaFX应用程序收到的特殊待遇有关。至少在Java8中,您不必在Application1的子类中声明main方法。如果主类是应用程序的子类,Java将自动处理启动

import javafx.application.Application;
import javafx.stage.Stage;

public class MyApp extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        // create scene and show stage...
    }

}
如果您具有上述功能并调用java MyApp,则应用程序将启动并调用start。但是,如果您具备以下条件:

import javafx.application.Application;
import javafx.stage.Stage;

public class MyApp extends Application {

    public static void main(String[] args) {}

    @Override
    public void start(Stage primaryStage) throws Exception {
        // create scene and show stage...
    }

}
然后调用main方法,但不调用start。基本上,显式声明main会覆盖启动JavaFX应用程序的默认行为,但不会阻止初始化JavaFX运行时。也许这种行为是故意的,也可能是疏忽。但这里重要的是,只有当主类有一个main方法并且是一个应用程序子类时,才会发生这种情况。如果将这两者分开:

public class MyApp extends Application {
    // implement ...
}

public class Main {
    public static void main(String[] args) {
        // Perform pre-checks, return if necessary
        Application.launch(MyApp.class, args);
    }
}
那么你就不会再有这个问题了

否则,您可以继续使用System.exit或切换到Platform.exit

还有另一种可能更合适的方法来处理这个问题。在调用Application.launch之前,您似乎正在主方法中执行初始化。如果在初始化过程中出现问题,您希望中止启动JavaFX应用程序。好的,JavaFX本身提供了实现这一点的方法:

应用程序初始化方法。加载和构造应用程序类后,立即调用此方法。应用程序可以重写此方法,以便在实际启动应用程序之前执行初始化

应用程序类提供的此方法的实现不起任何作用

注意:此方法不在JavaFX应用程序线程上调用。应用程序不得在此方法中构造场景或舞台。应用程序可以在此方法中构造其他JavaFX对象

将初始化代码移到此方法。如果调用,则应用程序将退出,并且不会调用application.start。另一种方法是在init内部抛出异常。还可以使用返回的实例来获取应用程序参数


一,。JavaFX在版本8中包含在JavaSE中。注意,由于JavaFX将再次与JavaSE分离,Java11中的这种行为可能会发生变化。

请您展示ArgumentsHandler.handle的代码片段。。。和存储。加载?我假设这些方法中的一个产生了一个非守护进程线程,该线程阻止进程在离开主方法后结束。从主线程调用主方法,只是因为返回并不意味着退出线程。您没有足够的进度来启动窗口,但是也没有明确地告诉线程退出,因此您会遇到应用程序暂停。我不确定您在main方法中试图做什么,但是如果您试图返回,那么您可能无论如何都想退出。@tryl
问题中添加了imits。您可以在调试时检查除主线程外是否还有其他线程在运行。如果使用Eclipse,您可以在Debug视图中看到正在运行的线程:从调用launch的方式来看,我假设main位于应用程序子类中。我发现在应用程序类中使用main会导致某种初始化,从而在main退出后阻止JVM退出。尽管未调用launch,但仍会发生这种情况。我猜这与Java启动JavaFX应用程序的特殊方式有关,因为将main移到另一个类不会导致这个问题。它不是由应用程序类引起的,因为手动初始化该类也不会导致此问题。
public class MyApp extends Application {

    @Override
    public void init() throws Exception {
        if (!ArgumentsHandler.handle(getParameters()) {
            Platform.exit(); // or throw an exception
        } else {
            Storage storage = Storage.getInstance();
            storage.load();
            if (!storage.isLoadSuccessful()) {
                Platform.exit(); // or throw an exception
            }
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        // Create Scene and show the primary Stage
    }

    @Override
    public void stop() throws Exception {
        /*
         * Called when the JavaFX application is exiting, such as from
         * a call to Platform.exit(). Note, however, that in my experience
         * this method is *not* called when Platform.exit() is called inside
         * the "init" method. It is called if Platform.exit() is called from
         * inside the "start" method or anywhere else in the application once
         * it is properly started.
         *
         * This is where you could perform any necessary cleanup.
         */
    }

}