为啥 javafx 忽略 main 的返回并仍然启动应用程序?
Posted
技术标签:
【中文标题】为啥 javafx 忽略 main 的返回并仍然启动应用程序?【英文标题】:why javafx ignore return from main and still launches an application?为什么 javafx 忽略 main 的返回并仍然启动应用程序? 【发布时间】:2019-02-12 04:10:24 【问题描述】:我有以下代码。
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
方法,但仍显示应用程序窗口。
我还注意到,在 main
方法中使用 return
语句没有任何效果 - 应用程序仍在继续执行。它只响应System.exit(0)
。
为什么会这样?
更新:
根据您的要求,这是 ArgumentsHandler 的 sn-p。我在这里没有使用线程(至少是有意的)。
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 文件,而是会访问复杂的档案,这就是为什么我已经创建了几个几乎相同的方法。
实用程序.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;
只是从文件中反序列化对象。
【问题讨论】:
能否请您出示ArgumentsHandler.handle(...)
和Storage.load()
的代码sn-ps?我假设其中一种方法会产生一个非守护线程,它会阻止进程在离开 main
方法后结束。
main方法是从主线程调用的,你return
不代表你退出了线程。您的进度不足以启动窗口,但也没有明确告诉线程退出,因此您会遇到应用程序停顿。我不确定您在 main
方法中尝试做什么,但如果您尝试使用 return
,那么您可能还是想退出。
@trylimits 添加到问题中。
调试的时候可以检查是否有其他线程在运行(除了主线程)。如果您使用 Eclipse,您可以在 Debug View 中看到正在运行的线程:help.eclipse.org/photon/…
从您调用launch
的方式来看,我假设main
在Application
子类中。我发现在Application
类中包含main
会导致某种初始化,一旦main
退出,就会阻止JVM 退出。尽管没有调用launch
,但仍会发生这种情况。我猜这与 Java 启动 JavaFX 应用程序的特殊方式有关,因为将 main
移动到另一个类不会导致这个问题。而且它不是由Application
类引起的,因为手动初始化该类也不会导致此问题。
【参考方案1】:
从您调用launch(args)
的方式来看,我假设以及稍后的confirmed 这个main
方法在Application
的子类中。我相信这是您的问题的原因。
正如您所注意到的,有许多看似特定于 JavaFX 的线程正在运行。具体来说,非守护程序“JavaFX 应用程序线程”正在运行(至少,它在 Java 10 中是非守护程序)。即使main
线程退出,该线程也会使JVM 保持活动状态。这是 Java 的正常行为:
java.lang.Thread
当 Java 虚拟机启动时,通常有一个非守护线程(通常调用某个指定类的名为
main
的方法)。 Java 虚拟机继续执行线程,直到发生以下任一情况:Runtime
类的exit
方法已被调用,安全管理器已允许执行退出操作。 不是守护线程的所有线程都已死亡,要么从对run
方法的调用返回,要么抛出传播到run
方法之外的异常。
但是为什么在你故意不调用Application.launch
的时候启动“JavaFX 应用程序线程”呢?我只是在这里猜测,但它可能与 JavaFX 应用程序收到的特殊处理有关。至少从 Java 8 开始,您不必在 Application
1 的子类中声明 main
方法。如果主类是Application
的子类,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
方法并且是 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()
。
还有另一种可能更合适的方法来处理这个问题。您似乎在调用Application.launch
之前在main
方法中执行初始化。如果在此初始化过程中出现问题,您希望中止启动 JavaFX 应用程序。好吧,JavaFX 自己提供了执行此操作的方法:Application.init()
。
应用程序初始化方法。在加载和构造 Application 类后立即调用此方法。应用程序可以覆盖此方法以在应用程序实际启动之前执行初始化。
Application 类提供的这个方法的实现什么都不做。
注意:JavaFX 应用程序线程上不会调用此方法。应用程序不得在此方法中构造场景或舞台。应用程序可以在此方法中构造其他 JavaFX 对象。
将您的初始化代码移至此方法。如果您调用Platform.exit()
,则应用程序将退出并且不会调用Application.start
。另一种方法是在init
内抛出异常。您还可以使用返回Application.Parameters
实例的Application.getParameters()
获取应用程序参数。
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.
*/
1. JavaFX 在版本 8 中包含在 Java SE 中。请注意,此行为在 Java 11 中可能会发生变化,因为 JavaFX 将再次与 Java SE 分离。
【讨论】:
以上是关于为啥 javafx 忽略 main 的返回并仍然启动应用程序?的主要内容,如果未能解决你的问题,请参考以下文章
Javafx怎么播放flash,就是我用Java main函数执行,直接调用Javafx做好的页面,为啥不能播放flash
为啥我在函数内部使用引用并通过引用返回它仍然有效? [复制]