読者です 読者をやめる 読者になる 読者になる

へっぽこびんぼう野郎のnewbie日記

けろけーろ(´・ω・`)!

あのハゲそうなくらいよくわからんかったビット演算子と三項演算子が便利すぎるものだった話

PC Java

String hoge = ( i > 3) ? "○" : "×";

三項演算子ってこういうやつ。

if文でも同じようなことを書けるが、if文で書くとめんどくさい。

String hoge = null;

if( i > 3) {

    hoge = "○";

} else {

    hoge = "×";

 こうなってしまう。「だから何? if文の方が簡単に書けるでしょ?^^」って思ってる人は次の文を見てほしい。

こう書けるのも

String hoge =  (i > 0) ? ((i > 3) ? "3" :(i > 2) ? "2" : "0") + "より大きい"

                                      :  "0以下";

こうなる。

String hoge = null;

if ( i > 0) {

    if( i > 3) {

        hoge = "3";

    } else if( i > 2) {

        hoge = "2";

    } else {

         hoge= "0";

    }

    hoge += "より大きい";

} else {

    hoge = "0以下";

}

ナゲェ。ちなみに赤色が無駄な部分。無駄の方が多いね!

だから三項演算子の文の書き方に慣れるべきである。

 

次にビット演算子のよいところ

boolean aFlg = false;

boolean bFlg = false;

boolean cFlg = false;

boolean dFlg = false;

boolean eFlg = false;

っていうフラグがあるとする。

これを毎回別のものとして管理するのって結構めんどくさいし、

今どのようにフラグが立ってるかわかりにくい。

 

だから一元管理するお! ってことでビット演算子を活用する。

 int manFlg = 0; 

 これを"00000"として扱う。

aFlgを"00001"

bFlgを"00010"

cFlgを"00100"

dFlgを"01000"

eFlgを"10000"として使う。

こんな感じでおいておく。

static final int A_FLG = 1;

static final int B_FLG = 2; //2進数で10

static final int C_FLG = 4; //2進数で100

 適当にenumの定数にしてもいいかもしれない。

 列挙型にしなくても、定数にしないとよくわからなくなる気がする。

 

 aFlgを反転させたいとき、ふつうは

aFlg =  (aFlg) ? false : true;

こうする。当然if文を使うともっと文は長くなる

 

ビット演算をつかってみるとこうなる(みじかい)

(XOR演算)

manFlg ^= A_FLG; 

 00000 ^ 00001 → 00001 // false → true

 00001 ^ 00001 → 00000 // true → false

 10100 ^ 00001 → 10101 // false → true

 01011 ^ 00001 → 01010 // true → false

みたいな感じになる。

 

bFlgを常にtrueにしたい場合(OR演算)は、

manFlg |= B_FLG;

 とする。ちなみにこれを「1にマスクする」という。

|=ってなんとなくマスクっぽい形してるから一度理解したらそんな感じで覚えるべき。

 00000 | 00010 → 00010 // false → true

 00001 | 00010 → 00011 // false → true

 10110 | 00010 → 10110 // true → true

 

cFlgを常にfalseにしたい場合は定数の否定と、AND演算を使う

manFlg &= ~C_FLG;

こっちは「0にマスクする」という。

&=って、体操座りした人がくしゃみしてる感じに見えるから(こじつけ)

「こいつマスクしろよ」的な感じで覚えるべき(てきとう)

 00000 & 11011 → 00000 // false → false

 00100 & 11011 → 00100 // true → false

 10110 & 11011 → 10010 // true → false

 

aFlgの状態がどうなっているか調べたいときはAND演算

(manFlg & A_FLG) == A_FLG

 00000 & 00001 → 00000 // false → false

 00001 & 00001 → 00001 // true → true

 10110 & 00001 → 00001 // false → false

↑ aFlgがtrueならtrueを返し、falseならfalseを返す。

 

ひとまずこれを、バカみたいに何も考えず使っていけばいいと思った。

今フラグ全体どうなってんのってのをあまり気にせずにボカスカとフラグをぶちこめるのは嬉しい。

フラグの一元管理をしたいときは使っていこうと思う。

 

こういうことも可能になる。

static final int AC_FLG = A_FLG | C_FLG

↑ aFlgとcFlgを同時に変更するFlg

 

ちなみにビット演算子の&=や|=などは、+=などと同じで演算の優先順位が最低なので使うときは括弧でくくってあげないと「ほぇ?!」という結果になってしまうので注意。

シフト演算子はなぜかけっこうつよい。

&や|の単独も、+や-などと比べると大幅によわいので注意。

演算の優先順位って、ポケモンでいう優先度(しんそくが+2とか、でんこうせっかが+1とかのアレ)で考えるとちょっと楽しいかもしれない。

それからインクリメントやデクリメント、キャストじゃない方の()と[]が最強。

 

次はシフト演算の使い道って何か気になります

ただ、こんな書き方職場でやると「えっなにしてるのわかりにくいよ」って顔されそうで怖い。

まぁフラグ管理なんてそうそうないだろ・・・(なげやり)