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

时间:2018-09-06 20:35:29

标签: 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
    {
        System.err.println("Unable to load configurations.");
    }
}

我专门将if语句中的条件转换为失败的条件,并且我肯定在调试器中看到它不执行launch方法,但是仍然显示应用程序窗口

我还注意到,在return方法内使用main语句无效-应用程序仍继续执行。它仅响应System.exit(0)

为什么会这样?

更新:

根据您的要求,这是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);
}

loadConfigurationloadCompanyloadRepository实际上是相同的。将来,他们将不会读取简单的json文件,但会访问复杂的档案,这就是为什么我已经创建了几种几乎相同的方法的原因。

Utility.load

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

只需反序列化文件中的对象即可。

1 个答案:

答案 0 :(得分:1)

从我假设您调用launch(args)的方式开始,后来您confirmed假设,main方法位于Application的子类中。我相信这是造成您问题的原因。

您已经注意到,有很多看似JavaFX的线程正在运行。具体来说,非守护程序“ JavaFX Application Thread”正在运行(至少,在Java 10中是非守护程序)。即使main线程退出,该线程也将导致JVM保持活动状态。这是Java的正常行为:

  

java.lang.Thread

     

Java虚拟机启动时,通常只有一个非守护线程(通常调用某些指定类的名为main的方法)。 Java虚拟机将继续执行线程,直到发生以下两种情况之一为止:

     
      
  • 已调用类exit的{​​{1}}方法,并且安全管理器已允许进行退出操作。
  •   
  • 不是所有守护进程线程的所有线程都已死亡,要么通过从调用返回到Runtime方法,要么抛出传播到run方法之外的异常。
  •   

但是,当您故意还没有调用run时,为什么启动了“ JavaFX Application Thread”呢?我只是在这里猜测,但这可能与JavaFX应用程序获得的特殊待遇有关。至少从Java 8开始,您不必在Application.launch 1 的子类中声明main方法。如果主类是Application的子类,则Java将自动处理启动。

Application

如果具有上述条件,并调用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会覆盖启动JavaFX应用程序的默认行为,但不会阻止JavaFX运行时的初始化。也许这种行为是设计使然,或者是疏忽大意。但是重要的是,这仅在主类具有main方法并且是main子类的情况下才会发生。如果您将两者分开:

Application

那么您将不再有此问题。

否则,您可以继续使用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()之前,您似乎正在main方法中执行初始化。如果在初始化期间出现问题,则要中止启动JavaFX应用程序。好吧,JavaFX提供了自己执行此操作的方法:Application.init()

  

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

     

Application类提供的此方法的实现不起作用。

     

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

将初始化代码移至此方法。如果您调用Platform.exit(),则该应用程序将退出,并且不会调用Application.launch。一种替代方法是在Application.start中引发异常。您还可以使用Application.getParameters()来获取应用程序参数,该参数返回Application.Parameters的实例。

init

1。 Java SE在版本8中包含JavaFX。请注意,由于JavaFX将再次与Java SE分开,因此在Java 11中此行为可能会更改。