J'ai une question sur l'initialisation de la liste dans le POJO car il suit le code suivant:
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;
}
}
OU est-ce mieux comme ça et avoir une initalisation dans une autre classe (comme par exemple 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;
}
}
Donc, ma question est quelle approche est la meilleure?
Si c'est un bean géré comme vous le dites, vous devriez le faire dans une méthode annotée avec @PostConstruct
public class Person {
private List<String> friends;
@PostConstruct
public void init(){
friends = new ArrayList<String>();
}
//getter and setter...
}
Toute pratique d'initialisation dans le getter et le setter est généralement mal vue dans le contexte de JSF. Voir Pourquoi JSF appelle les Getters plusieurs fois
De plus, pour l'API de @PostConstruct
, le contrat spécifie des fonctionnalités de sécurité et garantit que si une exception est renvoyée dans une méthode annotée en tant que telle, le bean ne doit pas être mis en service. Il n'y a pas de telles garanties sur un constructeur ordinaire.
Dans un haricot géré, l'injection a lieu immédiatement après la construction. Cela signifie que les opérations que vous effectuez dans le constructeur ne peuvent dépendre d'aucune ressource injectée (via @ManagedProperty
). Alors que dans une méthode @PostConstruct
, vous aurez accès à toutes les ressources déclarées sur le bean géré
EDIT: Il est important de noter que il ne peut en exister qu'un seul@PostConstruct
pour tout @ManagedBean
, toutes les initialisations importantes doivent donc y être effectuées.
Il est également intéressant de noter que, si la méthode @PostConstruct
est l’endroit idéal pour initialiser une variable de bean de support/List
, il existe des implications en ce qui concerne la portée du bean géré.
@RequestScoped
: Dans un bean géré avec cette annotation, la méthode sera appelée par soumission de la vue JSF concernée. Un bean @RequestScoped
est détruit et recréé à chaque demande. Cela a pour conséquence qu'en fonction de votre configuration, la liste initialisée dans le @PostConstruct
peut être réinitialisée à des valeurs vides ou par défaut lors de chaque demande. Dans certaines circonstances, des erreurs de conversion peuvent survenir à la suite de la réinitialisation de la demande de liste mi-JSF.
@ViewScoped
: dans un bean géré avec cette annotation, la méthode @PostConstruct
sera exécutée une fois, si et seulement si vous traitez avec la même instance du bean @ViewScoped
. Si le bean en vue est détruit et recréé, la méthode @PostConstruct
sera exécutée à nouveau.
@SessionScoped
: un bean avec cette annotation est créé une fois et reste actif jusqu'à la fin de la session HTTP de l'utilisateur. Dans ce scénario, la méthode @PostConstruct
est garantie d'être exécutée une et une seule fois jusqu'à la destruction du bean
Voir également
Je suggérerais ceci:
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);
}
}
À mon avis, il serait préférable de gérer cela dans les constructeurs. Si un constructeur par défaut est utilisé, initialisez la liste dans le constructeur.
public Person() {
friends = new ArrayList<>();
}
Si un constructeur acceptant des paramètres est utilisé, laissez la classe appelante passer dans une liste.
public Person(ArrayList<> friends) {
this.friends = friends;//friends
}
Ma suggestion, ajouter un chèque nul dans le getter:
public class Person {
//other fields...
private List<String> friends;
public List<String> getFriends() {
if (this.friends == null) friends = new ArrayList<String>();
return friends;
}
}
Mais notez aussi que j'ai omis le passeur. Au lieu de cela, dans n'importe quel code client, appelez comme ceci:
personInstance.getFriends().add("Some Item");
Ou si vous avez une liste complète à ajouter:
personInstance.getFriends().addAll(someStringCollection);
Ça dépend. Habituellement, la première solution est préférable, car vous souhaiterez peut-être ajouter quelque chose à la collection ultérieurement. Si vous ne savez pas si votre collection a été initialisée ou non, vous devez la vérifier à chaque fois.