简体   繁体   中英

Java8 String replaceAll changed behavior

I have this text = "$i $index" and this map:

Map<String, String> vars = new HashMap<String, String>();

        vars.put("i","index0");
        vars.put("index","counter0"); 

The goal is to replace all keys with the relative values.
In this test the regex used in the replaceAll method is a result of a concatenation

            firstTest();
            // first test results:
            // java 7: index0  counter0
            // java 8: index0  index0ndex

in this, the regex used in the replaceAll method is a complete string

            secondTest();
            // second test resuls:
            // java 7: index0  index0ndex
            // java 8: index0  index0ndex

In this last, i compare the Pattern.quote method with strings concatenated and the same strings complete

            thirdTest();
            // third test results:
            // java 7: first: \Q$index\E second: \Q$index\E are equals: true
            // java 8: first: \Q$index\E second: \Q$index\E are equals: true

First test code:

private static void firstTest() {
    Map<String, String> vars = new HashMap<String, String>();

    vars.put("i","index0");
    vars.put("index","counter0");

    String text = "$i  $index";

    for (Entry<String, String> var : vars.entrySet())
        text = text.replaceAll(Pattern.quote("$"+var.getKey()), var.getValue());

    System.out.println(text);
}

Second test code:

private static void secondTest() {
    Map<String, String> vars = new HashMap<String, String>();

    vars.put("$i","index0");
    vars.put("$index","counter0");

    String text = "$i  $index";

    for (Entry<String, String> var : vars.entrySet())
        text = text.replaceAll(Pattern.quote(var.getKey()), var.getValue());

    System.out.println(text);
}

Third test code:

private static void thirdTest() {
    Map<String, String> vars = new HashMap<String, String>();
    vars.put("index","counter0");

    String firstQuote = Pattern.quote("$"+vars.keySet().toArray()[0]);
    String secondQuote = Pattern.quote("$index");

    System.out.println("first: " + firstQuote + " second: " + secondQuote 
                     + " are equals: " + firstQuote.equals(secondQuote));

}

Can someone explain why I get such different results?

Variation in the output would be due to order of iteration.

while iterating over vars if you get $i first then in text string both $i and $i in $index gets replaced. in the second iteration nothing will get replaced as it didn't find any '$index' in the string.

If you can debug your code you can find the answer for that. To get the values in some sorted order use LinkedHashMap (kept in insertion order) or TreeMap, sortedMap (Custom order as designed by you)

java.util.HashMap is unordered; you can't and shouldn't assume anything beyond that.

This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.

java.util.LinkedHashMap uses insertion-order.

This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).

java.util.TreeMap, a SortedMap, uses either natural or custom ordering of the keys.

The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM