Deep source analysis and application introduction of Java collection Properties

Keywords: Attribute xml JDK Java

                        .

1 overview of properties

public class Properties
  extends Hashtable<Object,Object>

   Properties, from the collection class of JDK 1.0, inherits Hashtable, which is thread safe.
   this class has no generics, because its element type is fixed: both key and value can only be String type, although you can use put method to store other types of key value, it is not recommended to do so.
                       .
                                  .

2 source code analysis of properties

2.1 main attributes

                       . Therefore, before understanding Properties, you can understand hash table: Deep analysis and application of Java set Hashtable.
It also has its own attribute defaults. In fact, the function of this attribute is to search from defaults (if any) when no corresponding attribute is found in the attribute table itself. The defaults here are used to store the default value of the attribute, so the value of this attribute is optional (according to your needs).

/**
 * An internal property list that contains the default values for any keys not found in this property list.
 * In fact, the function of this attribute is to search from the defaults (if any) when no corresponding attribute is found in the attribute table itself. The defaults here are used to store the default value of the attribute
 */
protected Properties defaults;

2.2 constructor

2.2.1 Properties()

public Properties()

   create an empty property sheet collection with no default values.

public Properties() {
    //Internal call to another constructor, passing null defaults
    this(null);
}

2.2.2 Properties(Properties defaults)

public Properties(Properties defaults)

   create an empty property list with the specified default value. The default value can also be specified as null.

public Properties(Properties defaults) {
    this.defaults = defaults;
}

2.3 traversal method

                               .
                      !

2.3.1 propertyNames method

public Enumeration< ? > propertyNames()

   returns an enumeration of all keys in the property sheet, including those in the default property sheet, if any. Method of JDK 1.0.
   if there is a key of non String type in Properties, an error will be reported: ClassCastException.

/**
 * @return Returns an enumeration of all keys in the property sheet, including those in the default property sheet.
 */
public Enumeration<?> propertyNames() {
    //Here, create a new hashtable named h
    Hashtable<String, Object> h = new Hashtable<>();
    //This method is used to store the traversed key value in h
    enumerate(h);
    //Return the enumeration of keys through the keys method of hashtable
    return h.keys();
}

/**
 * It is used to store the traversed key value in h. if there is a key of non String type, an error will be reported: ClassCastException
 *
 * @param h
 */
private synchronized void enumerate(Hashtable<String, Object> h) {
    //This step shows that if the internal defaults are not null, then defaults will call this method recursively Until defaults is null, start the following code
    if (defaults != null) {
        defaults.enumerate(h);
    }
    //To this step, it means that the bottom-level defaults (null) are traversed from the outside to the inside. Then, the keys enumeration of each layer defaults is traversed from the inside to the outside and added to the hashtable!
    for (Enumeration<?> e = keys(); e.hasMoreElements(); ) {
        //Get the key and forcibly convert it to String. We can know that if you don't store the key of String type, an error will be reported when the key is executed
        String key = (String) e.nextElement();
        //Save the key to hashtable. If value is null, an error will also be reported.
        h.put(key, get(key));
    }
}

2.3.2 stringPropertyNames method

public Set< String > stringPropertyNames()

   returns the key set in this property sheet, where the key and its corresponding value are strings. If no key with the same name is found in the main property list, different keys in the default property list are also included.
A new method of JDK 1.6. Compared with the propertyNames method, it is easier to operate on the results and relatively friendly. For key and value of non String type, errors will be reported directly in the propertyNames method, which will be ignored and returned normally.

public Set<String> stringPropertyNames() {
    //Here, create a new hashtable named h
    Hashtable<String, String> h = new Hashtable<>();
    //This method is used to store the traversal key value in h
    enumerateStringProperties(h);
    //Return the set set set of key through the keySet method of hashtable
    return h.keySet();
}

/**
 * It is used to store the key value of the traversed String type in h. if there is a key value of non String type, it will be ignored
 *
 * @param h
 */
