web-dev-qa-db-ja.com

JSFマネージドBeanでのリストの初期化

次のコードに従うので、POJOでのリストの初期化について質問があります。

public class Person {

 //other fields...
 private List<String> friends=new ArrayList<>();

     public List<String> getFriends() {
        return friends;
     }
     public void setFriends(List<String> friends) {
        this.friends = friends;
    }

}

または、このようにして、他のクラス(Bean(JSF)など)で初期化する方がよいですか?

public class Person {

 //other fields...
 private List<String> friends;

     public List<String> getFriends() {
        return friends;
     }
     public void setFriends(List<String> friends) {
        this.friends = friends;
    }

}

だから私の質問は、どのアプローチがより良いかということです。

12
Mitja Rogl

あなたが言うようにそれがマネージドBeanである場合は、@PostConstructアノテーションが付けられたメソッドでこれを行う必要があります。

public class Person {
    private List<String> friends;
    @PostConstruct
    public void init(){
         friends = new ArrayList<String>();
    }

    //getter and setter...
}
  1. ゲッターとセッターで初期化を行う慣行は、一般的にJSFのコンテキスト内で嫌われています。 JSFがゲッターを複数回呼び出す理由 を参照してください。

  2. また、 @PostConstructのAPIに従って 、コントラクトは安全機能を指定し、そのように注釈が付けられたメソッドで例外がスローされた場合、Beanがサービスに使用されないことを保証します。プレーンコンストラクターにはそのような保証はありません。

  3. マネージドBeanでは、注入は構築直後に行われます。これは、コンストラクターで実行している操作が、(@ManagedPropertyを介して)注入されたリソースに依存できないことを意味します。一方、@PostConstructメソッドでは、マネージドBeanで宣言されたすべてのリソースにアクセスできます。

編集:は任意の@PostConstructに対して1つ@ManagedBeanしか存在できないため、すべての重要な初期化はそこで行われる必要があることに注意することが重要です。

@PostConstructメソッドはバッキングBean変数/ Listを初期化するのに理想的な場所ですが、マネージドBeanのスコープに関しては影響があることに注意することも価値があります。

  1. @RequestScoped:このアノテーションが付いたマネージドBeanでは、関連するJSFビューの送信ごとにメソッドが呼び出されます。 @RequestScoped Beanは、リクエストごとに破棄および再作成されます。これは、セットアップによっては、@PostConstructで初期化されたリストが、リクエストごとに空またはデフォルト値にリセットされる場合があることを意味します。特定の状況下では、JSF要求の途中でリストを再初期化した結果として、変換エラーが発生する場合があります。

  2. @ViewScoped:このアノテーションが付いたマネージドBeanでは、@PostConstructメソッドが1回実行されることが保証されていますif and only if@ViewScopedBeanの同じインスタンスを処理しています。ビュースコープのBeanが破棄されて再作成された場合、@PostConstructメソッドが再度実行されます。

  3. @SessionScoped:このアノテーションが付いたBeanは一度作成され、ユーザーのHTTPセッションが終了するまで存続します。このシナリオでは、@PostConstructメソッドは、Beanが破棄されるまで1回だけ実行されることが保証されています。

も参照してください

25
kolossus

私はこれを提案します:

public class Person {
     //other fields...
     private List<String> friends=new ArrayList<>();

     // returns a copy to protect original list
     public List<String> getFriends() {
        Collections.unmodifiableList(new ArrayList<>(friends));
     }
     public void addFriend(String> friend) {
        this.friends.add(friend);
     }
     public void addFriends(List<String> friends) {
        this.friends.addAll(friends);
     }
}
4
anubhava

私の意見では、コンストラクターでそれを処理するのが最善でしょう。デフォルトのコンストラクターを使用する場合は、コンストラクターでリストを初期化します。

public Person() {
    friends = new ArrayList<>();
}

パラメーターを受け入れるコンストラクターを使用する場合は、呼び出し元のクラスにリストを渡させます。

public Person(ArrayList<> friends) {
    this.friends = friends;//friends
}
3
Haz

私の提案では、ゲッターにnullチェックを追加します。

public class Person {
  //other fields...
  private List<String> friends;

  public List<String> getFriends() {
     if (this.friends == null) friends = new ArrayList<String>();
     return friends;
  }
}

ただし、セッターを省略していることにも注意してください。代わりに、クライアントコードでは、次のように呼び出します。

personInstance.getFriends().add("Some Item");

または、追加する完全なリストがある場合:

personInstance.getFriends().addAll(someStringCollection);
2
cobaltduck

場合によります。後でコレクションに何かを追加したい場合があるため、通常は最初の方法が望ましいです。コレクションが初期化されたかどうかわからない場合は、毎回チェックする必要があります。

1