如何在java中对属性进行排序?

shi*_*t66 21 java sorting properties

我有一个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);
Run Code Online (Sandbox Code Playgroud)

我想myBasicProps在此之后排序.我不想获取所有键和值,对它们进行排序Collections.sort(),然后将它们全部放到一个新对象上.有没有更好的办法?

har*_*rto 21

不,java.util.Properties扩展java.util.Hashtable没有为键或值定义可预测的排序顺序.

你可以尝试将所有值转储成类似的东西java.util.TreeMap,这将对你的密钥强加一个自然的顺序.


dan*_*pr4 20

你所要做的就是创建扩展属性的类.来源: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();
  }

}
Run Code Online (Sandbox Code Playgroud)

这个对我有用.

  • Java 8版本:ArrayList <Object> result = Collections.list(super.keys()); Collections.sort(result,(a,b) - > a.toString().compareTo(b.toString())); return Collections.enumeration(result); (3认同)
  • 这不适用于`java&gt; = 9`。例如,当使用“ BB”,“ CC”,“ AA”,“ DD”作为键时。请参阅下面的[post](/sf/answers/3917014111/)。 (2认同)

smi*_*n62 8

覆盖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()));
        }
    };
Run Code Online (Sandbox Code Playgroud)


小智 6

@ 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();
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

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();
}
Run Code Online (Sandbox Code Playgroud)


Mar*_* An 6

解决方案也适用于 java > 8

尽管该问题没有明确提及store(OutputStream out, String comments)功能,但我发现这(和load(InputStream inStream)分别)是Properties.

如果我们对存储/加载属性不感兴趣,我们可以Properties用一些MapSortedMap实现替换。

Properties与 相比的不同之处在于提供一些特定序列化规则Mapstore()/load()方法的存在 。这些规则没有(也不会)在 Java 版本之间改变。例如

  • 存储对像 prop=value
  • Unicode 和特殊字符的转义规则。
  • 在顶部添加可选注释

不幸的是,功能的上述 3 部分隐藏在私有方法中,并且不能在希望使用不同内部数据结构(例如保持属性排序)的扩展或替代实现中轻松重用

所以剩下的就是保持相同的内部结构并覆盖这两个store()方法

注意:为了获得排序的属性,前段时间我遵循了danisupr4实现,但在java9 上它坏了。

TL; 博士

下面的代码保存完整功能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);
        }
    }

Run Code Online (Sandbox Code Playgroud)

注意:根据谁调用store(),最好不要覆盖现有方法而是创建一个新方法:例如storeSorted()
此外,为了简单起见,我只覆盖了其中一种store()方法,但相同的概念适用于这两种方法。