使用XML抛出空指针异常的持久性

时间:2013-03-07 18:23:29

标签: java xml-serialization nullpointerexception persistence distributed-system

我正在设计一个分布式系统,它将库存的ArrayList保存到文件中。我正在写文件到文件,并在读取该文件时,我收到空指针异常错误。

这是A类中的一个字段:

private static StockList instance = null;

这是我的方法getInstance(),在A类中,它从文件中检索库存列表。

public static StockList getInstance(){
    if (instance==null){
        try {
            XMLDecoder d = new XMLDecoder(
                    new BufferedInputStream(
                    new FileInputStream("Stock.xml")));
            instance = (StockList) d.readObject();
            d.close();
        } catch (IOException ex) {
            instance= new StockList();
            Logger.getLogger(StockList.class.getName()).log(Level.SEVERE, null, ex);
        } 
    }
    return instance;
}

这是A类构造函数,如果getInstance()中存在IOException,则调用它:

public StockList(){
    stock.put("APL", new Stock("APL","Apple","Apple",3200));
    System.out.println("");
}

这是我的方法writeStockList,在A类中,它将股票写入文件:

public void writeStockList()
    {
       try {
            XMLEncoder e = new XMLEncoder(
                new BufferedOutputStream(
                new FileOutputStream("Stock.xml")));
        e.writeObject(getInstance());
        e.flush();
        e.close();            
    } catch (IOException ex) {            
        Logger.getLogger(StockList.class.getName()).log(Level.SEVERE, null, ex);
    }
}

这是我的主要方法,在B类中,它在服务器运行时初始化stocklist:

public static void main(String[] args){
    try {
        //Make sure all lists are initialised
        StockList.getInstance();
        //delete after first run
        //StockList.getInstance().addStock(new Stock("APL2","Apple2","Apple",3200));
        //StockList.getInstance().writeStockList();
        System.out.println(StockList.getInstance().getStock("APL" ).name);          
        System.out.println(StockList.getInstance().getStock("APL2" ).name);

        System.out.println("registered ok");
    } catch (RemoteException ex) {
        Logger.getLogger(ClientServer.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("finished server setup");
}

出于测试目的,第一次运行程序时,以下行是未注释的:

//StockList.getInstance().addStock(new Stock("APL2","Apple2","Apple",3200));  
//StockList.getInstance().writeStockList();

这应该将新库存(APL2)添加到列表中并将其写入文件。

以下行正确打印 - 证明找到了两种股票:

System.out.println(StockList.getInstance().getStock("APL" ).name);          
System.out.println(StockList.getInstance().getStock("APL2" ).name);

然后当我们第二次运行时,上面的行被注释,但是上面的System.out.println引发了以下错误:

Exception in thread "main" java.lang.NullPointerException at food.stockticker.priceserver.ClientServer.main(ClientServer.java:46)
Java Result: 1

当调用getInstance()时,第二个项目写入文件并读回库存清单时,不应出现上述情况。如果我打印第一个项目(APL),它将返回它。打印APL2时,会发生错误。

似乎Stock.xml文件被覆盖,或者第一次运行中所做的更改未写入xml文件。有什么想法吗?

编辑:

XML:

<?xml version="1.0" encoding="UTF-8"?> 
<java version="1.6.0_41" class="java.beans.XMLDecoder"> 
<object class="food.stockticker.priceserver.StockList"/> 
</java> 

1 个答案:

答案 0 :(得分:1)

如果我理解正确,文件在第一次运行后就被删除了,那么注释掉的行被带回来。在这种情况下,文件此时不存在,读者不会初始化和很多东西将为null,包括实例 - 因此为NullPointerException

还要注意的是,如果这是为分布式(多线程并发)系统构建的:

如果应该只有一个主库存对象的实例,请使用Singleton pattern,在这种情况下,当从文件中读取数据时,在加载器周围放置一个锁(并使其成为一种不同的方法)。在这种情况下,通常建议在静态{}加载时执行此操作,以确保只执行一次,并且无论如何都不需要double-check locks在高度并发系统中不起作用。

private static synchronized void load()
{
 // return if file is already loaded, unless you meant to re-load
 // load the file here...
}

否则多个并发线程可能同时调用getInstance,stock对象仍然会执行/ null并且它们将相互遍历。设计和代码也存在许多问题,超出了这个问题,但希望这能解决NPE问题。