スキップしてメイン コンテンツに移動

Enumの使い方メモ

今まであまりEnumを使う機会はなかったのですが、ちょっと調べたらこれは見やすなって事でメモしておきます。Androidに限った話ではないですが、Androidっぽさも交えながらサンプルを作りました。サンプルの特徴としては、以下の3点です。
  1. Enumの定義でswitch文を判定できる
  2. Enumの定義とstring.xmlのデータを紐付ける
  3. Enumの定義した順番で欲しい場合はvalues()メソッドで
特に何か意味のある実用的なサンプルではありませんが、上記特徴を表すために....

1は言わずと知れたことですが、それに加えてと2に関して。例えば以下のようなエラーコードとエラーのメッセージを取得できるように定義したとします。

public enum ResultCode {

    // エラーコード,エラーメッセージのID
    OK(200, R.string.result_code_ok),
    ERROR_FORBIDDEN(403, R.string.result_error_fobidden),
    ERROR_NOTFOUND(404, R.string.result_error_notfound),
    ERROR_INTERNAL_SERVER(503, R.string.result_error_internalserver),
    ERROR_UNKNOWN(999, R.string.result_error_unknown),;

    int code,id;
    ResultCode(int code, int id) {
        this.code = code;
        this.id = id;
    }

    // idからエラーメッセージを取得して返す
    public String getMessage(Resources r) {
        return r.getString(id);
    }

    // エラーコードを返す
    public int getErrorCode() {
        return this.code;
    }
}

これを任意のメソッドの戻り値として利用することができます。こんな感じで

    public ResultCode function() {
     
     String page_content = null;
     
     // .....
     
     if(null == page_content) {
      return ResultCode.ERROR_NOTFOUND;
     }
     
     return ResultCode.OK;
    }



呼び出し元の戻り値ではgetErrorCodeでエラーコードを取得でき、getMessageでエラーメッセージを取得できます。エラーメッセージは、getMessageメソッドでstrings.xml経由で定義したIDから文字列に変換する工夫がしてあります。こうしておけば、多言語対応にも便利です。

switch文の判定には、前述の通り直接シンボル名で判定できます。下記サンプルは先ほどのエラーをswitch文で判定してメッセージ(Toast)の表示方法を分岐しています。ERROR_FORBIDDENの場合のメッセージはこんな感じで画面に




    private void dispErrorMessage(ResultCode result) {

        Resources resources = this.getResources();

        switch(result) {
        // ResultCode型として判定できる↓
        case OK:
            // なにもしない
            break;
        case ERROR_FORBIDDEN:
        case ERROR_NOTFOUND:
        case ERROR_INTERNAL_SERVER:
            // エラーを画面に表示
            String error_message = result.getErrorCode() + ":" + result.getMessage(resources);
            Toast.makeText(this, error_message, Toast.LENGTH_SHORT).show();
            break;
        default:
            Toast.makeText(this, ResultCode.ERROR_UNKNOWN.getMessage(resources), Toast.LENGTH_LONG).show();
            break;
        }
    }

で、特徴の3つめですが、例えばEnumで定義したものをspinnerウィジェットへ表示させている場合、spinnerでは何番目が選択されかを返しますが、それがEnumで定義したどれに当たるか知りたい時があるかもしれません。その時に、Enumの定義をvalues()メソッドで配列として取得できるので、この配列の何番目かを見れば紐付けられます。

サンプルでは、spinnerウェジェットに表示されているいずれかのスイーツを選択すると、Toastに値段を表示するものです。






Enumの定義

public enum Sweets {

    // スイーツ名, 値段
    ECLAIR(R.string.spin_product_name_eclair, R.string.spin_product_price_eclair),
    FROZEN_YOGURT(R.string.spin_product_name_froyo, R.string.spin_product_price_froyo),
    GINGERBREAD(R.string.spin_product_name_gingerbread, R.string.spin_product_price_gingerbread),
    ICE_CREAM_SANDWICH(R.string.spin_product_name_ics, R.string.spin_product_price_ics);

    int id_name,id_price;
    Sweets(int id_name, int id_price) {
        this.id_name = id_name;
        this.id_price = id_price;
    }

    public String getName(Resources r) {
        return r.getString(this.id_name);
    }

    public String getPrice(Resources r) {
        return r.getString(this.id_price);
    }
}

