4 Replies Latest reply: Sep 29, 2012 10:53 PM by 965123 RSS

    Suggestion for Improving Number

    James Genac
      Hello Oracle Java community,

      I've recently encountered some difficulties using the abstract class java.lang.Number, and have a suggestion for improvement.

      I'm writing a class that computes statistical information on a list of numbers - it would be nice to not couple this class to Integer, Double, BigDecimal, or any other wrapper by using generics. I saw that there is a nice superclass that all Number objects inherit from.

      I came up with:
      public class Statistics<T extends Number> {

      private List<T> data;

      // statistical data that i wish to find and store, such as median, mean, standard dev, etc

      public synchronized void setData(List<T> data) {
      this.data = data;
      if (this.data != null && !this.data.isEmpty()) calculateStatistics();

      private void calculateStatistics() {
      // Welcome to instanceof and casting hell...


      h4. It would be nice to have richer functionality from the Number class, say to do mathematical operations with them or compare them.
      h4. After all, in the real world it is possible to do so.

      h4. Real numbers are much like BigDecimal. Why not take the idea of BigDecimal, and make that the parent of Integer, BigInteger, Double, Short, Byte, Float (I'm probably forgetting a few)? All of those are limited forms of real numbers. It would make comparison between Number datatypes easy, would probably remove all of that duplicated arithmetic code between all of the children of Number, and also allow Numbers to be used in powerful generic ways. The parent/replacement of BigDecimal could even be named RealNumber, which stays true to its math domain.

      As a side note, I'm solving this problem by taking an initial step to convert the List<whatever type of Number that the user enters> into a List<BigDecimal> by getting the toString() value of each element when cast as a Number.

      private List<BigDecimal> convertData(List<T> data) {
      ArrayList<BigDecimal> converted = new ArrayList<BigDecimal>();

      for (T element : data) {
      converted.add(new BigDecimal(((Number) element).toString()));
      return converted;

      Criticism is always welcome.

      Thanks for your time and thoughts.
      -James Genac
        • 1. Re: Suggestion for Improving Number
          Seems to me you would have a lot of trouble writing an equals() method for this RealNumber class.

          Remember that for BigDecimal, 2.0 is not equal to 2.00 because they have different scales (see the API docs for details). So that would mean that whenever you compared a Double object to a BigDecimal object, you would have to somehow figure out what scale would be suitable for that Double. Or perhaps you could always return false, regardless of the values of the two objects. In one case you are in danger of going down the road where equals() isn't transitive, and in the other case you are in danger of making the equals() method meaningless.

          Personally if they ever rewrite Java to get rid of legacy stuff, I would like to see things like int and float, which expose hardware dependencies and idiosyncrasies, be removed in favour of more generalized Number classes which don't remind you all the time that you're using 8-bit bytes for integer data and IEEE-754 (or whatever it is) for non-integer data. But of course that doesn't help you with the current question.
          • 2. Re: Suggestion for Improving Number
            Another reason not to do so is to save memory. When a small number can be represented with a Byte, you don't want to use a BigDecimal to represent it since BigDecimal uses more bytes. In terms of efficient memory utilization and hence the performance, you should look for the smallest data type that is sufficient for you. The common parent class idea sounds good in terms of modeling mathematical number type relationships to the computer domain, but the parent type then should be capable of representing all types - generally consuming more bytes and more CPU cycles than needed for the job at hand.
            • 3. Re: Suggestion for Improving Number
              James Genac
              Thanks for the replies and good points.

              It's fine that the .equals() method doesn't determine that 2.00 is equal to 2.0 because that's what the compareTo() method is for - numerical equivalency. equals() can be numerical and scale equivalency. Even if the .equals() method would be for solely numerical equivalency, a subclass of RealNumber representing a scale-significant number could implement the numeric and scale dependent version of .equals().

              As for the size, good point. BigDecimal does eat more memory than something like Byte. Then again, if performance is what you're after, you're simply not going to beat primitives. The objective of wrappers was not to perform well, but to allow them to be modeled into modern data structures and to be more flexible. Not to say that a heavily-used java standard library class shouldn't be optimally performing, but performance tradeoffs are to be expected.

              Also, to your point, legacy systems that are used to running near their max heap size may get pushed over the edge if they use a lot of wrappers. If there is no way to efficiently represent real numbers in a way that is comparable to say, Integers, Shorts, or Bytes, then it cannot be done.

              Edited by: James Genac on Sep 29, 2012 8:44 AM
              • 4. Re: Suggestion for Improving Number
                How compareTo() came into existence is from Comparable interface. As I understand, Comparable came into existence since Collections API has sorting functions - which needs to be run with a matching Comparable object that knows how to determine which element is larger than the other (not limited to objects representing numbers, you might sort a list of Persons). Hence, compareTo() is not solely meant for the comparison of numbers. Existence of the method in BigDecimal is just one case.

                Subclasses can override the equals() method, but that cannot be implemented in a cleaner manner and leads to a very poor design. For example, you might want to compare an Integer and a Float. So the Integer class's equals() method need to have some if-else structure to determine the other type and then compare. Same holds true for the Float class's equals() method as well. Ultimately, Everything becomes a mess. All subclasses of RealNumber needs to know about all other subclasses of RealNumber. And you will not be able to introduce new subtypes and expect the equals() method to work correctly.

                To avoid this, you need to depend on a single representation form for all types of numbers. If that's the case, you might just live with something like BigDecimal and not use Byte, Float, Integer,... (which we kind of do in some cases - for example to represent monetary amounts). So we can live without Byte, Float, Integer,...

                Then we need some utility classes that would contain some number type specific functions to work with primitives. So we will also have Byte, Float, Integer... unrelated to BigDecimal.

                Clearly, the wrapper types are there not because of the need to represent real world number types, but because of the need to represent computer domain number types. Hence, they have been organized not according to relationships found in real world number types. Many of us find this way of modelling sufficient and have an understanding about the limitations. But if you need to model the real world number relationships for some special reason, you might write some new classes. Then again there will be real world aspects that you will not be able to model easily. So you will model some aspects and neglect the other.