What is the easiest/best/most correct way to iterate through the characters of a string in Java?

前端 未结 15 1204
挽巷
挽巷 2020-11-22 11:14

StringTokenizer? Convert the String to a char[] and iterate over that? Something else?

相关标签:
15条回答
  • 2020-11-22 11:41

    I agree that StringTokenizer is overkill here. Actually I tried out the suggestions above and took the time.

    My test was fairly simple: create a StringBuilder with about a million characters, convert it to a String, and traverse each of them with charAt() / after converting to a char array / with a CharacterIterator a thousand times (of course making sure to do something on the string so the compiler can't optimize away the whole loop :-) ).

    The result on my 2.6 GHz Powerbook (that's a mac :-) ) and JDK 1.5:

    • Test 1: charAt + String --> 3138msec
    • Test 2: String converted to array --> 9568msec
    • Test 3: StringBuilder charAt --> 3536msec
    • Test 4: CharacterIterator and String --> 12151msec

    As the results are significantly different, the most straightforward way also seems to be the fastest one. Interestingly, charAt() of a StringBuilder seems to be slightly slower than the one of String.

    BTW I suggest not to use CharacterIterator as I consider its abuse of the '\uFFFF' character as "end of iteration" a really awful hack. In big projects there's always two guys that use the same kind of hack for two different purposes and the code crashes really mysteriously.

    Here's one of the tests:

        int count = 1000;
        ...
    
        System.out.println("Test 1: charAt + String");
        long t = System.currentTimeMillis();
        int sum=0;
        for (int i=0; i<count; i++) {
            int len = str.length();
            for (int j=0; j<len; j++) {
                if (str.charAt(j) == 'b')
                    sum = sum + 1;
            }
        }
        t = System.currentTimeMillis()-t;
        System.out.println("result: "+ sum + " after " + t + "msec");
    
    0 讨论(0)
  • 2020-11-22 11:41

    I wouldn't use StringTokenizer as it is one of classes in the JDK that's legacy.

    The javadoc says:

    StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.

    0 讨论(0)
  • 2020-11-22 11:41

    If you need performance, then you must test on your environment. No other way.

    Here example code:

    int tmp = 0;
    String s = new String(new byte[64*1024]);
    {
        long st = System.nanoTime();
        for(int i = 0, n = s.length(); i < n; i++) {
            tmp += s.charAt(i);
        }
        st = System.nanoTime() - st;
        System.out.println("1 " + st);
    }
    
    {
        long st = System.nanoTime();
        char[] ch = s.toCharArray();
        for(int i = 0, n = ch.length; i < n; i++) {
            tmp += ch[i];
        }
        st = System.nanoTime() - st;
        System.out.println("2 " + st);
    }
    {
        long st = System.nanoTime();
        for(char c : s.toCharArray()) {
            tmp += c;
        }
        st = System.nanoTime() - st;
        System.out.println("3 " + st);
    }
    System.out.println("" + tmp);
    

    On Java online I get:

    1 10349420
    2 526130
    3 484200
    0
    

    On Android x86 API 17 I get:

    1 9122107
    2 13486911
    3 12700778
    0
    
    0 讨论(0)
  • 2020-11-22 11:42

    So typically there are two ways to iterate through string in java which has already been answered by multiple people here in this thread, just adding my version of it First is using

    String s = sc.next() // assuming scanner class is defined above
    for(int i=0; i<s.length; i++){
         s.charAt(i)   // This being the first way and is a constant time operation will hardly add any overhead
      }
    
    char[] str = new char[10];
    str = s.toCharArray() // this is another way of doing so and it takes O(n) amount of time for copying contents from your string class to character array
    

    If performance is at stake then I will recommend to use the first one in constant time, if it is not then going with the second one makes your work easier considering the immutability with string classes in java.

    0 讨论(0)
  • 2020-11-22 11:46

    If you have Guava on your classpath, the following is a pretty readable alternative. Guava even has a fairly sensible custom List implementation for this case, so this shouldn't be inefficient.

    for(char c : Lists.charactersOf(yourString)) {
        // Do whatever you want     
    }
    

    UPDATE: As @Alex noted, with Java 8 there's also CharSequence#chars to use. Even the type is IntStream, so it can be mapped to chars like:

    yourString.chars()
            .mapToObj(c -> Character.valueOf((char) c))
            .forEach(c -> System.out.println(c)); // Or whatever you want
    
    0 讨论(0)
  • 2020-11-22 11:46

    This Example Code will Help you out!

    import java.util.Comparator;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.TreeMap;
    
    public class Solution {
        public static void main(String[] args) {
            HashMap<String, Integer> map = new HashMap<String, Integer>();
            map.put("a", 10);
            map.put("b", 30);
            map.put("c", 50);
            map.put("d", 40);
            map.put("e", 20);
            System.out.println(map);
    
            Map sortedMap = sortByValue(map);
            System.out.println(sortedMap);
        }
    
        public static Map sortByValue(Map unsortedMap) {
            Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
            sortedMap.putAll(unsortedMap);
            return sortedMap;
        }
    
    }
    
    class ValueComparator implements Comparator {
        Map map;
    
        public ValueComparator(Map map) {
            this.map = map;
        }
    
        public int compare(Object keyA, Object keyB) {
            Comparable valueA = (Comparable) map.get(keyA);
            Comparable valueB = (Comparable) map.get(keyB);
            return valueB.compareTo(valueA);
        }
    }
    
    0 讨论(0)
提交回复
热议问题