java.util.Base64でのencodeはapache commons codecより50倍以上速い

タイトルで言いたいことをほぼ言い切っているし、Base64かつJavaならよくある話なので、ググったらいくらでも出てくるのですが、2025年時点の最新でそれなりに自分で計測してみた。

というだけの話。

apache-commons以外も実験しろよ!!!とか、decodeもやれよ!などあると思いますが、ググったら(多少古いけど)もう少し色々やっているの出てくるし、あるいは皆さん自分で試しましょう。

以下実験したコードや条件と結果。

パラメーターあまり変えたりしてないけれど、一応ちゃんとjmhで計測しました。

10689097.969 / 200796.409 で53倍の差が出ました。

さすがによくある処理だからJVM側で特殊処理してるんでしょうね、おそらく(知らんけど)

とはいえ Array[Byte] のsize固定だったので、その部分など変えたら多少は違う結果になるのかもしれませんが。

これだけ速ければ全体的に速いだろう、と予想がつくし、わざわざ外部のライブラリ使う必要がほぼないですね。

Javaのversion

21でもあまり変わらなかった

$ java --version      
openjdk 25 2025-09-16 LTS
OpenJDK Runtime Environment Corretto-25.0.0.36.2 (build 25+36-LTS)
OpenJDK 64-Bit Server VM Corretto-25.0.0.36.2 (build 25+36-LTS, mixed mode, sharing)

sbtの引数

Jmh/run -i 5 -wi 5 -f1 -t1

Test.scala

package example

import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Setup
import org.openjdk.jmh.annotations.State
import org.openjdk.jmh.annotations.Scope

@State(Scope.Thread)
class Test {
  private var value: Array[Byte] = null

  @Setup
  def setup(): Unit = {
    value = scala.util.Random.nextBytes(1024)
  }

  @Benchmark
  def apache(): Array[Byte] = {
    org.apache.commons.codec.binary.Base64.encodeBase64(value)
  }

  @Benchmark
  def jdk(): Array[Byte] = {
    java.util.Base64.getEncoder.encode(value)
  }
}

build.sbt

scalaVersion := "3.7.3"

libraryDependencies += "commons-codec" % "commons-codec" % "1.19.0"

enablePlugins(JmhPlugin)

project/build.properties

sbt.version=1.11.7

project/plugins.sbt

addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.8")

終結

[info] Benchmark     Mode  Cnt         Score       Error  Units
[info] Test.apache  thrpt    5    200796.409 ± 10119.913  ops/s
[info] Test.jdk     thrpt    5  10689097.969 ± 93549.265  ops/s

途中結果詳細

[info] # Warmup Iteration   1: 201664.601 ops/s
[info] # Warmup Iteration   2: 201722.927 ops/s
[info] # Warmup Iteration   3: 201767.282 ops/s
[info] # Warmup Iteration   4: 202104.386 ops/s
[info] # Warmup Iteration   5: 201373.901 ops/s
[info] Iteration   1: 196124.613 ops/s
[info] Iteration   2: 201776.207 ops/s
[info] Iteration   3: 201588.184 ops/s
[info] Iteration   4: 202177.230 ops/s
[info] Iteration   5: 202315.809 ops/s
[info] Result "example.Test.apache":
[info]   200796.409 ±(99.9%) 10119.913 ops/s [Average]
[info]   (min, avg, max) = (196124.613, 200796.409, 202315.809), stdev = 2628.109
[info]   CI (99.9%): [190676.496, 210916.322] (assumes normal distribution)
[info] # Warmup Iteration   1: 10692549.602 ops/s
[info] # Warmup Iteration   2: 10788429.886 ops/s
[info] # Warmup Iteration   3: 10777627.856 ops/s
[info] # Warmup Iteration   4: 10666757.175 ops/s
[info] # Warmup Iteration   5: 10680488.416 ops/s
[info] Iteration   1: 10650964.876 ops/s
[info] Iteration   2: 10685445.893 ops/s
[info] Iteration   3: 10688619.287 ops/s
[info] Iteration   4: 10710409.356 ops/s
[info] Iteration   5: 10710050.434 ops/s
[info] Result "example.Test.jdk":
[info]   10689097.969 ±(99.9%) 93549.265 ops/s [Average]
[info]   (min, avg, max) = (10650964.876, 10689097.969, 10710409.356), stdev = 24294.447
[info]   CI (99.9%): [10595548.705, 10782647.234] (assumes normal distribution)