有没有更好的方法来遍历java中的字符串?

时间:2013-07-18 22:12:05

标签: java string coding-style

请耐心等待。我在一年多的时间里没有编程,而且我正在通过做“家庭作业问题”来审查我的Java面试。我的函数应该返回一个包含给定字符串中每个第二个字符的字符串。是否有一种不那么尴尬的方法呢?

public String stringBits(String str) {
  StringBuffer tmp = new StringBuffer();
  for(int i = 0; i<str.length(); i+=2)
    tmp.append(str.charAt(i));
  String ret = new String(tmp);
  return ret;

7 个答案:

答案 0 :(得分:3)

我会使用StringBuilder,而不是StringBufferStringBuffer用于多线程情况,因此比StringBuilder慢,因为它不同步。我测试了这个线程中各种答案列出的四种基本方法。 但请注意,我总是在这里做的某些事情;这些应该是你的面试官真正想要的东西:

  • 我从不使用String += nextCharacter;,因为它比使用StringBuilder慢得多。
  • 我设置initialCapacity因为这样做总是更快。如果不这样做,如果StringBuilder已满,则必须重新分配新阵列并复制,这很慢。

代码:

import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;

import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Random;

public class EveryOtherTest {
    public static class StringBenchmark extends SimpleBenchmark {
        private String input;

        protected void setUp() {
            Random r = new Random();
            int length = r.nextInt(1000) + 1000;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length; i++) {
                sb.append((char) ('A' + r.nextInt(26)));
            }
            input = sb.toString();
        }

        public String timeCharArrayForeach(int reps) {
            String output = "";
            Random r = new Random();
            for (int i = 0; i < reps; i++) {
                StringBuilder sb = new StringBuilder(input.length() / 2 + 1);
                boolean use = false;
                for (char c : input.toCharArray()) {
                    if(use) sb.append(c);
                    use = !use;
                }
                String newOutput = sb.toString();
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }

        public String timeCharArrayPlusTwo(int reps) {
            String output = "";
            Random r = new Random();
            for (int i = 0; i < reps; i++) {
                StringBuilder sb = new StringBuilder(input.length() / 2 + 1);
                char[] charArray = input.toCharArray();
                for(int j = 0; j < input.length(); j += 2) {
                    sb.append(charArray[j]);
                }
                String newOutput = sb.toString();
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }

        public String timeCharAt(int reps) {
            String output = "";
            Random r = new Random();
            for (int i = 0; i < reps; i++) {
                StringBuilder tmp = new StringBuilder(input.length() / 2 + 1);
                for (int j = 0; j < input.length(); j += 2) {
                    tmp.append(input.charAt(j));
                }
                String newOutput = tmp.toString();
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }

        public String timeIterator(int reps) {
            String output = "";
            Random r  = new Random();
            for(int i = 0; i < reps; i++) {
                StringBuilder buf = new StringBuilder(input.length() / 2 + 1);
                StringCharacterIterator iterator = new StringCharacterIterator(input);
                for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
                    buf.append(c);
                    iterator.next();
                }
                String newOutput = buf.toString();
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }

        public String timeRegex(int reps) {
            String output = "";
            Random r  = new Random();
            for(int i = 0; i < reps; i++) {
                String newOutput = input.replaceAll("(?<!^).(.)", "$1");
                if (r.nextBoolean()) output = newOutput; // Trick the JIT
            }

            return output;
        }
    }

    public static void main(String... args) {
        Runner.main(StringBenchmark.class, args);
    }
}

结果:

 0% Scenario{vm=java, trial=0, benchmark=CharArrayForeach} 2805.55 ns; ?=688.96 ns @ 10 trials
20% Scenario{vm=java, trial=0, benchmark=CharArrayPlusTwo} 3428.48 ns; ?=475.32 ns @ 10 trials
40% Scenario{vm=java, trial=0, benchmark=CharAt} 2138.68 ns; ?=379.44 ns @ 10 trials
60% Scenario{vm=java, trial=0, benchmark=Iterator} 3963.94 ns; ?=389.53 ns @ 10 trials
80% Scenario{vm=java, trial=0, benchmark=Regex} 58743.66 ns; ?=10850.33 ns @ 10 trials

       benchmark    us linear runtime
CharArrayForeach  2.81 =
CharArrayPlusTwo  3.43 =
          CharAt  2.14 =
        Iterator  3.96 ==
           Regex 58.74 ==============================

vm: java
trial: 0

答案 1 :(得分:2)

如果您更喜欢迭代器方法,则有一个StringCharacterIterator类。

答案 2 :(得分:1)

您可以使用此正则表达式等效

String newString = str.replaceAll("(?<!^).(.)", "$1");

答案 3 :(得分:0)

没有。这根本不尴尬。对于每个有用的任务,可能有更合适的方法,但在这种情况下,你别无选择,只能迭代字符串。

答案 4 :(得分:0)

我相信这也应该有效,对我来说看起来更简单。

public String stringBits(String str) {
    String tmp = "";
    for(int i = 0; i<str.length(); i+=2)
        tmp+=str.charAt(i);
    return tmp;

我编辑说如果你想要第二个,第四个,六个......字符,我应该等于1。

答案 5 :(得分:0)

您可以将字符串转换为CharArray并使用for-each循环:

for (char c: str.toCharArray()){
}

当然,你可能需要一个计数器或一个标志来获得其他所有角色,所以它可能不会那么尴尬。

答案 6 :(得分:0)

据我所知,你正在做什么。这是一个简单的测试用例:

package com.sandbox;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class SandboxTest {

    @Test
    public void testMocking() {
        assertEquals("foo", stringBits("f1o2o3"));
    }

    public String stringBits(String str) {
        StringBuffer tmp = new StringBuffer();
        for (int i = 0; i < str.length(); i += 2) {
            tmp.append(str.charAt(i));
        }
        String ret = new String(tmp);
        return ret;
    }
}

我认为这是一种非常直接的方式。使用正则表达式和组可能有一种方法,但我感觉您当前的代码更容易阅读。


在我看到@Joey的答案之前,我从未听说过StringCharacterIterator,但它看起来像是一个有趣的解决方案。这是使用他的答案的代码:

package com.sandbox;

import org.junit.Test;

import java.text.CharacterIterator;
import java.text.StringCharacterIterator;

import static org.junit.Assert.assertEquals;

public class SandboxTest {

    @Test
    public void testMocking() {
        assertEquals("foo", stringBits("f1o2o3"));
    }

    public String stringBits(String str) {
        StringBuilder buf = new StringBuilder();
        StringCharacterIterator iterator = new StringCharacterIterator(str);
        for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
            buf.append(c);
            iterator.next();
        }
        return buf.toString();
    }
}