0

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

这是 A 类中的一个字段:

private static StockList instance = null;

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

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("");
}

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

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 类中的主要方法,它在服务器运行时初始化库存清单:

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> 
4

1 回答 1

1

如果我理解正确的话,文件在第一次运行后被删除,然后注释掉的行被带回来。在这种情况下,此时文件不存在,阅读器不会初始化,很多东西都会为空,包括实例 - 因此NullPointerException.

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

如果应该只有一个主要股票对象的实例,请使用单例模式,在这种情况下,当从文件中读取数据时,在加载器周围加一个锁(并使其成为不同的方法)。在这种情况下,通常建议在静态加载时执行此操作,以保证仅执行一次,并且不需要在高并发系统中无论如何都不起作用的双重检查锁。

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

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

于 2013-03-07T18:48:18.320 回答