0

我正在设计一个分布式系统,它将股票的ArrayList持久化到文件中。我正在写入股票的文件,并在阅读该文件时,我收到一个空指针异常错误。使用XML抛出空指针异常的持久性

这是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类的构造函数,它被称为如果(一个IOException中的getInstance):

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 

作为第二项被写入到文件中的上述不应该发生,并且读回stocklist时的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> 
+0

XML是什么样的?我们能否看到'StockList'类的其余部分 - 主要是'get'方法。 – 2013-03-07 18:27:57

+0

我添加了XML文件以及在发生IOException时调用的构造函数。没有其他方法与上述相关 - 我现在添加了所有内容。 – 2013-03-07 18:38:41

+0

如果发布完整的代码会更容易。同时,也可以使用这个log4j或类似的结构:logger.error(“{msg}”,{ex})其中{ex}是Exception。这将产生完整的堆栈跟踪。还可以使用日志记录而不是与System.out.println()混合。 – 2013-03-07 18:38:57

回答

1

如果我的理解是正确的,该文件是在第一次运行后删除,然后被注释掉的线是在带回在这种情况下,该文件在此处不存在,读者将不会初始化,并且许多事情将为空,包括实例 - 因此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,股票对象仍然会执行/ null的,他们会走到另一个。设计和代码也存在许多问题,超出了这个问题,但希望这能够解决NPE问题。