【问题标题】:Issue with running JAR from Desktop, but not from command line or Eclipse从桌面运行 JAR 的问题,但不是从命令行或 Eclipse
【发布时间】:2023-08-28 10:35:01
【问题描述】:

我在SwingWorker 中遇到了一个奇怪的问题(无论如何对我来说很奇怪),我用它来将另一个“SwingWorker”线程的结果保存为制表符分隔的文件(只是一个数据电子表格)。

这里是工人,它初始化并声明一个对象,该对象组织数据并将每个表行写入文件(使用BufferedWriter):

// Some instance variables outside of the SwingWorker:
// model: holds a matrix of numerical data (double[][])
// view: the GUI class

class SaveWorker extends SwingWorker<Void, Void> {

        /* The finished reordered matrix axes */
        private String[] reorderedRows;
        private String[] reorderedCols;
        private String filePath;  // the path of the file that will be generated

        public SaveWorker(String[] reorderedRows, String[] reorderedCols) {

            // variables have been checked for null outside of the worker
            this.reorderedRows = reorderedRows;
            this.reorderedCols = reorderedCols;
        }

        @Override
        protected Void doInBackground() throws Exception {

            if (!isCancelled()) {
                LogBuffer.println("Initializing writer.");
                final CDTGenerator cdtGen = new CDTGenerator(
                        model, view, reorderedRows, reorderedCols);

                LogBuffer.println("Generating CDT.");
                cdtGen.generateCDT();

                LogBuffer.println("Setting file path.");
                filePath = cdtGen.getFilePath();         // stops inside here, jumps to done()
                LogBuffer.println("Path: " + filePath);
            }
            return null;
        }

        @Override
        protected void done() {

            if (!isCancelled()) {
                view.setLoadText("Done!");
                LogBuffer.println("Done saving. Opening file now.");

                // need filePath here to load and then display generated file
                visualizeData(filePath);

            } else {
                view.setReorderOngoing(false);
                LogBuffer.println("Reordering has been cancelled.");
            }
        }
    }

当我从 Eclipse 运行程序时,一切正常。没有任何问题。现在我知道这里有很多关于 Eclipse 运行良好而可运行 JAR 失败的问题。这通常是由于不包括依赖项或以错误的方式引用它们。但奇怪的是 JAR also 在从命令行启动时完全可以正常工作(Windows 8.1):

java -jar reorder.jar

等等,一切都符合预期。 CDTGenerator 将完成,将所有矩阵行写入文件,并返回 filePath。使用filePath,我随后可以打开新文件并显示矩阵。

如果双击桌面上的 JAR(我在 Eclipse 中创建它时放置它的位置),程序会在此通知我发生的事情。我收到了我为filePath == null 的情况创建的错误消息,并使用一些日志记录关闭了CDTGenerator 对象停止执行其方法generateCDT() 的位置(Eclipse 调试器不会重现错误并按计划执行所有操作)。

日志显示的内容让我认为这是并发问题,但实际上我反对这一点,因为 Eclipse 命令行都可以正常运行代码。日志只是告诉我,代码在循环期间突然停止执行,该循环将double 值从矩阵行 (double[]) 转换为 Strings 以存储在 String[] 中,以便以后使用 BufferedWriter 编写。

如果我在该循环中使用更多日志记录,则循环将在不同的迭代器 (???) 处停止。

此外,代码确实适用于小矩阵 (130x130),但不适用于较大的矩阵 (1500x3500),但我尚未测试限制在哪里。这使它看起来几乎是时间相关的,或记忆。

我还使用 jVisualVM 来查看潜在的内存问题,但即使对于较大的矩阵,我的内存约为 250MB,这对于潜在的OutOfMemoryExceptions 来说几乎没有问题。

最后,我能想到的最后一个潜在因素:由于一些classpath 问题(清理和重建没有效果......)而生成 JAR '失败',但这从来都不是我之前遇到的问题使用“损坏的”JAR 多次运行代码并从桌面执行。

我是一个真正的编程新手,所以如果可能的话,请指出一些方向。我试图找到记录的异常,记录变量的值,我正在检查它停止执行的数组中的nullIndexOutOfBound 问题......我完全不知所措尤其是因为这从命令行运行良好。

【问题讨论】:

  • 拜托,你能发布你的错误的堆栈跟踪吗?如果您在可视化它时遇到任何问题,请尝试配置一些记录器以便将其转储到文件中,但完整的跟踪将非常有用
  • 这正是我的问题。 no 堆栈跟踪,甚至在命令提示符中也没有,因为从那里启动时它工作正常。将行写入文件的方法只是随机停止,在一个特定循环的不同点,这取决于我打印了多少日志消息(再次,让我认为时间是一个因素)。没有循环迭代器越界,没有数组值null在那个循环中......
  • 当程序停止时,进行线程转储并查看是否存在死锁,或者应该处于可运行状态的线程是否由于某种原因(阻塞、等待、timed_waiting)或完全不存在。
  • 顺便看看您的操作系统文件关联和执行它们的预定程序。你确定你在命令行和双击它都使用相同的java版本吗?
  • 这可能是它。我注意到别的东西:尝试在 jVisualVM 中进行线程转储只能从命令行进行。否则“线程”选项卡甚至不会出现,也不允许我在“监视器”选项卡中进行 GC 转储。我马上回来报告。

标签: java concurrency jar io swingworker


【解决方案1】:

看起来问题必须与安装在 OP 计算机中的 java 版本有关。他们检查了文件扩展名和与每个文件关联的程序,以查看它是否与从 Eclipse 和命令行执行的 java 版本相同。

一旦他们清理了较旧的 java 版本,jar 就会通过双击它开始工作:)

【讨论】:

    【解决方案2】:

    因为我没有足够的积分(需要50才能直接回答你的问题),我需要这样问: 如果双击 JAR,您将看不到控制台,这通常是问题所在,因为您看不到堆栈跟踪。他们只是被写到“无处”。也许你会得到一个 NPE 矿石别的东西。 尝试像这样Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler) 附加一个异常处理程序,并让这个处理程序将一条消息写到一个文件或类似的...... 只是一个想法。

    【讨论】:

    • 应用程序中有一个单独的记录器,在所有其他情况下总是会打印异常和日志消息。据我所知,那里的输出与打印到命令行的输出完全相同。那里没有提示..