Why does this code use an oversized array instead of a Map?

Viewed 152

Here's JBoss JSTL implementation for the EscapeXML tag

public class EscapeXML {

    private static final String[] ESCAPES;

    static {
        int size = '>' + 1; // '>' is the largest escaped value
        ESCAPES = new String[size];
        ESCAPES['<'] = "&lt;";
        ESCAPES['>'] = "&gt;";
        ESCAPES['&'] = "&amp;";
        ESCAPES['\''] = "&#039;";
        ESCAPES['"'] = "&#034;";
    }
  //omitted
}

Why is ESCAPES a 61 elements array? What are the implication of using a Map<Character,String> instead?

1 Answers

I think the main reason is performance. Each map query needs to get the hashcode, and then calculate the position of the array in the map, and the array can be obtained directly. The following is a simple test, querying 10,000 times separately, the array is about 10 times faster than the map.

array query result: cost time= 184041
map query result: cost time= 1677042
import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author jahe
 * @date 2022/1/9
 * @note
 */
public class ArrayMapTest {
    private char[] chars = {'<', '>', '&', '\'', '"'};
    private char[] charsForQuery = new char[10000];
    @Before
    public void init(){
        Random random = new Random(5);
        random.nextInt(5);
        for (int i = 0; i < charsForQuery.length; i++) {
            charsForQuery[i] = chars[random.nextInt(5)];
        }
        System.out.println(Arrays.toString(charsForQuery));
    }
    @Test
    public void test() {
        int size = '>' + 1;
        String[] ESCAPES = new String[size];
        ESCAPES['<'] = "&lt;";
        ESCAPES['>'] = "&gt;";
        ESCAPES['&'] = "&amp;";
        ESCAPES['\''] = "&#039;";
        ESCAPES['"'] = "&#034;";
        long start = System.nanoTime();
        doTestForArray(ESCAPES);
        long end = System.nanoTime();
        System.out.println("array query result: cost time= " + (end - start));

        Map<Character, String> map = new HashMap<>();
        map.put('<', "&lt;");
        map.put('>', "&gt;");
        map.put('&', "&amp;");
        map.put('\'', "&#039;");
        map.put('"', "&#034;");
        start = System.nanoTime();
        doTestForMap(map);
        end = System.nanoTime();
        System.out.println("map query result: cost time= " + (end - start));

    }
    private void doTestForArray(String[] ESCAPES){
        for (char c : charsForQuery) {
            String str = ESCAPES[c];
        }
    }
    private void doTestForMap(Map<Character, String> map){
        for (char c : charsForQuery) {
            String s = map.get(c);
        }
    }
}
Related