I'm trying to understand why java.util.Properties was implemented in this way. It has two interfaces: getProperty/setProperty which only accepts strings, and put/get which accepts any object as a value. These two interfaces appear to be overlapping, so a string added with put() can be retrieved using getProperty().
There seems to be some problems with this weird hybrid interface. Putting an object that overrides a string property has the side-effect of clearing the string value, producing null as the getProperty result. Adding an integer, or some other value that has a simple string translation, might be misunderstood as being a real property value (but as a property it's always null).
My question is: Is there a real, practical reason for this? Or is it a half-baked implementation as I suspect?
Joshua Bloch mentions this explicitly in Effective Java
[from Chapter 4] In the case of
Properties
, the designers intended that only strings be allowed as keys and values, but direct access to the underlyingHashtable
allows this invariant to be violated. Once this invariant is violated, it is no longer possible to use other parts of the Properties API (load
andstore
). By the time this problem was discovered, it was too late to correct it because clients depended on the use of nonstring keys and values.
That text is in context of using composition over inheritance. He's basically using this as an example of when composition should be used instead of inheritance. If Properties
wrapped a Map
instead of extending one, it could have enforced the invarient of using String
as keys and values.
So the answer is: It was an oversight.
Access to put
and get
is a result of Properties
being an extension of Hashtable
, and the two method should not be used (but cannot be hidden from implementation due to their public access in the superclass).
The Javadocs have a nice note about why you shouldn't use those methods, and should instead only use strings:
Because
Properties
inherits fromHashtable
, theput
andputAll
methods can be applied to aProperties
object. Their use is strongly discouraged as they allow the caller to insert entries whose keys or values are notStrings
. ThesetProperty
method should be used instead. If thestore
orsave
method is called on a "compromised"Properties
object that contains a non-String
key or value, the call will fail. Similarly, the call to thepropertyNames
orlist
method will fail if it is called on a "compromised"Properties
object that contains a non-String
key.
As @yshavit notes, it'd make more sense for Properties
to extend Hashtable<String, String>
than a hashtable of two objects, but this was likely a decision made to maintain backwards compatibility, as any programs using get
/put
with any non-String objects would have been broken by such a change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With