"値が入力されている"の判定
“値が入力されている”ということを調べるのに、
if (s != null && !s.equals("")) { ‥ }
とか、
if (s != null && s.length() > 0) { ‥ }
という判定条件を書くことはよくあると思う。
if (!"".equals(s)) { ‥ }
というのもあるかな。
ここで“値が入力されている”というとき、“その値とは1文字以上の文字列である”という暗黙の了解があるという前提の下で上記のようなコードが生まれてくる。
仕事で人が書いたコードを見るときによく見かけるのは一番最初のケース。三番目のケースも時々見かける。一方、私自身は、特にどういうポリシーがあって、ということではないが二番目のケースを使用する。
また例によって(謎)計ってみるが、その結果は抜きにして、なぜ二番目のケースを使うのかを考えてみた。
一番目は「なんとなく違うな」と感じる。知りたいのは“1文字以上の文字列であるかどうか”なので、特定の文字列との比較を持ち出すのは「違う」かな、と。
三番目は論外。一時期、nullチェックをしなくていいということから自分の中で流行ったことがあるが、ここでの条件判定の主体は変数sなので、三番目のように書いてあると思考が一瞬停止している自分に気づくことがある。“慣れ”だと言われたらそうかもしれないけど‥
で、計ってみる。今回はよほどの回数ループを回さないと差が出ないだろうな、という読みで‥
import java.text.DecimalFormat; import java.text.NumberFormat; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class TestValueCheck { private static NumberFormat nf = new DecimalFormat("0.000"); private static String s = "abc"; private static int loopCount = 10000; private long start; private long end; private String name; @BeforeClass public static void setUpBeforeClass() throws Exception { } @AfterClass public static void tearDownAfterClass() throws Exception { } @Before public void setUp() throws Exception { start = System.currentTimeMillis(); } @After public void tearDown() throws Exception { end = System.currentTimeMillis(); System.out.printf("%-16s %7s %24s\n", name, loopCount, nf.format((end - start) / 1000.0) + " sec"); } @Test public void testLength() { name = "length"; for (int i = 0; i < loopCount; ++i) { for (int j = 0; j < loopCount; ++j) { if (s != null && s.length() > 0) { } } } } @Test public void testEquals() { name = "equals"; for (int i = 0; i < loopCount; ++i) { for (int j = 0; j < loopCount; ++j) { if (s != null && !s.equals("")) { } } } } @Test public void testEquals2() { name = "equals(2)"; for (int i = 0; i < loopCount; ++i) { for (int j = 0; j < loopCount; ++j) { if (!"".equals(s)) { } } } } }
「指定したループ回数の二乗」回だけ条件判定を行うのにかかる時間を測定。
で、結果。
length 10000 0.607 sec equals 10000 2.113 sec equals(2) 10000 1.962 sec
String#length()を使ったほうが3倍早いという結果に。まぁ、1億回もループして1.3〜1.5秒の差なので‥‥