java - CSVhelper writeLine,for 循环期间中途空指针

标签 java csv for-loop nullpointerexception string-length

对于 java 模拟项目,我有一个日志文件,用于跟踪单次运行期间发生的所有情况。我通过将自定义 TimeLog.class 的对象添加到列表中来实现此目的。模拟完成后,我循环遍历此列表,并为每个条目编写一个字符串 ArrayList,然后使用我在网上找到的以下“CSVHelper”类将其写入 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 (<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="167d737d7338757e73785661647f717e6238737263" rel="noreferrer noopener nofollow">[email protected]</a>)
* 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++)

在字符串中途抛出异常。如果我打开创建的日志文件,最后一个条目也有半完成的消息或时间戳(例如:“工具 X 是 res”而不是“工具 X 为项目 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$1.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$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.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 文件的日志。不知何故,当 writeLine 抛出异常时,TimeLog for 循环仍在继续。

EDIT2:时间日志的结构:

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 打印返回 null 的值的想法揭示了问题。 val 的值确实变成了 null,并且它发生在 NullPointerException(没有消息)处,因此 e.getMessage() 返回 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());

此添加之一是向列表中添加空值,您应该检查其中之一。 但是发布完整的跟踪,包括(如果存在)“引起的”

更新

尝试像这样修改 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++) {
        [...]

发布导致 NullPointerException 的情况的输出

关于java - CSVhelper writeLine,for 循环期间中途空指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48378882/

相关文章:

javascript - 将递增 ID 添加到数组中的 obj

javascript - 如何在 JavaScript 中添加 'for' 循环的结果?

java - 为什么没有检测到 JAVA 版本? Android Gradle 插件需要 Java 11 才能运行。您当前使用的是 Java 1.8

java - 添加自定义通知 LED 灯

java - 如何从命令行指定 jconsole 的用户名和密码?

regex - 分割 CSV 文件中的字符串

c++ - 大csv文件c++解析性能

javascript - 如何循环遍历嵌套数组,然后使用 Javascript 以预定义的顺序存储输出

java - Wicket:使用 PropertyResolver 可以吗?

ruby - 显示 iso-8859-1 编码的数据给出奇怪的字符