Java 性能妄想症:Float.parseFloat(字符串)和Integer.parseInt(字符串)的价格是多少?

Java 性能妄想症:Float.parseFloat(字符串)和Integer.parseInt(字符串)的价格是多少?,java,performance,interface,types,casting,Java,Performance,Interface,Types,Casting,我最近使用JSON来存储同一类中一定数量的子类的配置参数。为了保持统一的接口,我为父类提供了publicvoid setParameter(String,String)和String getParameter(String)方法。然后,每个子类将提供的参数强制转换为其本机类型,并使用它们进行某种计算 现在,我想知道:既然我已经在HashMap中存储了每个参数,那么为每个参数保留一个具有正确类型的单独字段真的有意义吗?考虑到我需要经常使用字符串参数,每次需要时将其转换为本机类型的计算开销是多少 谢

我最近使用JSON来存储同一类中一定数量的子类的配置参数。为了保持统一的接口,我为父类提供了public
void setParameter(String,String)
String getParameter(String)
方法。然后,每个子类将提供的参数强制转换为其本机类型,并使用它们进行某种计算

现在,我想知道:既然我已经在HashMap中存储了每个参数,那么为每个参数保留一个具有正确类型的单独字段真的有意义吗?考虑到我需要经常使用字符串参数,每次需要时将其转换为本机类型的计算开销是多少

谢谢你

Tunnuz

我建议你测试一下。如果需要多次执行此操作,则此操作的成本相当高,但如果首先使用Double.toString()或Integer.toString()创建数据,则此操作的成本可能低于Double.toString()或Integer.toString()

我还建议您只使用
double
,除非您知道使用
float
永远不会引起舍入问题

这与创建对象(如字符串)或向HashMap添加条目一样昂贵。除非你打算避免这样做,否则我不会担心的

编辑:与@Stackers的基准测试类似,我将运行更长的测试时间并使用nanoTime()


顺便说一句:我有一个函数,从一个需要80纳秒的直接ByteBuffer读取双倍。它更快,因为它不需要字符串,也不创建任何对象。然而,这样做绝非小事,您必须设计您的核心系统以避免任何对象创建。;)

测量与以下一样简单:

public class PerfTest {
    public static void main(String[] args) {
        String val = "" + (float) Math.PI;
        long start = System.currentTimeMillis();
        for ( int i = 0 ; i < 100000 ; i++ ) {
            Float.parseFloat( val );
        }
        System.out.println( System.currentTimeMillis() - start + " ms." );
    }
}
公共类性能测试{
公共静态void main(字符串[]args){
字符串val=”“+(float)Math.PI;
长启动=System.currentTimeMillis();
对于(int i=0;i<100000;i++){
Float.parseFloat(val);
}
System.out.println(System.currentTimeMillis()-start+“ms.”;
}
}

62毫秒,用于100.000次迭代

fwiw上面的微基准点似乎有点不安全,您可能希望hotspot能够发现val从未改变&从未使用过。要记住的另一件事是,有时(2个实现的)平均值在绝对值上可能很接近,但其中1个与另一个相比具有非常糟糕的尾部成本,例如,您的第90个百分位值可能非常相似,但最后10%要差得多

例如,每次将其更改为使用不同的值并将该值转储到stderr会在我的设备上产生更高的平均成本(对于重复使用该值的情况,平均成本约为3300ns,而对于重复使用该值的情况,平均成本约为2500ns)。这比其他帖子要高得多,可能是因为实际获取时间需要一些时间,所以测量结果被人为夸大了。这只是展示了做好微基准的困难之一

也可能值得注意的是,我无法衡量我所建议的可能存在的效果,例如,如果它存在,那么您可能期望它得到完全优化。我想如果你真的感兴趣的话,你可以通过
LogCompilation
看到正在发生的事情

    int runs = 10000000;
    long totalTime = 0;
    for (int i = 0; i < runs; i++) {
        String val = "" + Math.random();
        long start = System.nanoTime();
        float f = Float.parseFloat(val);
        long end = System.nanoTime();
        System.err.println(f);
        totalTime += (end-start);
    }
    long time = totalTime / runs;
    totalTime = 0;
    for (int i = 0; i < runs; i++) {
        String val = "" + Math.random();
        long start = System.nanoTime();
        double d = Double.parseDouble(val);
        long end = System.nanoTime();
        System.err.println(d);
        totalTime += (end-start);
    }
    long time2 = totalTime / runs;
    System.out.println("Average Float.parseFloat() time was " + time + " ns.");
    System.out.println("Average Double.parseDouble() time was " + time2 + " ns.");
int runs=10000000;
长总时间=0;
for(int i=0;i
您也可以使用Float.valueOf()而不是Float.parseFloat(),这将稍微提高性能,因为它使用一个简单的缓存。@bvk256:Float.valueOf不做任何缓存。javadoc建议这样做,但如果您查看源代码(至少在sunjdk中),它不会这样做。这只是一个新的例子。整数类型上的方法的值可以,但浮点类型不可以。+1:我会运行更长的测试,例如至少多秒,使用nanoTime()并打印平均时间。并且在开始实际测量之前进行一次干运行,以便不测量任何JIT开销。编辑:…将基准放在单独的函数中(使用@PeterLawrey的nanoTime()建议&1000万次迭代)并调用两次,第一次运行的速度始终比我在速度较慢的x86上网本上的第二次运行慢(~20%)。@pauluss86原因可能是虚拟机(JIT)执行的优化@stacker感谢您的回复,但没有考虑到这种可能性。尽管如此,最终结果仍然是一样的:多次执行测试以更好地了解真实世界的性能。
public class PerfTest {
    public static void main(String[] args) {
        String val = "" + (float) Math.PI;
        long start = System.currentTimeMillis();
        for ( int i = 0 ; i < 100000 ; i++ ) {
            Float.parseFloat( val );
        }
        System.out.println( System.currentTimeMillis() - start + " ms." );
    }
}
    int runs = 10000000;
    long totalTime = 0;
    for (int i = 0; i < runs; i++) {
        String val = "" + Math.random();
        long start = System.nanoTime();
        float f = Float.parseFloat(val);
        long end = System.nanoTime();
        System.err.println(f);
        totalTime += (end-start);
    }
    long time = totalTime / runs;
    totalTime = 0;
    for (int i = 0; i < runs; i++) {
        String val = "" + Math.random();
        long start = System.nanoTime();
        double d = Double.parseDouble(val);
        long end = System.nanoTime();
        System.err.println(d);
        totalTime += (end-start);
    }
    long time2 = totalTime / runs;
    System.out.println("Average Float.parseFloat() time was " + time + " ns.");
    System.out.println("Average Double.parseDouble() time was " + time2 + " ns.");