Java性能:关于使用Long.valueOf(..)

时间:2015-09-16 10:29:24

标签: java performance casting

我们经常使用 Long.valueOf()进行同一场投射。这样就可以了,或者我们需要在其他字段中存储已转换的值然后使用。 例: 我们在String中收到特定的id,无论我们在哪里使用,我们每次都会使用Long.valueOf(id)。

喜欢:

void methodName(String id) {
//some code
... = Long.valueOf(id);
....
....
callOtherMethod(Long.valueOf(id));
....
...
map.put("urId", Long.valueOf(id));
....
}

当我们考虑性能和所有这些时,这是可以的。其他

这个很好去

喜欢:

void methodName(String id) {
//some code
Long longId = Long.valueOf(id);
... = longId;
....
....
callOtherMethod(longId);
....
...
map.put("urId", longId);
....
}

哪一个最好,为什么(如果你能解释)?

2 个答案:

答案 0 :(得分:2)

我个人赞成不多次重复相同的操作。所以我更喜欢你的第二种方法。

编程时,多次写入的同一段代码往往是难闻的气味,如果你可以提取重复的代码片段以便重复使用,比如将重复的块提取到参数化方法,或者在这种情况下分配输出Long.valueOf(id)对变量,您可以避免使用难以阅读的冗长代码。

答案 1 :(得分:0)

如果从Long.valueOf()(或任何其他方法)返回的值应该多次使用,那么使用第二种方法总是更好。因为它的alsmot总是在本地存储它比再次计算它更便宜。

对于相关示例,使用JMH计算性能差异并不难。我创建了可以计算出来的小基准:

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5)
@Measurement(iterations = 10)
@Fork(1)
@State(Scope.Thread)
public class ValueOfPerfTest {

    @Param({ "1000" })
    private String number;

    @Param({ "10", "20", "30"})
    private long tokens;

    @Benchmark
    public void cachedValueOf(Blackhole blackhole) {
        Long l = Long.valueOf(number);

        // three times using the consume
        blackhole.consume(l);
        blackhole.consume(l);
        blackhole.consume(l);

        Blackhole.consumeCPU(tokens);
    }

    @Benchmark
    public void nonCachedValueOf(Blackhole blackhole) {
        // three times using the consume
        blackhole.consume(Long.valueOf(number));
        blackhole.consume(Long.valueOf(number));
        blackhole.consume(Long.valueOf(number));

        Blackhole.consumeCPU(tokens);
    }

    @Benchmark
    public Long valueOf(Blackhole blackhole) {
        Blackhole.consumeCPU(tokens);

        return Long.valueOf(number);
    }

    @Benchmark
    public void baseline(){
        Blackhole.consumeCPU(tokens);
    }

}

我不想在这里找到JMH的具体内容,但主要区别在于nonCachedValueOf调用Long.valueOf()的3倍,相比之下,缓存版本只有一次。我的期望是非缓存版本会慢3倍,这基本上是结果显示:

 [java] Benchmark                                   (number)  (tokens)  Mode  Samples    Score   Error  Units
 [java] i.n.a.p.ValueOfPerfTest.baseline                1000        10  avgt       10   11.238 ± 0.387  ns/op
 [java] i.n.a.p.ValueOfPerfTest.baseline                1000        20  avgt       10   30.392 ± 0.668  ns/op
 [java] i.n.a.p.ValueOfPerfTest.baseline                1000        30  avgt       10   50.217 ± 1.101  ns/op
 [java] i.n.a.p.ValueOfPerfTest.cachedValueOf           1000        10  avgt       10   37.368 ± 2.035  ns/op
 [java] i.n.a.p.ValueOfPerfTest.cachedValueOf           1000        20  avgt       10   54.614 ± 3.847  ns/op
 [java] i.n.a.p.ValueOfPerfTest.cachedValueOf           1000        30  avgt       10   74.412 ± 2.474  ns/op
 [java] i.n.a.p.ValueOfPerfTest.nonCachedValueOf        1000        10  avgt       10   82.329 ± 2.649  ns/op
 [java] i.n.a.p.ValueOfPerfTest.nonCachedValueOf        1000        20  avgt       10  100.595 ± 2.476  ns/op
 [java] i.n.a.p.ValueOfPerfTest.nonCachedValueOf        1000        30  avgt       10  118.715 ± 3.277  ns/op
 [java] i.n.a.p.ValueOfPerfTest.valueOf                 1000        10  avgt       10   35.815 ± 0.766  ns/op
 [java] i.n.a.p.ValueOfPerfTest.valueOf                 1000        20  avgt       10   53.074 ± 3.942  ns/op
 [java] i.n.a.p.ValueOfPerfTest.valueOf                 1000        30  avgt       10   73.378 ± 2.318  ns/op

如果你深入研究结果,如果你排除基线(这里有30个代币),你会得到大约以下的结果:

[java] i.n.a.p.ValueOfPerfTest.cachedValueOf       24,195 ns/op
[java] i.n.a.p.ValueOfPerfTest.nonCachedValueOf    68,498 ns/op
[java] i.n.a.p.ValueOfPerfTest.valueOf             23,161 ns/op

相当清楚几乎因素3。

关于每次使用Long.valueOf创建任何新对象的问题?,如果数字不在缓存中,答案是肯定的.java有&#34的缓存;经常使用的值"默认情况下,这是从-128到127的数字。但是可以通过使用-XX:AutoBoxCacheMax JVM选项来增加它。