Как сортировать свойства в java?
У меня есть переменная Properties, и иногда мне нужно добавить к ней другие свойства.
Properties myBasicProps = this.getClass.getResourceAsStream(MY_PROPS_PATH);
...
Properties otherProps = new Properties();
otherProps.load(new StringReader(tempPropsString)); //tempPropsString contains my temporary properties
myBasicProps.putAll(otherProps);
Я хочу отсортировать myBasicProps
после этого. Я не хочу получать все ключи и значения, сортировать их с помощью Collections.sort()
, а затем переносить все на новый объект. Есть ли лучший способ?
Ответы
Ответ 1
Нет, java.util.Properties
extends java.util.Hashtable
, который не определяет предсказуемый порядок сортировки для ключей или значений.
Вы можете попробовать сбросить все значения во что-то вроде java.util.TreeMap
, что наложит естественный порядок на ваши ключи.
Ответ 2
все, что вам нужно сделать, это создать класс, который расширяет свойства. источник: java2s.com
import java.io.FileOutputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
public class Main{
public static void main(String[] args) throws Exception {
SortedProperties sp = new SortedProperties();
sp.put("B", "value B");
sp.put("C", "value C");
sp.put("A", "value A");
sp.put("D", "value D");
FileOutputStream fos = new FileOutputStream("sp.props");
sp.store(fos, "sorted props");
}
}
class SortedProperties extends Properties {
public Enumeration keys() {
Enumeration keysEnum = super.keys();
Vector<String> keyList = new Vector<String>();
while(keysEnum.hasMoreElements()){
keyList.add((String)keysEnum.nextElement());
}
Collections.sort(keyList);
return keyList.elements();
}
}
он работает для меня.
Ответ 3
Переопределение keys
хорошо работает с Java 8, но с Java 9 новая реализация store
методов больше не вызывает keys
метода, а метод entrySet
.
Таким образом, вы должны переопределить entrySet
чтобы ваши Properties
отсортированы с Java 8/9/10 при сохранении.
Вот пример с встроенным переопределением:
Properties properties = new Properties() {
private static final long serialVersionUID = 1L;
@Override
public Set<Object> keySet() {
return Collections.unmodifiableSet(new TreeSet<Object>(super.keySet()));
}
@Override
public Set<Map.Entry<Object, Object>> entrySet() {
Set<Map.Entry<Object, Object>> set1 = super.entrySet();
Set<Map.Entry<Object, Object>> set2 = new LinkedHashSet<Map.Entry<Object, Object>>(set1.size());
Iterator<Map.Entry<Object, Object>> iterator = set1.stream().sorted(new Comparator<Map.Entry<Object, Object>>() {
@Override
public int compare(java.util.Map.Entry<Object, Object> o1, java.util.Map.Entry<Object, Object> o2) {
return o1.getKey().toString().compareTo(o2.getKey().toString());
}
}).iterator();
while (iterator.hasNext())
set2.add(iterator.next());
return set2;
}
@Override
public synchronized Enumeration<Object> keys() {
return Collections.enumeration(new TreeSet<Object>(super.keySet()));
}
};
Ответ 4
@danisupr4 имеет лучшее решение.
Я бы немного улучшил его, чтобы вы не получали никаких предупреждений в своей среде IDE:
public static class MyProperties extends Properties {
private static final long serialVersionUID = 1L;
public Enumeration<Object> keys() {
Enumeration<Object> keysEnum = super.keys();
Vector<Object> keyList = new Vector<Object>();
while (keysEnum.hasMoreElements()) {
keyList.add(keysEnum.nextElement());
}
Collections.sort(keyList, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return o1.toString().compareTo(o2.toString());
}
});
return keyList.elements();
}
}
Ответ 5
TreeMap должен быть самым простым способом:
Properties myProps = this.getClass.getResourceAsStream(MY_PROPS_PATH);
try {
myProps.load(new FileInputStream(extraPropertiesFilename));
//you can load more properties from external file
Map<String, String> sortedMap = new TreeMap(myProps);
//output sorted properties (key=value)
for (String key : sortedMap.keySet()) {
System.out.println(key + "=" + sortedMap.get(key));
}
} catch (Exception e) {
e.printStackTrace();
}
Ответ 6
гораздо проще просто отсортировать ключи:
List<String> keys = new ArrayList<String>()
for(String key : properties.stringPropertyNames()) {
keys.add(key)
}
Collections.sort(keys);
Ответ 7
Решение работает также для Java> 8
Несмотря на то, что в этом вопросе явно не упоминается о функциональности store(OutputStream out, String comments)
, я считаю, что это (и load(InputStream inStream)
соответственно) является наиболее интересной частью Properties
.
Если бы мы не были заинтересованы в сохранении/загрузке свойств, мы могли бы просто заменить Properties
на некоторую реализацию Map
или SortedMap
.
Отличие в Properties
по сравнению с Map
заключается в существовании методов store()
/load()
, которые предлагают некоторые специальные правила сериализации. Эти правила не изменились (и не будут) в разных версиях Java. например
- Хранение пар, таких как
prop=value
- Экранирование правил для юникода и специальных символов.
- Добавление необязательного комментария сверху
К сожалению, вышеупомянутые 3 части функциональности скрыты внутри частных методов, и не может быть легко повторно использован внутри расширенных или альтернативных реализаций, которые хотят использовать различные внутренние структуры данных (например, для сохранения отсортированных свойств). Поэтому остается сохранить те же внутренние структуры и переопределить два метода store()
.
Примечание: для получения отсортированных свойств, некоторое время назад я следовал реализации danisupr4, но на java9 это сломалось.
TL; DR
Приведенный ниже код поддерживает полную функциональность Properties
, переопределяя только метод store(OutputStream out, String comments)
, и тестируется со всеми версиями из java5
- java12
.
Я считаю, что фильтрация выходных данных этого открытого метода делает реализацию менее хрупкой для будущих изменений кода в классе java.util.Properties
.
class SortedStoreProperties extends Properties {
@Override
public void store(OutputStream out, String comments) throws IOException {
Properties sortedProps = new Properties() {
@Override
public Set<Map.Entry<Object, Object>> entrySet() {
/*
* Using comparator to avoid the following exception on jdk >=9:
* java.lang.ClassCastException: java.base/java.util.concurrent.ConcurrentHashMap$MapEntry cannot be cast to java.base/java.lang.Comparable
*/
Set<Map.Entry<Object, Object>> sortedSet = new TreeSet<Map.Entry<Object, Object>>(new Comparator<Map.Entry<Object, Object>>() {
@Override
public int compare(Map.Entry<Object, Object> o1, Map.Entry<Object, Object> o2) {
return o1.getKey().toString().compareTo(o2.getKey().toString());
}
}
);
sortedSet.addAll(super.entrySet());
return sortedSet;
}
@Override
public Set<Object> keySet() {
return new TreeSet<Object>(super.keySet());
}
@Override
public synchronized Enumeration<Object> keys() {
return Collections.enumeration(new TreeSet<Object>(super.keySet()));
}
};
sortedProps.putAll(this);
sortedProps.store(out, comments);
}
}
Примечание. В зависимости от того, кто вызывает store()
, может быть даже лучше не переопределять существующий метод, но создать новый: storeSorted()
.
Кроме того, для простоты я переопределяю только один из методов store()
, но та же концепция
относится к обоим.
Ответ 8
Я сделал, переопределив метод хранения, например:
@Override
public void store(Writer writer, String comments) throws IOException {
this.keySet().stream().map(k -> (String)k).sorted().forEach(k -> {
try {
writer.append(String.format("%s=%s\n", k, get(k)));
} catch (IOException e) {
e.printStackTrace();
}
});
}
Предыдущие ответы мне не подходят.
Ответ 9
вы можете переопределить метод keys() для сохранения отсортированных свойств в txt файле:
//this method downloaded from edu.umd.cs.findbugs.config package
@SuppressWarnings("unchecked")
@Override
public synchronized Enumeration<Object> keys() {
Set<?> set = keySet();
return (Enumeration<Object>) sortKeys((Set<String>) set);
}
static public Enumeration<?> sortKeys(Set<String> keySet) {
List<String> sortedList = new ArrayList<String>();
sortedList.addAll(keySet);
Collections.sort(sortedList);
return Collections.enumeration(sortedList);
}
и переопределить метод stringPropertyNames() для сохранения отсортированных свойств в файле xml:
@Override
public Set<String> stringPropertyNames() {
Set<String> tmpSet = new TreeSet<String>();
for (Object key : keySet())
{
tmpSet.add(key.toString());
}
return tmpSet;
}