質問

I am designing a distributed system which is persisting an ArrayList of stock to a file. I am writing stock to the file and upon reading that file, I receive a null pointer exception error.

This is a field in class A:

private static StockList instance = null;

This is my method getInstance(), in class A, which retrieves a list of stock from the file.

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;
}

This is the class A constructor, it is called if there is an IOException in getInstance():

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

This is my method writeStockList, in class A, which writes the stock to the file:

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

This is my main method, in class B, which initialises the stocklist when the server is run:

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

For testing purposes, the first time running the program, the following lines are uncommented:

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

This should add a new stock (APL2) to the list and write it to the file.

The following line, printed correctly - proving that both stocks were found:

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

Then when we run a second time, the above lines are commented, however the above System.out.println throws the following error:

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

The above should not occur as the second item was written to the file and read back into the stocklist when getInstance() was called. If I print the first item (APL), it returns it. When APL2 is printed, an error occurs.

It seems as if the Stock.xml file was either overwritten or the changes made in the first run were not written to the xml file. Any ideas?

Edit:

The 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> 
役に立ちましたか?

解決

If I understood it correctly, the file was deleted after the first run, then the commented-out lines were brought back in. In this case, the file does not exist at this point, the reader will not initialize and many things will be null, including the instance - hence the NullPointerException.

Also noted is that if this is being built for a distributed (multi-threaded concurrent) system:

If there is supposed to be one and only one instance of the main stock object, use the Singleton pattern and, in this case, as the data is being read from a file, put a lock around the loader (and make that a different method). It is generally advisable to do this in this case at static{} load time so that it is guaranteed to only be done once and there is no need for double-check locks that do not work in highly concurrent systems anyway.

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

Otherwise multiple concurrent threads may simultaneously call getInstance, the stock object will still be executing/null and they will walk over one another. There are also numerous problems with the design and code that go beyond this question but hopefully this answers the NPE problem.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top