39

It seems that java.util.Properties assumes one value per propery key. That is,

foo=1
foo=2

is not expected,

Is there a class for this kind of multi-value property sheet, which also provides the load method?

ClueMinus
  • 393
  • 1
  • 3
  • 5
  • possible duplicate of [How do I specify values in a properties file so they can be retrieved using ResourceBundle#getStringArray?](http://stackoverflow.com/questions/226050/how-do-i-specify-values-in-a-properties-file-so-they-can-be-retrieved-using-reso) – Andy Brown Sep 07 '15 at 11:33

5 Answers5

72

Try:

foo=1,2

String[] foos = properties.getProperty("foo").split(",");
Adrian Petrescu
  • 16,629
  • 6
  • 56
  • 82
Nick Holt
  • 33,455
  • 4
  • 52
  • 58
  • 12
    The above line will throw a NullPointerException if property foo isn't found. So make sure to check the property exists or catch/throw the exception if the property is required. If the property is optional then properties.getProperty("foo", "").split(",") could be a safer alternative. – Lee Theobald Oct 12 '10 at 09:32
  • 2
    @lee-theobald: make your properties class a Groovy class and you can do this: `String[] foos = properties.getProperty("foo")?.split(",")` and foo will be null instead of getting an NPE :) – rjohnston Dec 12 '11 at 10:47
  • 1
    What if the data item itself contains a comma? – David Balažic Apr 20 '16 at 20:18
  • @DavidBalažic you'd need to use an alternative regex that allows the string property to be split into its constituent parts – Nick Holt Apr 25 '16 at 10:04
  • @DavidBalažic I skip commas as much as possible. Try using the old pipe " | " it not used that commonly in data. – Namphibian Dec 28 '16 at 22:21
23

The java.util.Properties function is pretty limited. If you want support list, you might want try PropertyConfiguration from Apache Commons Configuration,

http://commons.apache.org/configuration/userguide/howto_properties.html#Using_PropertiesConfiguration

With it, you can set any delimiters to your list and it will split for you automatically. You can also do other fancy things in properties file. For example,

foo=item1, item2
bar=${foo}, item3
number=123

You can retrieve it like this,

Configuration config = new PropertiesConfiguration("your.properties");
String[] items = config.getStringArray("bar"); // return {"item1", "item2", "item3"}
int number = config.getInt("number", 456); // 456 is default value
ZZ Coder
  • 74,484
  • 29
  • 137
  • 169
  • Does this work for property files only, or could this work for Java "-D" command line property parameters too? – David Nov 26 '13 at 00:44
4

Correct answer by Nick.

Or, if you can give a different subname to each value, you could have your properties be:

    my.properties

    foo.title=Foo
    foo.description=This a big fat foo.
KLE
  • 23,689
  • 4
  • 56
  • 62
  • 1
    But using this approach, how would you grab all main properties of foo, into a list/array/collection of foo? And since you've shown as subnames, one would think we'd like to grab the property once as a root object then iterate through the subnames by the subname as key to get it's value. That's trickier part. Just accessing them as individual properties is simple, but most people aren't looking to do it that way for multi-valued properties. – David Nov 25 '13 at 22:42
0

This won't provide the load method but a place to store them you could use a apache commons multivaluemap:

"A MultiValueMap decorates another map, allowing it to have more than one value for a key. "

This is often a requirement for http request parameters...

http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/MultiValueMap.html

Pablojim
  • 8,542
  • 8
  • 45
  • 69
0

If you have a more complex example you might use the following:

# pairs of properties
source1=foo
target1=bar
source2=anotherFoo
target2=regardingBar
source3= ...

In your code you will have to search:

Map<String, String> myMap = new HashMap<>();
for (int i=1; i<max; i++) {
  String source = properties.get("source" + i);
  String target = properties.get("target" + i);
  if (source == null || target == null) {
    break;
  }
  myMap.put(source, target);
}

Drawback: updating the properties file. If you remove values *2, all the following values will not be added. To improve you might want to replace the break with a continue and stick to a maximum of allowed pairs.

Clerenz
  • 821
  • 8
  • 23
  • 1
    instead of aborting on a missing key, you could iterate over all keys starting with "source". for (Entry prop : properies.entrySet()) { if (prop.getKey().startsWith("source")) { do something } – Chris Oct 14 '18 at 10:47