CSVhelper writeLine,for循环中途的空指针

CSVhelper writeLine, null pointer halfway during a for-loop

对于 java 模拟项目,我有一个日志文件,用于跟踪单个 运行 期间发生的所有事情。我通过将自定义 TimeLog.class 的对象添加到列表来完成此操作。模拟完成后,我遍历此列表并为每个条目编写一个字符串 ArrayList,然后使用我在网上找到的以下 "CSVHelper" class 将其写入 csv 文件(致谢 Keke Chen ).

创建字符串 ArrayList:

public static void saveData(List<TimeLog> data, String fileName, Simulator simulator, 
        ArrayList<String> header) throws Exception {
    File csvFile = new File(simulator.getOutputFolder()+fileName);
    FileOutputStream fos = new FileOutputStream(csvFile);
    Writer fw = new OutputStreamWriter(fos, "UTF-8");
    CSVHelper.writeLine(fw, header);
    for (TimeLog entry : data) {
        ArrayList<String> row = new ArrayList<>();
        row.add(String.valueOf(entry.getTime())); //time of entry, double
        row.add(String.valueOf(entry.getMessageType())); //type of message (SETUP, DEBUG, EVENT, ERROR)
        if (entry.getEvent() == null) {
            row.add("");
        } else { 
            row.add(entry.getEvent().getTypeName()); //event type if event
        }
        row.add(entry.getLog()); //message
        CSVHelper.writeLine(fw, row);
    }
    fw.flush();
    fw.close();
}

CSVHelper.writeLine :

/** Class for processing csv file.
* created by Keke Chen (keke.chen@wright.edu)
* For Cloud Computing Labs
* Feb. 2014
*/
public static void writeLine(Writer w, ArrayList<String> values) throws Exception  {
    boolean firstVal = true;
    for (String val : values)  {
        if (!firstVal) {
            w.write(",");
        }
        w.write("\"");
        for (int i=0; i<val.length(); i++) {
            char ch = val.charAt(i);
            if (ch=='\"') {
                w.write("\"");  //extra quote
            }
            w.write(ch);
        }
        w.write("\"");
        firstVal = false;
    }
    w.write("\n");
}

出于调试目的,我捕获了模拟器抛出的异常,将有关它们的信息添加到我的日志列表中,写入日志文件,然后再次抛出异常。这样,当出现问题时,我可以在日志文件中查看发生了什么。

直到最近这一切都很好,但现在我在编写过程中的第二个 for 循环期间遇到了 NullPointerException。由于某种原因,行

for (int i=0; i<val.length(); i++)

在字符串中途抛出异常。如果我打开创建的日志文件,最后一个条目也有完成一半的消息或时间戳(例如:"tool X was res" 而不是 "tool X was reserved for item Y" 或“212”而不是“212312.16”)。

编写 csv 文件、将列表保存在 java 中、在字符串字符上使用 for 循环或其他我不知道的内容是否有任何限制?这让我很头疼。

再见, 罗宾

编辑:根据要求,列表条目的示例:

//initiating:
private List<TimeLog> logging = new ArrayList<>();

//message:
public void message(MessageType mt, String s, Event e) {
    if (saveLog) {
        logFile.add(new TimeLog(now(), mt, s, e)); //now() gets the current time of the simulator
    }
}

//example:
Event e = new ReservationEvent(simulator.now(), X, Y);
simulator.message(MessageType.EVENT, "Tool "+X.getId()+" was reserved for item "+Y+getId(), e);

这是堆栈跟踪:

java.lang.NullPointerException
at model.simulator.transport.input.CSVHelper.writeLine(CSVHelper.java:27)
at model.simulator.TimeLog.saveData(TimeLog.java:73)
at model.simulator.Simulator.endSimulation(Simulator.java:98)
at model.simulator.Simulator.runSimulation(Simulator.java:64)
at test.simulator.compare.TestFullFab.testRunning(TestFullFab.java:147)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=14=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:539)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)

由于 Emax 的评论,我注意到了一些其他事情。我添加了

System.out.println("0:"+row.get(0)+", 1:"+row.get(1)+", 2:"+row.get(2)+", 3:"+row.get(3));

在 saveData 方法中,就在 CSVHelper.writeLine(fw,row) 之前,在字符串被写入之前查看字符串列表。这会在控制台中生成完整的日志列表,因此也会生成未(或部分)写入 csv 文件的日志。不知何故,TimeLog for 循环在 writeLine 抛出异常时继续。

EDIT2:TimeLog 的结构:

public class TimeLog {
    private double time;
    private MessageType mt;
    private String log;
    private Event e;

    public TimeLog(double time, MessageType mt, String log, Event e) {
        this.time = time;
        this.mt = mt;
        this.log = log;
        this.e = e;
    }

    //see full method above
    public static void saveData(List<TimeLog> data, String fileName, Simulator simulator, 
        ArrayList<String> header) throws Exception { ...

    //further more, there are some getters
}

作为 System.out.println() 行结果的控制台输出示例:

0:27131.490112666303, 1:EVENT, 2:TOOLEVENT, 3:Tool input event, item 3998 has gone into tool QSD301

请记住,0:、1:、2: 和 3: 不在原始列表中,而是在 println() 方法中添加的。

更新:使用 Emax 的打印值的想法 returns null 揭示了问题。 val 的值确实变成了 null,它发生在 NullPointerException(没有消息),所以 e.getMessage() returns null。奇怪的是,Writer 根本没有将所有值写入 csv 文件,但似乎有某种延迟(也许它在实际写入文件之前首先收集了默认数量的字符或其他什么?)。因此,我认为 NullPointer 是在 val 循环期间发生的,而它已经完成了。感谢您的帮助!

导致该行出现 NullPointerException 的唯一可能原因是 val 为 null,因为 val 取自列表,问题冒泡到:

    row.add(String.valueOf(entry.getTime()));
    row.add(String.valueOf(entry.getMessageType()));
    row.add(entry.getEvent().getTypeName());
    row.add(entry.getLog());

其中一项添加是向列表中添加一个空值,您应该检查其中一项。 但是 post 完整的 stracktrace 包括(如果存在)"Caused By"

更新

尝试像这样修改 writeLine:

        [...]
        if (!firstVal) {
            w.write(",");
        }
        w.write("\"");

        // EDIT HERE
        if (val == null) {
            System.out.println("This val is null: " + values);
        }
        // .....

        for (int i = 0; i < val.length(); i++) {
        [...]

Post 导致 NullPointerException

的情况的输出