transactionFeeProperty

transactionFeeProperty

我的Trade类具有以下代码:

public class Trade{

    // attributes of each trade that go into the Transaction log
    // properties
    private ObjectProperty<LocalDate> transactionDate;
    private StringProperty itemNum;
    private StringProperty buySell;
    private DoubleProperty volume;
    private DoubleProperty price;
    private DoubleBinding transactionFee;


    public Trade(BuySell buySell, LocalDate transactionDate, int itemNum, double volume, double price){
        this.buySell = new SimpleStringProperty(buySell.toString());
        this.transactionDate = new SimpleObjectProperty<LocalDate>(transactionDate);
        this.itemNum = new SimpleStringProperty(itemNum));
        this.volume = new SimpleDoubleProperty(volume);
        this.price = new SimpleDoubleProperty(price);
    }
    ...
}


现在在我的Controller类中,我有以下内容,并且在添加observableListOfTrades.addAll语句之前,一切工作都很好,代码破裂并给了我很长的NullPointerException列表。我不知道如何解决这个问题。

 public class Controller implements Initializable{


    ObservableList<Trade> observableListOfTrades =FXCollections.observableArrayList(trade ->
            new Observable[]{
                    trade.transactionDateProperty(),
                    trade.stockTickerProperty(),
                    trade.buySellProperty(),
                    trade.volumeProperty(),
                    trade.priceProperty(),
                    trade.transactionFeeProperty()
            }
        );
        ....
        ....

        public void initialize(URL fxmlFileLocation, ResourceBundle resources){
               ...
               ...
               observableListOfTrades.addAll(new Trade(BuySell.Sell, LocalDate.now().minusDays(5),50,99,99),new Trade(BuySell.Buy, LocalDate.now(),50,1,1));
              //<--- Entire Code used to work fine until I added the addAll shown above.

            observableListOfTrades.addListener(new ListChangeListener<Trade>() {
            @Override
            public void onChanged(ListChangeListener.Change change) {
                System.out.println("Detected a change! ");
            }
          });

              ...
        }


这是错误消息:

javafx.fxml.LoadException:
/Users/Eclipse/StockTrackerJavaFX/bin/application/Interface.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2605)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2583)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2445)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3218)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3179)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3152)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3128)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3108)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3101)
    at application.Main.start(Main.java:27)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$159(LauncherImpl.java:863)
    at com.sun.javafx.application.LauncherImpl$$Lambda$54/1508757224.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$172(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl$$Lambda$47/186276003.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295)
    at com.sun.javafx.application.PlatformImpl$$Lambda$49/223236686.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294)
    at com.sun.javafx.application.PlatformImpl$$Lambda$48/237061348.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    Caused by: java.lang.NullPointerException
        at com.sun.javafx.collections.ElementObserver.attachListener(ElementObserver.java:80)
        at com.sun.javafx.collections.ObservableListWrapper.doAdd(ObservableListWrapper.java:100)
        at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:151)
        at java.util.AbstractList.add(AbstractList.java:108)
        at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
        at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:99)
        at javafx.collections.ObservableListBase.addAll(ObservableListBase.java:245)
        at application.Controller.initialize(Controller.java:233)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
        ... 18 more


更新:正如@James_D所指出的,transactionFeeProperty返回一个null值。所以,我给那些方法的代码

public double getVolume(){
        return this.volume.get();
    }

public DoubleProperty volumeProperty(){
    return this.volume;
}

public void setVolume(double volume){
    this.volume.set(volume);
}


public double getPrice(){
    return this.price.get();
}

public DoubleProperty priceProperty(){
    return this.price;
}

public void setPrice(double price){
    this.price.set(price);
}

public double getTransactionFee(){
        this.transactionFee = this.price.multiply(this.volume).multiply(0.5);
        return this.transactionFee.getValue();
}

public DoubleBinding transactionFeeProperty(){
    return this.transactionFee;
}

最佳答案

由于使用提取器创建了ObservableList,因此将Trade添加到列表中时:

observableListOfTrades.add(trade);