spinner側の処理

        Resources resources = this.getResources();

        final Sweets[] values = Sweets.values();
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        // アイテムを追加します
        for(Sweets value : values) {
            adapter.add(value.getName(resources));
        }
        Spinner spinner = (Spinner) findViewById(R.id.spinner1);
        // アダプターを設定します
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                Resources resources = MainActivity.this.getResources();

                String message = "値段:" + values[position].getPrice(resources);
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {}
        });



onItemSelectedはspinnerの項目が選択されたタイミングで実行されます。Sweetsのvalues()で取得される配列とそのメソッドで渡されるpositionで紐付けてものをgetPriceをする事で値段の文字列を取得しています。

上記の全ソースはGithubへアップしました。

takaiwa/EnumSample · GitHub

追記:2012/11/08


onItemSelected内のようなpositionが得られる場面でswitch文を使う場合

switch(values[position]) {
case ECLAIR:
    break;
case FROZEN_YOGURT:
    break;
case GINGERBREAD:
    break;
case ICE_CREAM_SANDWICH:
    break;

}

追記:2013/06/13
入れ子を表現

文字列で定義
public enum Baz{
  yin("yang"),    
  yang("yin"),
  good("evil"),   
  evil("good");

  private String opposite;

  Baz(String opposite){
    this.opposite = opposite;
  }

  public Baz getOpposite(){
     return Baz.valueOf(opposite);
  }
}

switch文で定義
public enum Baz{
  yin,
  yang,
  good,
  evil;

  public Baz getOpposite() {
    switch (this) {
        case yin: return yang;
        case yang: return yin;
        case good: return evil;
        case evil: return good;
    }
    throw new AssertionError();
}

参考:Java enum- Cannot reference a field before it is defined - Stack Overflow

PR:オラクル認定資格教科書 Javaプログラマ Bronze SE 7 スピードマスター問題集 (EXAMPRESS)
PR:Java言語プログラミングレッスン 第3版(上)

コメント

このブログの人気の投稿

Javaでprivateなfieldやmethodにアクセスする

JUnitでテストしてると、privateなフィールドにアクセスして、値を参照したりセットしたりしたくなるわけですが、よく使うのでメモしておきます。 例えば、次のような対象のクラスがあるとします。 public class ParentClass { private String hoge = "ParentClass!!"; public void dispMsg() { System.out.println("dispMsg:" + hoge); } private void privateDispMsg(String msg) { System.out.println("dispMsg:" + msg); } }

GolangでWindows GUIアプリケーション

GUIアプリ作成の前提 社内ツールとしてexeで配布 開発環境はGoLandを使う 社内ツールとしてexeを配布ということであれば、Visual StudioでC#による開発だと思います。しかしながら、Go言語を習得したいのと、GoLandの補完機能が便利で、Android Studio使っていたこともあり、とっつきやすいという点からGo縛りでGUIアプリケーションを考えたいと思います。 lxn/walk Windows application library kit for Go. Windows向けしか考えていないので、まずこのライブラリなのですが、ボタンやコンボボックスが思ったように並ばなかったり、手軽にイメージボタンを配置したりなど、簡単にレイアウトを変更できない課題に直面しました。レイアウト作成だけで時間を取られてしまいます。そう言えば、Androidアプリ開発のときは、XMLでデザイン部分を切り離してたのを思い出して、今回の調査の運びとなりました。 fyne-io/fyne Cross platform native GUIs designed for Go based on Material Design. Supports: Linux, macOS, Windows, BSD, iOS and Android. walkと比べると、クロスプラットフォームで作成できるのですが、こちらもコードの中にデザインを書いていく形でした。 therecipe/qt therecipe/qt allows you to write Qt applications entirely in Go or JavaScript. Qt Creatorなるものがあるようで、デザイン部分を切り離せる印象はあるものの、最新のPCでもビルドに時間がかかるようで、学習コストもかかるという記事を見かけて断念しました。 どうしたものかとツイートしましたら、下記のようにご助言をいただいた。 同じ課題に対し色々試した結果、PWAのフルキャッシュドに落ち着いた。中身はGo+WASMで。 https://t.co/e60whDTV16 — のぼのぼ📡 (@nobonobo) July 21, 2020 PWA 早速調べてみました。Googleが進めているプロジェクトで、ネイティブアプリのよ

Eclipseの高速化メモ

Eclipseが重いと一言に言っても、いろいろな工程での話があると思いますが、過去記事のなども含めてこの記事にピックアップしておきたいと思います。以下はWindows環境での話です。