1

我有一个带有字符串作为参数的方法,它用方法中的字符串替换特定的占位符:

public static String format(String in)
{
    in=in.replace("[time]",getTime()); //just some methods returning strings
    in=in.replace("[name]",getName());
}

我的问题是,即使字符串“[time]”没有出现在字符串中,每次调用 format(String) 时都会调用方法 getTime() 和 getName()。由于我调用了数百次 format(String),因此解析所有字符串需要一分钟。由于 getTime() 和 getName() 需要很长时间才能执行,并且子字符串“[time]”和“[name]”很少见,如果替换方法只调用 getTime() 或 getName() 会快得多是占位符。我看到的最快的解决方案是将 string.replace() 重写为 replace(String)。现在我的两个问题是:

  1. 有没有更快的方法来做到这一点?
  2. 哪个是编写替换(字符串)的最快方法?
4

3 回答 3

1

如果在字符串中搜索比调用getTime()and花费的时间更少getName(),那么contains首先使用。

if (in.contains("[time]"))
{
    in=in.replace("[time]",getTime());
}

然后你只getTime()在需要时才打电话。对getName().

或者,如果getTime()并且getName()总是返回相同的结果,则只调用它们一次并存储它们的结果以供以后使用。

于 2013-03-14T21:27:51.457 回答
1

从逻辑上讲,replace 必须在替换之前先搜索字符串,因此在字符串不出现的情况下,它相当于调用 contains,因为 contains 只是进行搜索。所以先搜索不会加快速度。

听起来代码可能对相同的源字符串进行了多次重复搜索。如果是这样,那么答案可能是停止这样做。您可能希望先扫描所有内容,存储替换的结果,然后在必要时检索这些结果。

于 2013-03-14T21:35:08.190 回答
0

性能测试是确定什么是最快的。

一个小代码来测试三种不同的方法来编写这个......

import java.io.IOException;
import java.util.Properties;
import java.util.Vector;


public class BenchmarkStringStuff {


    public static void main(String[] args) {
        try {
            System.getProperties().store(System.out, "");
        } catch (IOException ioe ) {
            System.out.println("Failed to write properties to STDOUT");
            return;
        }


        BenchmarkStringStuff bss = new BenchmarkStringStuff();
        bss.benchmark(10);
        bss.benchmark(1000);
        bss.benchmark(100000);
        bss.benchmark(1000000);
    }