(或与addAll(...)类似),列表将使用提取程序返回的属性注册一个侦听器。即它基本上调用

trade.transactionDateProperty().addListener(...);
trade.stockTickerProperty().addListener(...);
// ...
trade.transactionFeeProperty().addListener(...);


因此,确保添加对象时这些方法不返回null是很重要的(让属性访问器方法返回null实际上是一个坏主意)。

定义transactionFeeProperty()getTransactionFee()方法的方式,仅在首次调用transactionFee之后初始化getTransactionFee(),直到那时,transactionFeeProperty()返回null。因此,当您将new Trade(...)添加到列表中时,就会出现NullPointerException

一种解决方法是初始化构造函数中的transactionFee以及其他属性:

public Trade(BuySell buySell, LocalDate transactionDate, int itemNum, double volume, double price){
    this.buySell = new SimpleStringProperty(buySell.toString());
    this.transactionDate = new SimpleObjectProperty<LocalDate>(transactionDate);
    this.itemNum = new SimpleStringProperty(itemNum));
    this.volume = new SimpleDoubleProperty(volume);
    this.price = new SimpleDoubleProperty(price);
    this.transactionFee = this.price.multiply(this.volume).multiply(0.5);
}


然后就

public double getTransactionFee(){
        return this.transactionFee.getValue();
}

public DoubleBinding transactionFeeProperty(){
    return this.transactionFee;
}


其他几点。

首先,transactionFee仅在pricevolume更改时才会更改。由于您要在提取程序中返回这些属性,因此实际上也要返回transactionFeeProperty()是多余的,因为如果transactionFee发生更改,则pricevolume必须已更改,并且列表将已经收到更新通知。

其次,xxxProperty()方法应该真正返回属性,而不是Binding。表示绑定(或从属)属性的常规方法是使用ReadOnlyDoubleWrapper。因此,您应该遵循以下几点:

public class Trade{

    // attributes of each trade that go into the Transaction log
    // properties
    private ObjectProperty<LocalDate> transactionDate;
    private StringProperty itemNum;
    private StringProperty buySell;
    private DoubleProperty volume;
    private DoubleProperty price;
    private ReadOnlyDoubleWrapper transactionFee;


    public Trade(BuySell buySell, LocalDate transactionDate, int itemNum, double volume, double price){
        this.buySell = new SimpleStringProperty(buySell.toString());
        this.transactionDate = new SimpleObjectProperty<LocalDate>(transactionDate);
        this.itemNum = new SimpleStringProperty(itemNum));
        this.volume = new SimpleDoubleProperty(volume);
        this.price = new SimpleDoubleProperty(price);
        this.transactionFee = new ReadOnlyDoubleWrapper();
        this.transactionFee.bind(this.price.multiply(this.volume).multiply(0.5));
    }

    public double getVolume(){
            return this.volume.get();
        }

    public DoubleProperty volumeProperty(){
        return this.volume;
    }

    public void setVolume(double volume){
        this.volume.set(volume);
    }


    public double getPrice(){
        return this.price.get();
    }

    public DoubleProperty priceProperty(){
        return this.price;
    }

    public void setPrice(double price){
        this.price.set(price);
    }

    // etc etc...

    public ReadOnlyDoubleProperty transactionFeeProperty() {
        return this.transactionFee.getReadOnlyProperty();
    }

    public final double getTransactionFee() {
        return transactionFeeProperty().get();
    }

}




ObservableList<Trade> observableListOfTrades =FXCollections.observableArrayList(trade ->
        new Observable[]{
                trade.transactionDateProperty(),
                trade.stockTickerProperty(),
                trade.buySellProperty(),
                trade.volumeProperty(),
                trade.priceProperty(),
        }
    );


以下内容在功能上是等效的(出于某些原因,我会让您知道...):

ObservableList<Trade> observableListOfTrades =FXCollections.observableArrayList(trade ->
        new Observable[]{
                trade.transactionDateProperty(),
                trade.stockTickerProperty(),
                trade.buySellProperty(),
                trade.transactionFeeProperty(),
        }
    );

08-25 01:53