Musashitokiwa.LLC Blog

武蔵常盤株式会社のブログです。

久しぶりのJavaについて

皆さん、こんにちは、こんばんわ。

His First Japan 合同会社 代表社員の字引淳です。

 

 f:id:a-j1b1k1:20180805211928p:plain

 

 

今日はAI以外の、本業のJavaについて書きます。

 

最近、Java Bronzeの勉強を見る機会があって、現場では絶対にゆるされないようなサンプルコードの数々に、SJCPの頃、私が、ドシロートから勉強をして資格を取っていたあの頃を思い出しました。

 

それで、とあるサンプルコードをみて、「なぜその結果になるか、わからない。」と言われたので、私も見たのですが、確かに、分からないんです。

 

コード①

interface  MyInter {

  public static final int VAL = 3;

  void foo(int s);

}

public class Test implements MyInter {

  public static void main(String args) {

    int x = 5;

    new Test().foo(++x);

  }

  public void foo(int s) {

    s += VAL + ++s;

    System.out.println("s:" + s);

  }

}

実際に実行して見ると、結果はS:16となります。

 

「あれっ?S:17じゃないの?」って、はずしてしまいます。

 

とりあえずは、まずはじめに、コードレビュー的に。

「あれ?こんな書き方したらいかんよ。処理は一目瞭然にしないと。バグの温床になるぜ。」と言う箇所。

 

  s += VAL + ++s;

 ※ s = VAL + ++s;これであれば問題はないんですよね。

 

普通に考えれば++sがインクリメントされた時点で値が変わっているものと思っていた。

 

 new Test().foo(++x);→x:6

public void foo(int s) {→s:6

s += VAL + ++s;

s:6  VAL:3  s:7→実際にはこう言う形で処理が行われる。

s:7  VAL:3  s:7→机上デバッグではこうなっていると思っていた。

 

確認しようと思って、各変数をコンソールアウトして見たところ、

こうなる。

 

コード②

interface  MyInter {
  public static final int VAL = 3;
  void foo(int s);
}
public class Test implements MyInter {
  public static void main(String args) {
    int x = 5;
    new Test().foo(++x);
  }
  public void foo(int s) {
    System.out.println("s1:" + s);
    int a =VAL + ++s;
      System.out.println("s2:" + s);
    System.out.println("a:" +  a);
    s += a;
    System.out.println("s3:" + s);
  }
}
 
結果はこうなる。
s1:6
s2:7
a:10
s3:17←あれ?違うやんか。
 
机上デバッグと実行の場合の値の違いがそのまま出てます。
コード②の場合はsがインクリメントされていますが、
コード①の場合は、インクリメントの反映タイミングがちょっと違うんですね。
基本型なので、参照を利用していないので、こう言うことが起こるんでしょうね。
 
最初に書きましたが、このようなコードはコードレビューでチェックされて修正させられます。処理は一目瞭然でなければいけない。(開発現場による)
 
このプログラムは、見事なバグの温床プログラムですわ。
 
資格試験のサンプルコードとしては「こんな事もできるんだぜ」っていうプログラムになるのでいいんでしょうが。
 
このブログで何が言いたいかといえば、
やべー、この程度のことで間違えちゃったよ〜。
ってことですね。