1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html#License
3/*
4**********************************************************************
5* Copyright (c) 2004-2013, International Business Machines
6* Corporation and others.  All Rights Reserved.
7**********************************************************************
8* Author: Alan Liu
9* Created: April 20, 2004
10* Since: ICU 3.0
11**********************************************************************
12*/
13package com.ibm.icu.util;
14
15
16/**
17 * An amount of a specified unit, consisting of a Number and a Unit.
18 * For example, a length measure consists of a Number and a length
19 * unit, such as feet or meters.
20 *
21 * <p>Measure objects are parsed and formatted by subclasses of
22 * MeasureFormat.
23 *
24 * <p>Measure objects are immutable. All subclasses must guarantee that.
25 * (However, subclassing is discouraged.)
26 *
27 * @see java.lang.Number
28 * @see com.ibm.icu.util.MeasureUnit
29 * @see com.ibm.icu.text.MeasureFormat
30 * @author Alan Liu
31 * @stable ICU 3.0
32 */
33public class Measure {
34
35    private final Number number;
36    private final MeasureUnit unit;
37
38    /**
39     * Constructs a new object given a number and a unit.
40     * @param number the number
41     * @param unit the unit
42     * @stable ICU 3.0
43     */
44    public Measure(Number number, MeasureUnit unit) {
45        if (number == null || unit == null) {
46            throw new NullPointerException("Number and MeasureUnit must not be null");
47        }
48        this.number = number;
49        this.unit = unit;
50    }
51
52    /**
53     * Returns true if the given object is equal to this object.
54     * @return true if this object is equal to the given object
55     * @stable ICU 3.0
56     */
57    @Override
58    public boolean equals(Object obj) {
59        if (obj == this) {
60            return true;
61        }
62        if (!(obj instanceof Measure)) {
63            return false;
64        }
65        Measure m = (Measure) obj;
66        return unit.equals(m.unit) && numbersEqual(number, m.number);
67    }
68
69    /*
70     * See if two numbers are identical or have the same double value.
71     * @param a A number
72     * @param b Another number to be compared with
73     * @return Returns true if two numbers are identical or have the same double value.
74     */
75    // TODO improve this to catch more cases (two different longs that have same double values, BigDecimals, etc)
76    private static boolean numbersEqual(Number a, Number b) {
77        if (a.equals(b)) {
78            return true;
79        }
80        if (a.doubleValue() == b.doubleValue()) {
81            return true;
82        }
83        return false;
84    }
85
86    /**
87     * Returns a hashcode for this object.
88     * @return a 32-bit hash
89     * @stable ICU 3.0
90     */
91    @Override
92    public int hashCode() {
93        return 31 * Double.valueOf(number.doubleValue()).hashCode() + unit.hashCode();
94    }
95
96    /**
97     * Returns a string representation of this object.
98     * @return a string representation consisting of the ISO currency
99     * code together with the numeric amount
100     * @stable ICU 3.0
101     */
102    @Override
103    public String toString() {
104        return number.toString() + ' ' + unit.toString();
105    }
106
107    /**
108     * Returns the numeric value of this object.
109     * @return this object's Number
110     * @stable ICU 3.0
111     */
112    public Number getNumber() {
113        return number;
114    }
115
116    /**
117     * Returns the unit of this object.
118     * @return this object's Unit
119     * @stable ICU 3.0
120     */
121    public MeasureUnit getUnit() {
122        return unit;
123    }
124}
125