    public void benchmark(int numTests) 
    {
        Vector<Test> tests = new Vector<Test>();
        tests.add(new OriginalCode());
        tests.add(new TwoSearches());
        tests.add(new SearchOnceAndSubstring());


        Vector<String> testStrings = new Vector<String>();
        // we have a very poor sample, here.  You should test with a better 
        // representation of your expected values
        testStrings.add("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[time]aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

        Performance overallRuntime = new Performance("overall combined runtime");
        overallRuntime.setCount(numTests * testStrings.size() * tests.size());
        overallRuntime.start();
        for( Test test : tests )
        {
            Performance codePerformance = new Performance(test.getClass().getName());
            codePerformance.setCount(numTests * testStrings.size());
            codePerformance.start();
            for(String testString : testStrings)
            {
                //Performance stringPerformance = new Performance(testString);
                //stringPerformance.setCount(numTests);
                //stringPerformance.start();
                for(int i=0; i<numTests; i++)
                {
                    test.test(testString);
                }
                //stringPerformance.end();
                //System.out.println(stringPerformance.toString());
            }
            codePerformance.end();
            System.out.println(codePerformance.toString());
        }
        overallRuntime.end();
        System.out.println(overallRuntime.toString());
        System.out.println();

    }

    private static String getTime()
    { 
        return "a date"; 
        // static value to avoid any caching behavior - we
        // want to test the algorithm, not the external stuff.
        // you should use your real getTime method to see real numbers
        // for your application
    }

    private static String getName(){ return "a name"; }


    private interface Test {
        public String test(String in);
    }

    public class OriginalCode implements Test {

        public String test(String in)
        {
            in=in.replace("[time]",getTime()); //just some methods returning strings
            in=in.replace("[name]",getName());
            return in;
        }
    }

    public class TwoSearches implements Test {
        public String test(String in)
        {
            if (in.contains("[time]"))
            {
                in=in.replace("[time]",getTime());
            }
            return in;
        }
    }

    public class SearchOnceAndSubstring implements Test {
        public String test(String in)
        {
            String REPLACEME = "[time]";
            int idx = in.indexOf(REPLACEME);
            if( idx == 0 )
            {
                in=getTime() + in.substring(REPLACEME.length());
            }
            else if( idx > 0 )
            {
                in = in.substring(0,idx) + getTime();
                if( idx+REPLACEME.length() < in.length())
                {
                    in += in.substring(idx+REPLACEME.length());
                }
            }
            return in;
        }
    }





    private class Performance
    {
        long start = 0;
        long end = 0;
        String name = null;
        public int count = 0;

        public Performance(String name)
        {
            this.name = name;
        }

        public void start(){ start = System.currentTimeMillis(); }
        public void end() { end   = System.currentTimeMillis(); }
        public void setCount(int count){ this.count = count; } 

        /** be sure to call start & stop first **/
        public long total(){ return end - start; }


        public String toString()
        {
            return count + "cycles    start:"+start+"     end:"+end+"    total:"+total() + "   <---- " + name;
        }
    }
}

以及运行此代码的结果(已编辑与性能无关的内容)......

#
#Thu Mar 14 18:45:37 EDT 2013
java.runtime.name=Java(TM) SE Runtime Environment
java.vm.version=20.5-b03
java.vm.vendor=Sun Microsystems Inc.
java.vendor.url=http\://java.sun.com/
java.vm.name=Java HotSpot(TM) Client VM
sun.java.launcher=SUN_STANDARD
sun.os.patch.level=Service Pack 1
java.vm.specification.name=Java Virtual Machine Specification
java.runtime.version=1.6.0_30-b12
os.arch=x86
java.vm.specification.vendor=Sun Microsystems Inc.
user.variant=
os.name=Windows 7
java.specification.name=Java Platform API Specification
java.class.version=50.0
sun.management.compiler=HotSpot Client Compiler
os.version=6.1
java.specification.version=1.6
java.class.path=REDACTED
java.vm.specification.version=1.0
sun.java.command=BenchmarkStringStuff
sun.arch.data.model=32
java.specification.vendor=Sun Microsystems Inc.
java.version=1.6.0_30
java.vendor=Sun Microsystems Inc.
sun.desktop=windows
sun.cpu.isalist=pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86
10cycles    start:1363301137531     end:1363301137531    total:0   <---- BenchmarkStringStuff$OriginalCode
10cycles    start:1363301137531     end:1363301137531    total:0   <---- BenchmarkStringStuff$TwoSearches
10cycles    start:1363301137531     end:1363301137531    total:0   <---- BenchmarkStringStuff$SearchOnceAndSubstring
30cycles    start:1363301137531     end:1363301137531    total:0   <---- overall combined runtime

1000cycles    start:1363301137531     end:1363301137546    total:15   <---- BenchmarkStringStuff$OriginalCode
1000cycles    start:1363301137546     end:1363301137546    total:0   <---- BenchmarkStringStuff$TwoSearches
1000cycles    start:1363301137546     end:1363301137562    total:16   <---- BenchmarkStringStuff$SearchOnceAndSubstring
3000cycles    start:1363301137531     end:1363301137562    total:31   <---- overall combined runtime

100000cycles    start:1363301137562     end:1363301138108    total:546   <---- BenchmarkStringStuff$OriginalCode
100000cycles    start:1363301138108     end:1363301138451    total:343   <---- BenchmarkStringStuff$TwoSearches
100000cycles    start:1363301138451     end:1363301138499    total:48   <---- BenchmarkStringStuff$SearchOnceAndSubstring
300000cycles    start:1363301137562     end:1363301138499    total:937   <---- overall combined runtime

1000000cycles    start:1363301138499     end:1363301143663    total:5164   <---- BenchmarkStringStuff$OriginalCode
1000000cycles    start:1363301143663     end:1363301146784    total:3121   <---- BenchmarkStringStuff$TwoSearches
1000000cycles    start:1363301146784     end:1363301147190    total:406   <---- BenchmarkStringStuff$SearchOnceAndSubstring
3000000cycles    start:1363301138499     end:1363301147190    total:8691   <---- overall combined runtime

获胜者是 SearchOnceAndSubstring,其速度始终比其他人快。

通过直接使用 char 数组可能还有其他优化,但我怀疑 SearchOnceAndSubstring 会非常接近,大部分时间都丢失在字符串连接上。我将把性能测试留给读者作为练习。

于 2013-03-14T22:59:42.960 回答