2 Replies Latest reply: Dec 2, 2012 10:58 PM by DanD RSS

    Conditional bind fails with divide by zero using the fluent API

    DanD
      I have two properties that I want to bind to a progress bar. The properties basically represent a max count value (the denominator), and a current count value (a numerator). I want to setup a bind using the fluent API that works more or less like so:
      IntegerProperty numerator = new SimpleIntegerProperty(0);
      IntegerProperty denominator = new SimpleIntegerProperty(0);
      
      progressBar.progressProperty().bind(
          Bindings.when(denominator.isEqualTo(0))
              .then(0)
              .otherwise(numerator.divide(denominator)));
      The numerator and denominator properties represent two properties in my model object that change based on certain criteria in the app, and I want the progress bar to be bound to those changes. The problem is at times, and by default, the denominator value is 0. My logic tells me the otherwise() clause should not execute, because the when() condition should evaluate to true, and therefore run the then() clause. When I run the code above, I get an ArithmeticException (/ by zero).

      Question - is this the correct behavior of the underlying binding code? I don't get why the otherwise() clause is being evaluated in this case.
      Can I suggest an enhancement to short-circuit the logic to avoid such a situation?

      My solution is to create a custom DoubleBinding like so:
      IntegerProperty numerator = new SimpleIntegerProperty(0);
      IntegerProperty denominator = new SimpleIntegerProperty(0);
      
      DoubleBinding db = new DoubleBinding() {
          { super.bind(numerator, denominator); }
       
          @Override
          protected double computeValue() {
              if(denominator.getValue() == 0) {
                  return 0.0;
              }
              return numerator.doubleValue() / denominator.doubleValue();
          }
      };
              
      progressBar.progressProperty().bind(db);
      I very much like the fluent API better (much less code to write, and far more elegant), though I'm glad the custom binding isn't too hard to write and understand.

      Thank you for any comments or feedback.