bb.util
Class Properties2

java.lang.Object
  extended by bb.util.Properties2
All Implemented Interfaces:
ConcurrentMap<String,String>, Map<String,String>, SortedMap<String,String>

public class Properties2
extends Object
implements SortedMap<String,String>, ConcurrentMap<String,String>

This class is what Properties ought to have been, namely, a Map<String, String> implementation with additional constraints and convenience methods.

Properties has issues:

  1. it lacks necessary constraints, for instance, it allows generic Objects to be used as keys and/or values
  2. it imposes no ordering on its keys (it's nice to have them iterated over in alphabetical, instead of random, order)
  3. it subclasses Hashtable (it should have used composition instead of inheritance, that is, have a field of some Map type that it delegates to)
This class fixes all these issues: it implements the SortedMap and ConcurrentMap interfaces (so it supports all that functionality, but is not commited to a particular implementation), plus it constrains keys and values.

This class also offers much additional functionality that is not present in Properties.

First, it offers several convenience constructors for initializing name/value pairs from Files, Maps, and Strings.

Second, it adds many convenience getXXX methods. With these methods, the user specifies whether mappings are mandatory or are optional. Specificly, every getXXX method comes in one-arg and two-arg versions. The one-arg versions take only a String key param, and have mandatory mapping semantics: each will throw an IllegalStateException if key is not mapped to a value (e.g. getProperty(key), getDouble(key), etc). The two-arg versions take both a String key param and a String default value param, and have optional mapping semantics: each will return the default value if key is not mapped to a value (e.g. getProperty(key, valueDefault), getDouble(key, valueDefault), etc). Note that the default value is never constrained, except for type correctness (e.g. it may be null).

Third, this class supports valid key checking.

Fourth, this class supports the notion of effectively only a key being present; see isKeyOnlyPresent and putKeyOnly. This is useful for dealing with command line switches where only the key part is present; see the String[]-arg constructor.

Fifth, this class supports auditing. It is not unusual in a large project for a Properties instance to be mutated at multiple points in the codebase, and this mutation includes not only adding new key/value pairs, but also overriding existing key/value pairs. If some piece of this configuration code is buggy, it can be very difficult to find the offender. (This same issue, by the way, affects the System properties.) To ease this type of debugging, this class logs whenever its properties are mutated. It not only logs the event and the state that changed, but it also logs the full stack trace of the calling thread.

Sixth, this class supports freezing its state. This allows initialization code to populate an instance, and then make it effectively immutable. As with auditing, this can be invaluable in large codebases. Be aware that freezing an instance has some subtle consequences. In particular, after freezing, entrySet, keySet, and values can no loner be called because all are potentially mutative (if their results are mutated, the change is propogated to this class). Users who need a view of the keys and values of this class after freezing should call copy.

Since this class is not an instance of Properties, it offers interoperability support. For converting Properties into Properties2, the toSortedMap method will convert a Properties instance into a Map instance which can then be passed to the Map-arg constructor or to putAll. This technique is used by the File[]-arg constructor to support legacy properties files. For converting Properties2 into Properties, the toProperties method may be called. This is useful when interacting with old APIs that require Properties instances.

Here is an example of a subclass which relaxes this class's restriction on values being non-blank. The subclass below allows values to be any non-null String (i.e. empty or all whitespace Strings are additionally allowed):


        private static class Properties3 extends Properties2 {
                // probably want to have more than the default no-arg constructor...

                protected String checkValue(Object obj) throws IllegalArgumentException {
                        Check.arg().notNull(obj);
                        if (!(obj instanceof String)) throw new IllegalArgumentException("arg " + obj.toString() + " is of type " + obj.getClass().getName() + " which is not an instance of String");
                        return (String) obj;
                }
        }
 

This class is multithread safe: every public method is synchronized.

Author:
Brent Boyer

Nested Class Summary
static class Properties2.UnitTest
          See the Overview page of the project's javadocs for a general description of this unit test class.
 
Nested classes/interfaces inherited from interface java.util.Map
Map.Entry<K,V>
 
Field Summary
private  int auditDepth
           
private  boolean frozen
           
private  long instanceId
          This instance's Id.
private static AtomicLong instanceIdNext
          The next Properties2 instance's instanceId field.
private  Logger2 logger2
           
private  SortedMap<String,String> sortedMap
          Holds all this instance's property data.
private static String valueUndefined
           
 
Constructor Summary
Properties2()
          Constructs a new instance which contains no key/value pairs.
Properties2(File... files)
          Constructs a new instance with key/value pairs parsed from files.
Properties2(Map<String,String> m)
          Constructs a new instance with initial key/value pairs drawn from m.
Properties2(String[] args)
          Constructs a new instance with initial key/value pairs parsed from args.
 
Method Summary
private  void audit(Level level, String methodName, String msg)
           
protected  String checkKey(Object obj)
          Checks that obj is a valid key.
 Properties2 checkKeys(Collection<String> keysLegal)
          Checks if this instance contains any keys which are not elements of keysLegal.
private  void checkMutate(String msg)
           
protected  String checkValue(Object obj)
          Checks that obj is a valid value.
 void clear()
          
 Comparator<? super String> comparator()
           
 boolean containsKey(Object key)
          
 boolean containsValue(Object value)
          
 ConcurrentNavigableMap<String,String> copy()
          Copies this instance into a new ConcurrentNavigableMap, which is then returned.
 Set<Map.Entry<String,String>> entrySet()
          
 boolean equals(Object obj)
           
 String firstKey()
           
 void freeze()
          Freezes this instances state to its present values.
 String get(Object key)
          Returns the String value to which key is mapped, or null if this instance contains no mapping for key.
 boolean getBoolean(String key)
          Returns Boolean.parseBoolean( getProperty(key) ).
 boolean getBoolean(String key, boolean valueDefault)
          If key has an associated value, then returns Boolean.parseBoolean(value).
 byte getByte(String key)
          Returns Byte.parseByte( getProperty(key) ).
 byte getByte(String key, byte valueDefault)
          If key has an associated value, then returns Byte.parseByte(value).
 double getDouble(String key)
          Returns Double.parseDouble( getProperty(key) ).
 double getDouble(String key, double valueDefault)
          If key has an associated value, then returns Double.parseDouble(value).
 File getFile(String key)
          Returns new File( getProperty(key) ).
 File getFile(String key, File valueDefault)
          If key has an associated value, then returns new File(value).
 float getFloat(String key)
          Returns Float.parseFloat( getProperty(key) ).
 float getFloat(String key, float valueDefault)
          If key has an associated value, then returns Float.parseFloat(value).
 int getInt(String key)
          Returns Integer.parseInt( getProperty(key) ).
 int getInt(String key, int valueDefault)
          If key has an associated value, then returns Integer.parseInt(value).
 long getLong(String key)
          Returns Long.parseLong( getProperty(key) ).
 long getLong(String key, long valueDefault)
          If key has an associated value, then returns Long.parseLong(value).
 String getProperty(String key)
          Returns the value associated with key.
 String getProperty(String key, String valueDefault)
          If key has an associated value, then returns that value.
 short getShort(String key)
          Returns Short.parseShort( getProperty(key) ).
 short getShort(String key, short valueDefault)
          If key has an associated value, then returns Short.parseShort(value).
protected  String getValueUndefined()
          Returns the value associated with every key added by putKeyOnly.
 int hashCode()
           
 SortedMap<String,String> headMap(String toKey)
          
 boolean isEmpty()
           
 boolean isFrozen()
          Reports whether or not this instance's state has been frozen.
 boolean isKeyOnlyPresent(String key)
          Reports whether or not only key is effectively in this instance (i.e. it has no substantial associated value).
protected  boolean isSwitchKey(String s)
          Determines whether or not s is a key for a command line switch.
 Set<String> keySet()
          
 String lastKey()
           
static Properties parseProperties(File file)
          Parses a new Properties instance from the contents of file.
 String put(String key, String value)
          Associates key with value, replacing any previous mapping of key.
 void putAll(Map<? extends String,? extends String> m)
          Copies all of the mappings from m to this instance.
 String putIfAbsent(String key, String value)
          
 String putKeyOnly(String key)
          Associates key with the result of getValueUndefined.
 String remove(Object key)
          
 boolean remove(Object key, Object value)
          
 String replace(String key, String value)
          
 boolean replace(String key, String valueOld, String valueNew)
          
 int size()
           
 SortedMap<String,String> subMap(String fromKey, String toKey)
          
 SortedMap<String,String> tailMap(String fromKey)
          
 Properties toProperties()
          Converts this instance into a new Properties instance, which is then returned.
static SortedMap<String,String> toSortedMap(Properties properties)
          Converts properties into a SortedMap.
 Collection<String> values()
          
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

instanceIdNext

private static final AtomicLong instanceIdNext
The next Properties2 instance's instanceId field.

Contract: is initialized to 0, and if this field has that value, it means that no instances have been created.


valueUndefined

private static final String valueUndefined
See Also:
getValueUndefined, Constant Field Values

instanceId

private final long instanceId
This instance's Id.


sortedMap

private final SortedMap<String,String> sortedMap
Holds all this instance's property data.


logger2

private final Logger2 logger2

auditDepth

private int auditDepth

frozen

private boolean frozen
Constructor Detail

Properties2

public Properties2(File... files)
            throws IllegalArgumentException,
                   SecurityException,
                   RuntimeException
Constructs a new instance with key/value pairs parsed from files.

Each element of files is processed in sequence as follows:

  1. its contents are parsed into a new Properties instance
  2. that Properties is converted into a SortedMap
  3. that SortedMap is passed to putAll

This method never throws a checked Exception in order to support convenient one-line field assignments like

private final int port = new Properties2(file).getInt("Port", 7462);

Throws:
RuntimeException - (or some subclass) if any error occurs; this may merely wrap some other underlying Throwable
IllegalArgumentException
SecurityException

Properties2

public Properties2(Map<String,String> m)
            throws IllegalArgumentException
Constructs a new instance with initial key/value pairs drawn from m.

Throws:
IllegalArgumentException - if m is null; m contains a key which fails checkKey; m contains a value which fails checkValue

Properties2

public Properties2(String[] args)
            throws IllegalArgumentException
Constructs a new instance with initial key/value pairs parsed from args.

The key/value pairs in args must be a series of command line switches (since args is typically supplied on the command line to a program's main). The precise format is:

  1. a command line switch is a key, optionally followed by a value
  2. every key must pass isSwitchKey
  3. every value must fail isSwitchKey
  4. each key and (optional) value is a separate consecutive element of args
  5. a value element of args must always be preceded by an element of args that is its key
  6. corollary: args[0] must be a switch key
  7. since switch values are optional, there may be multiple consecutive elements of args which are just keys
  8. if a switch lacks a value element, then the switch's key is added using a call to putKeyOnly(java.lang.String)
  9. a given switch key may only appear once (it is an error to have duplicate switches)

A common use case for this constructor is to parse the command line arguments passed to some class's main method. Here is an example which illustrates how this class can parse, verify, and exploit command line arguments:


        public class Operations
                private static final String operation_key = "-operation";
                private static final String n_key = "-n";
                private static final List keysLegal = Arrays.asList( operation_key, numberLoops_key );

                public static void main(String[] args) {
                        // may also want to use bb.util.Execute.XXX here...

                        Check.arg().notEmpty(args);

                        Properties2 properties = new Properties2(args).checkKeys(keysLegal);    // parses args into name/value pairs and verifies that only legal keys present
                        String operation = properties.getProperty(operation_key);       // gets a mandatory property
                        int n = properties.getInt(n_key, 10);   // gets an optional property as an int, and uses a default value if absent
                        ...
                }
        }
 
This class might be executed on a command line like

        java  Operations  -operation add  -a 1  -b 2
 

Throws:
IllegalArgumentException - if args is null or violates a format rule
See Also:
Command line programs

Properties2

public Properties2()
Constructs a new instance which contains no key/value pairs.

Method Detail

parseProperties

public static Properties parseProperties(File file)
                                  throws RuntimeException
Parses a new Properties instance from the contents of file. The format of file must be compatible with Properties.load.

Throws:
RuntimeException - (or some subclass) if any error occurs; this may merely wrap some other underlying Throwable

toSortedMap

public static SortedMap<String,String> toSortedMap(Properties properties)
                                            throws IllegalArgumentException
Converts properties into a SortedMap.

The keys are obtained by calling Properties.stringPropertyNames(). So, only those key/value pairs where both are String instances are in the result. Furthermore, in addition to the String keys immediately in properties, the chain of default properties is drawn on as well.

Throws:
IllegalArgumentException - if properties is null

isSwitchKey

protected boolean isSwitchKey(String s)
Determines whether or not s is a key for a command line switch. Returns true if and only if s is not null and starts with a hyphen (i.e. '-') char.


checkKey

protected String checkKey(Object obj)
                   throws IllegalArgumentException
Checks that obj is a valid key.

This class requires keys to be String instances which are not blank. Subclasses may override to implement their own key constraints.

Returns:
obj cast to a String
Throws:
IllegalArgumentException - if obj is null, is not an instance of String, or is blank

checkValue

protected String checkValue(Object obj)
                     throws IllegalArgumentException
Checks that obj is a valid value.

This class imposes the same requirements on values as keys, so the implementation here simply calls checkKey(obj). Subclasses may override to implement their own value constraints.

Returns:
obj cast to a String
Throws:
IllegalArgumentException - if obj is null, is not an instance of String, or is blank

checkKeys

public Properties2 checkKeys(Collection<String> keysLegal)
                      throws IllegalArgumentException,
                             IllegalStateException
Checks if this instance contains any keys which are not elements of keysLegal.

A common use for this method is verifying command line arguments, as illustrated in the String[]-arg constructor javadocs.

Returns:
this instance
Throws:
IllegalArgumentException - if keysLegal is null
IllegalStateException - if this instance contains any keys which are not elements of keysLegal

audit

private void audit(Level level,
                   String methodName,
                   String msg)

freeze

public void freeze()
Freezes this instances state to its present values. This is accomplished by setting a field that will cause any future calls to mutative methods to fail. Accessor methods, however, may still be called.


isFrozen

public boolean isFrozen()
Reports whether or not this instance's state has been frozen.


checkMutate

private void checkMutate(String msg)
                  throws IllegalStateException
Throws:
IllegalStateException

clear

public void clear()
           throws IllegalStateException

Specified by:
clear in interface Map<String,String>
Throws:
IllegalStateException - if isFrozen returns true

containsKey

public boolean containsKey(Object key)
                    throws IllegalArgumentException

Specified by:
containsKey in interface Map<String,String>
Throws:
IllegalArgumentException - if key fails checkKey

containsValue

public boolean containsValue(Object value)
                      throws IllegalArgumentException

Specified by:
containsValue in interface Map<String,String>
Throws:
IllegalArgumentException - if value fails checkValue

entrySet

public Set<Map.Entry<String,String>> entrySet()
                                       throws IllegalStateException

Specified by:
entrySet in interface Map<String,String>
Specified by:
entrySet in interface SortedMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true

equals

public boolean equals(Object obj)
Specified by:
equals in interface Map<String,String>
Overrides:
equals in class Object

get

public String get(Object key)
           throws IllegalArgumentException,
                  IllegalStateException
Returns the String value to which key is mapped, or null if this instance contains no mapping for key.

Contract: the result is only null if key has no mapping, since this class does not permit null keys or values. Furthermore, if non-null, then the result is guaranteed to pass checkValue.

Specified by:
get in interface Map<String,String>
Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException
See Also:
getProperty(String), getProperty(String, String)

hashCode

public int hashCode()
Specified by:
hashCode in interface Map<String,String>
Overrides:
hashCode in class Object

isEmpty

public boolean isEmpty()
Specified by:
isEmpty in interface Map<String,String>

keySet

public Set<String> keySet()
                   throws IllegalStateException

Specified by:
keySet in interface Map<String,String>
Specified by:
keySet in interface SortedMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true

put

public String put(String key,
                  String value)
           throws IllegalStateException,
                  IllegalArgumentException
Associates key with value, replacing any previous mapping of key.

Specified by:
put in interface Map<String,String>
Returns:
the previous value associated with key, or null if there was no mapping for key
Throws:
IllegalStateException - if isFrozen returns true
IllegalArgumentException - if key fails checkKey; value fails checkValue

putAll

public void putAll(Map<? extends String,? extends String> m)
            throws IllegalStateException,
                   IllegalArgumentException
Copies all of the mappings from m to this instance. The effect of this call is equivalent to that of calling put(k, v) on this instance once for each mapping from key k to value v in m. The behavior of this operation is undefined if m is modified while the operation is in progress.

Specified by:
putAll in interface Map<String,String>
Throws:
IllegalStateException - if isFrozen returns true
IllegalArgumentException - if m is null; m contains a key which fails checkKey; m contains a value which fails checkValue

remove

public String remove(Object key)
              throws IllegalStateException

Specified by:
remove in interface Map<String,String>
Throws:
IllegalStateException - if isFrozen returns true

size

public int size()
Specified by:
size in interface Map<String,String>

values

public Collection<String> values()
                          throws IllegalStateException

Specified by:
values in interface Map<String,String>
Specified by:
values in interface SortedMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true

comparator

public Comparator<? super String> comparator()
Specified by:
comparator in interface SortedMap<String,String>

subMap

public SortedMap<String,String> subMap(String fromKey,
                                       String toKey)
                                throws IllegalStateException

Specified by:
subMap in interface SortedMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true

headMap

public SortedMap<String,String> headMap(String toKey)
                                 throws IllegalStateException

Specified by:
headMap in interface SortedMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true

tailMap

public SortedMap<String,String> tailMap(String fromKey)
                                 throws IllegalStateException

Specified by:
tailMap in interface SortedMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true

firstKey

public String firstKey()
Specified by:
firstKey in interface SortedMap<String,String>

lastKey

public String lastKey()
Specified by:
lastKey in interface SortedMap<String,String>

putIfAbsent

public String putIfAbsent(String key,
                          String value)
                   throws IllegalStateException,
                          IllegalArgumentException

Specified by:
putIfAbsent in interface ConcurrentMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true
IllegalArgumentException - if key fails checkKey; value fails checkValue

remove

public boolean remove(Object key,
                      Object value)
               throws IllegalStateException,
                      IllegalArgumentException

Specified by:
remove in interface ConcurrentMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true
IllegalArgumentException - if key fails checkKey; value fails checkValue

replace

public String replace(String key,
                      String value)
               throws IllegalStateException,
                      IllegalArgumentException

Specified by:
replace in interface ConcurrentMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true
IllegalArgumentException - if key fails checkKey; value fails checkValue

replace

public boolean replace(String key,
                       String valueOld,
                       String valueNew)
                throws IllegalStateException,
                       IllegalArgumentException

Specified by:
replace in interface ConcurrentMap<String,String>
Throws:
IllegalStateException - if isFrozen returns true
IllegalArgumentException - if key fails checkKey; valueOld or valueNew fail checkValue

getProperty

public String getProperty(String key)
                   throws IllegalArgumentException,
                          IllegalStateException
Returns the value associated with key.

Is identical to get except that null is never returned (an IllegalStateException is thrown instead).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value

getBoolean

public boolean getBoolean(String key)
                   throws IllegalArgumentException,
                          IllegalStateException
Returns Boolean.parseBoolean( getProperty(key) ).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value

getByte

public byte getByte(String key)
             throws IllegalArgumentException,
                    IllegalStateException,
                    NumberFormatException
Returns Byte.parseByte( getProperty(key) ).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value
NumberFormatException - if the value is not a parsable byte

getDouble

public double getDouble(String key)
                 throws IllegalArgumentException,
                        IllegalStateException,
                        NumberFormatException
Returns Double.parseDouble( getProperty(key) ).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value
NumberFormatException - if the value is not a parsable double

getFile

public File getFile(String key)
             throws IllegalArgumentException,
                    IllegalStateException
Returns new File( getProperty(key) ).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value

getFloat

public float getFloat(String key)
               throws IllegalArgumentException,
                      IllegalStateException,
                      NumberFormatException
Returns Float.parseFloat( getProperty(key) ).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value
NumberFormatException - if the value is not a parsable float

getInt

public int getInt(String key)
           throws IllegalArgumentException,
                  IllegalStateException,
                  NumberFormatException
Returns Integer.parseInt( getProperty(key) ).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value
NumberFormatException - if the value is not a parsable int

getLong

public long getLong(String key)
             throws IllegalArgumentException,
                    IllegalStateException,
                    NumberFormatException
Returns Long.parseLong( getProperty(key) ).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value
NumberFormatException - if the value is not a parsable long

getShort

public short getShort(String key)
               throws IllegalArgumentException,
                      IllegalStateException,
                      NumberFormatException
Returns Short.parseShort( getProperty(key) ).

Throws:
IllegalArgumentException - if key fails checkKey
IllegalStateException - if key is not associated with any value
NumberFormatException - if the value is not a parsable short

getProperty

public String getProperty(String key,
                          String valueDefault)
                   throws IllegalArgumentException
If key has an associated value, then returns that value. Otherwise, returns valueDefault.

Is identical to get except that null is never returned (valueDefault is returned instead).

Throws:
IllegalArgumentException - if key fails checkKey

getBoolean

public boolean getBoolean(String key,
                          boolean valueDefault)
                   throws IllegalArgumentException
If key has an associated value, then returns Boolean.parseBoolean(value). Otherwise, returns valueDefault.

Throws:
IllegalArgumentException - if key fails checkKey

getByte

public byte getByte(String key,
                    byte valueDefault)
             throws IllegalArgumentException,
                    NumberFormatException
If key has an associated value, then returns Byte.parseByte(value). Otherwise, returns valueDefault.

Throws:
IllegalArgumentException - if key fails checkKey
NumberFormatException - if the value is not a parsable byte

getDouble

public double getDouble(String key,
                        double valueDefault)
                 throws IllegalArgumentException,
                        NumberFormatException
If key has an associated value, then returns Double.parseDouble(value). Otherwise, returns valueDefault.

Throws:
IllegalArgumentException - if key fails checkKey
NumberFormatException - if the value is not a parsable double

getFile

public File getFile(String key,
                    File valueDefault)
             throws IllegalArgumentException,
                    NumberFormatException
If key has an associated value, then returns new File(value). Otherwise, returns valueDefault.

Throws:
IllegalArgumentException - if key fails checkKey
NumberFormatException

getFloat

public float getFloat(String key,
                      float valueDefault)
               throws IllegalArgumentException,
                      NumberFormatException
If key has an associated value, then returns Float.parseFloat(value). Otherwise, returns valueDefault.

Throws:
IllegalArgumentException - if key fails checkKey
NumberFormatException - if the value is not a parsable float

getInt

public int getInt(String key,
                  int valueDefault)
           throws IllegalArgumentException,
                  NumberFormatException
If key has an associated value, then returns Integer.parseInt(value). Otherwise, returns valueDefault.

Throws:
IllegalArgumentException - if key fails checkKey
NumberFormatException - if the value is not a parsable int

getLong

public long getLong(String key,
                    long valueDefault)
             throws IllegalArgumentException,
                    NumberFormatException
If key has an associated value, then returns Long.parseLong(value). Otherwise, returns valueDefault.

Throws:
IllegalArgumentException - if key fails checkKey
NumberFormatException - if the value is not a parsable long

getShort

public short getShort(String key,
                      short valueDefault)
               throws IllegalArgumentException,
                      NumberFormatException
If key has an associated value, then returns Short.parseShort(value). Otherwise, returns valueDefault.

Throws:
IllegalArgumentException - if key fails checkKey
NumberFormatException - if the value is not a parsable short

isKeyOnlyPresent

public boolean isKeyOnlyPresent(String key)
                         throws IllegalArgumentException
Reports whether or not only key is effectively in this instance (i.e. it has no substantial associated value).

In principle, this method should only return true if putKeyOnly(key) was the last mapping done on key. So, this method is implemented as return getValueUndefined() == get(key) (note that the == operator, not the equals method, is used).

Throws:
IllegalArgumentException - if key fails checkKey

putKeyOnly

public String putKeyOnly(String key)
                  throws IllegalStateException,
                         IllegalArgumentException
Associates key with the result of getValueUndefined. This special value is meant for situations in which only the presence of key in this instance matters and its associated value is irrelevant. For example, if this instance represents a set of command line switches, it is often the case that many of the switches just have a key part and no associated value.

Throws:
IllegalStateException - if isFrozen returns true
IllegalArgumentException - if key fails checkKey

getValueUndefined

protected String getValueUndefined()
Returns the value associated with every key added by putKeyOnly.

Contract: the result must be the same String instance for a given Properties2 instance. (This class satisfies this by returning a static constant, however, subclasses may behave differently.) Furthermore, the result must pass checkValue.


copy

public ConcurrentNavigableMap<String,String> copy()
Copies this instance into a new ConcurrentNavigableMap, which is then returned. This method is an alternative to clone. The result is not backed by this instance (so mutating the result does not affect this instance).

Motivation: because instances can be frozen, this method was written to get a view of this instance whose keys and values can always be interrogated. Recall that entrySet, keySet, and values are potentially mutative methods, and so they will throw an IllegalStateException if called after an instance has been frozen.


toProperties

public Properties toProperties()
Converts this instance into a new Properties instance, which is then returned. This method is useful when dealing with old APIs that require Properties instances (e.g. System.setProperties).