private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
    //This step shows that if the internal defaults are not null, then defaults will call this method recursively Until defaults is null, start the following code
    if (defaults != null) {
        defaults.enumerateStringProperties(h);
    }
    //To this step, it means that the bottom-level defaults (null) are traversed from the outside to the inside. Then, the keys enumeration of each layer defaults is traversed from the inside to the outside and added to the hashtable!
    for (Enumeration<?> e = keys(); e.hasMoreElements(); ) {
        //Get key value
        Object k = e.nextElement();
        Object v = get(k);
        //If k and v are not both of String type, they will be ignored instead of error reporting
        if (k instanceof String && v instanceof String) {
            //If both k and v are of String type, h will be added
            h.put((String) k, (String) v);
        }
    }
}

2.3.3 summary

   when we traverse Properties, these two methods will additionally traverse the Properties in defaults, while the convenient methods of Hashtable will not, so we need to choose carefully!
   at the same time, if you need to traverse the properties in the defaults and return, you can only use the propertyNames and stringPropertyNames methods. The difference is that the return value types are different. The first is Enumeration, the second is set collection, which is more convenient to operate, supports iterator Iterator.remove , Set.remove , removeAll, retainAll, and clear operations. That is to say, this set supports element removal and can remove the corresponding mapping relationship from the mapping, but it does not support add or addAll operations.
   and if a key of non String type is encountered, the propertyNames method will throw an exception; while the stringPropertyNames method will ignore the key value of not all String types instead of throwing an exception.

2.4 method of reading from external file

The most important function of   properties collection is to obtain configuration information from external configuration files. Properties can read information from. Properties files and. XML files. Then natural properties provides corresponding methods!
The data in the  . properties file must be in the form of key value pairs, which can be separated by symbols such as "=", ":", "", "", "" \ t "," and "\ F". Note that here \ t represents a tab character and \ f represents a page break. The "space" here can be \ u00A0 (continuous space), \ u0020 (half width / English space), \ u3000 (full width / Chinese space). At the same time, the lines at the beginning of "ා" and "!" are counted as comments and will not be resolved.

Read the properties file:

public void load(InputStream inStream)

   read the list of attributes (key and element pairs) from the byte input stream.

public void load(Reader reader)

   reads a list of attributes (key and element pairs) from the input character stream in a simple row oriented format.

Read xml file:

public void loadFromXML(InputStream in)

   loads all the attributes represented by the XML document in the specified byte input stream into this property sheet.

2.4.1 load method

                       .

public synchronized void load(InputStream inStream) throws IOException {
    //Call the loca0 method and pass in the LineReader object. As the name implies, the object can read data line by line
    load0(new LineReader(inStream));
}

/**
 * Read data from LineReader to propeties
 *
 * @param lr
 * @throws IOException
 */
private void load0(LineReader lr) throws IOException {
    char[] convtBuf = new char[1024];
    int limit;
    int keyLen;
    int valueStart;
    char c;
    boolean hasSep;
    boolean precedingBackslash;
    /*Read one line at a time, loop read
     * If there is data, then linit is greater than 0*/
    while ((limit = lr.readLine()) >= 0) {
        c = 0;
        keyLen = 0;
        valueStart = limit;
        hasSep = false;

        //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
        precedingBackslash = false;
        while (keyLen < limit) {
            c = lr.lineBuf[keyLen];
            //Detect separator
            // =: can be used as separator
            if ((c == '=' || c == ':') && !precedingBackslash) {
                valueStart = keyLen + 1;
                hasSep = true;
                break;
                // Spaces \ t \ f can also be used as separators
            } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
                valueStart = keyLen + 1;
                break;
            }
            //  \Will be parsed into\
            if (c == '\\') {
                precedingBackslash = !precedingBackslash;
            } else {
                precedingBackslash = false;
            }
            keyLen++;
        }
        while (valueStart < limit) {
            c = lr.lineBuf[valueStart];
            if (c != ' ' && c != '\t' && c != '\f') {
                if (!hasSep && (c == '=' || c == ':')) {
                    hasSep = true;
                } else {
                    break;
                }
            }
            valueStart++;
        }
        //Get the parsed key and value
        String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
        String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
        //Call put method to store in collection
        put(key, value);
    }
}

2.5 method of output to external documents

Output to the properties file:

public void store(OutputStream out,String comments)

Write to output byte stream.
   Out: specifies an output stream; comments: the description of the property list, which can be null if there is no required comment..

public void store(Writer writer,String comments)

Write to the output character stream.

Output to xml file:

