Инициализация списка в управляемом компоненте JSF

У меня есть вопрос об инициализации List в 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;
    }

}

Итак, мой вопрос: какой подход лучше?

Ответ 1

Если это управляемый компонент, как вы говорите, вы должны сделать это в методе, аннотированном с @PostConstruct

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

    //getter and setter...
}
  1. Практика выполнения любой инициализации в getter и setter обычно не одобряется в контексте JSF. См. Почему JSF вызывает геттеры несколько раз

  2. Кроме того, для API для @PostConstruct, контракт определяет функции безопасности и гарантирует, что если исключение выбрасывается в методе, аннотированном как таковое, компонент не должен вводиться в действие. Таких гарантий для простого конструктора нет.

  3. В управляемом компоненте инъекция происходит сразу после строительства. Это означает, что любые операции, которые вы выполняете в конструкторе, не могут зависеть от каких-либо @ManagedProperty ресурсов (через @ManagedProperty). Если в методе @PostConstruct вас будет доступ ко всем ресурсам, объявленным в управляемом компоненте

EDIT: Это важно отметить, что может быть только один @PostConstruct для любого @ManagedBean, поэтому вся важная инициализация должна произойти там.

Также стоит отметить, что, хотя метод @PostConstruct является идеальным местом для инициализации переменной /List компонента backing bean, есть последствия в отношении объема управляемого компонента

  1. @RequestScoped: в управляемом компоненте с этой аннотацией метод будет вызван для каждого из представленных JSF-представлений. @RequestScoped уничтожается и воссоздается с каждым запросом. Следствием этого является то, что в зависимости от вашей установки список, инициализированный в @PostConstruct может быть сброшен до пустых значений или значений по умолчанию во время каждого запроса. При определенных обстоятельствах ошибки преобразования могут возникать в результате повторной инициализации запроса mid-JSF списка.

  2. @ViewScoped: в управляемом компоненте с этой аннотацией вы гарантированно @PostConstruct метод @PostConstruct один раз, если и только если вы имеете дело с одним и тем же экземпляром компонента @ViewScoped. Если обработанный вид бобов уничтожен и воссоздан, метод @PostConstruct снова запустится.

  3. @SessionScoped: компонент с этой аннотацией создается один раз и остается живым до окончания сеанса HTTP пользователя. В этом случае метод @PostConstruct гарантированно запускается один раз и только один раз, пока бит не будет уничтожен

Смотрите также

Ответ 2

Я бы предложил следующее:

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);
     }
}

Ответ 3

На мой взгляд, лучше всего было бы это обработать в конструкторах. Если используется конструктор по умолчанию, инициализируйте список в конструкторе.

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

Если используется конструктор, который принимает параметры, пусть вызывающий класс пройдет в списке.

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

Ответ 4

Мое предложение, добавьте нулевую проверку в getter:

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);

Ответ 5

Это зависит. Обычно первый способ предпочтительнее, потому что позже вы можете добавить что-то в коллекцию. Если вы не знаете, была ли ваша коллекция инициализирована или нет, вы должны проверять ее каждый раз.