code: public void defuzzify() {
          if (!isEnabled()) {
              return;
          }
  
          if (Op.isFinite(getValue())) {
              setPreviousValue(getValue());
          }
  
          String exception = null;
  
          double result = Double.NaN;
          boolean isValid = !fuzzyOutput().getTerms().isEmpty();
          if (isValid) {
              /* Checks whether the variable can be defuzzified without exceptions.
               * If it cannot be defuzzified, be that due to a missing defuzzifier
               * or aggregation operator, the expected behaviour is to leave the
               * variable in a state that reflects an invalid defuzzification,
               * that is, apply logic of default values and previous values.*/
              isValid = false;
              if (getDefuzzifier() != null) {
                  try {
                      result = getDefuzzifier().defuzzify(fuzzyOutput(),
                              getMinimum(), getMaximum());
                      isValid = true;
                  } catch (Exception ex) {
                      exception = ex.toString();
                  }
              } else {
                  exception = String.format("[defuzzifier error] defuzzifier needed "
                          + "to defuzzify output variable <%s>", getName());
              }
          }
  
          if (!isValid) {
              //if a previous defuzzification was successfully performed and
              //and the output value is supposed not to change when the output is empty
              if (isLockPreviousValue() && !Double.isNaN(getPreviousValue())) {
                  result = getPreviousValue();
              } else {
                  result = getDefaultValue();
              }
          }
  
          setValue(result);
  
          if (exception != null) {
              throw new RuntimeException(exception);
          }
      }
docs: Defuzzifies the output variable and stores the output value and the
  previous output value