public void storeToXML(OutputStream os,String comment)

   issue an XML document that represents all the attributes contained in this table.

public void storeToXML(OutputStream os,String comment,String encoding)

   issue an XML document that represents all the attributes contained in this table using the specified encoding.

2.6 other methods

public synchronized Object setProperty(String key, String value)

   add a property, requiring the key and value of the property to use a string. The method put of Hashtable is called internally, and the return value is the result of the call put of Hashtable. Here we know that the key value pairs stored in this method are stored in the table attribute instead of the defaults attribute!
The   Properties collection should use this method instead of put to store Properties.

public synchronized Object setProperty(String key, String value) {
    return put(key, value);
}

public String getProperty(String key)

   search for a property in this property list with the specified key. If the key is not found in this property list, then recursively check the default property list and its default values. If the property is not found, the method returns null.
The   Properties collection should use this method instead of get to get property values.

public String getProperty(String key) {
    //Use the hashtable method to get the value. Note that it is the Object type
    Object oval = super.get(key);
    //If oval is of String type, then strong conversion to String and assign to sval, otherwise sval=null
    String sval = (oval instanceof String) ? (String) oval : null;
    //If sval=null and defaults is not empty, then the key value pair is not found in table, then search from defaults
    //Here, the defaults or the called getProperty method can be seen as a recursive search
    return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}

3 read file case demonstration

   let's briefly demonstrate how to read the configuration information of the. properties file at startup, which is mainly divided into two steps:

  1. Get the IO stream of the file;
  2. Read data from IO stream;
public class ReadFileByClassLoader {
    /**
     * Define an empty projects collection as a class variable, which is loaded as the class is loaded, and all the blocks and methods of the class can access
     */
    private static Properties properties = new Properties();

    /**
     * The method of using loader to read class path configuration file is defined in static block, so that the information of configuration file can be read when class is created
     */
    static {
        try {
            // There are three ways to get bytecode file objects!
            //Class<? extends ReadFileByClassLoader> class1 = ReadFileByClassLoader.class;
            //Class<?> class1 = Class.forName("collection.map.ReadFileByClassLoader");  //2
            //Class<? extends ReadFileByClassLoader> aClass = new ReadFileByClassLoader().getClass();  //3

            /*Method 1 = = > obtain the bytecode file object, then obtain the classloader, and call the classloader's method to obtain the input stream*/
            //The parameter of getResourceAsStream() method requires the package path to start from the package under resources + properties filename +. Suffix
            //there student.properties The file exists under the resources package, so write the name directly
            //InputStream resourceAsStream = ReadFileByClassLoader.class.getClassLoader().getResourceAsStream("student.properties");

            /*Method 2 = = > you can also directly use the getResourceAsStream method of bytecode file object to get the input stream*/
            //Pay attention to the front here/
            //InputStream resourceAsStream = ReadFileByClassLoader.class.getResourceAsStream("/student.properties");

            /*Method 3 = = > use getSystemResourceAsStream method of classloader to get input stream*/
            //InputStream resourceAsStream = ClassLoader.getSystemResourceAsStream("student.properties");

            /*Method 4 = = > read file bytes directly using input stream*/
            //The parameter of new File() requires the package path to start from src package + properties filename +. Suffix according to the format
            //there student.properties The files are stored under the resources package
            InputStream resourceAsStream = new BufferedInputStream(new FileInputStream(new File("src/main/resources/student.properties")));
            //Call the load input stream of properties
            properties.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        // Start to get the profile information directly
        System.out.println(properties);
    }
}

                        , student.properties Files are placed under the resources directory. Different project structures and different locations of configuration files may lead to different loading paths.
Here student.properties The contents of the configuration file are as follows:

! !As a comment
# #As a comment
# Equal sign separation
name=Zhang San
# : separation
age:22
# Space separation
score 22.1
a           i
# \t separation
b  xx
#  \Resolved into\
c=x\\

                   

{b=xx, a=i, age=22, name=Zhang San, score=22.1, c=x\}

If you don't understand or need to communicate, you can leave a message. In addition, I hope to like, collect and pay attention to it. I will keep updating all kinds of Java learning blogs!

Posted by maliskoleather on Thu, 11 Jun 2020 23:31:10 -0700