En supposant que vous utilisez Java 1.5 et que vous ne pouvez pas ajouter Collections Google je ferais quelque chose de très similaire à ce que les gars de Google ont fait. C'est une légère variation sur les commentaires de Jon.
Ajoutez d'abord cette interface à votre codebase.
public interface IPredicate<T> { boolean apply(T type); }
Ses implémenteurs peuvent répondre quand un certain prédicat est vrai pour un certain type. Par exemple, si T
étaient User
y AuthorizedUserPredicate<User>
met en œuvre IPredicate<T>
entonces AuthorizedUserPredicate#apply
renvoie si l'objet passé en User
est autorisé.
Ensuite, dans une classe d'utilité, vous pourriez dire
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element: target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
Donc, en supposant que vous avez l'utilisation de ce qui précède pourrait être
Predicate<User> isAuthorized = new Predicate<User>() {
public boolean apply(User user) {
// binds a boolean method in User to a reference
return user.isAuthorized();
}
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);
Si les performances de la vérification linéaire sont importantes, il est préférable d'avoir un objet de domaine qui possède la collection cible. L'objet de domaine qui possède la collection cible aurait une logique de filtrage pour les méthodes qui initialisent, ajoutent et définissent la collection cible.
UPDATE :
Dans la classe utilitaire (disons Predicate), j'ai ajouté une méthode de sélection avec une option pour la valeur par défaut lorsque le prédicat ne renvoie pas la valeur attendue, et aussi une propriété statique pour les paramètres à utiliser dans le nouvel IPredicate.
public class Predicate {
public static Object predicateParams;
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element : target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
T result = null;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
T result = defaultValue;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
}
L'exemple suivant recherche les objets manquants entre les collections :
List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
new IPredicate<MyTypeA>() {
public boolean apply(MyTypeA objectOfA) {
Predicate.predicateParams = objectOfA.getName();
return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
public boolean apply(MyTypeB objectOfB) {
return objectOfB.getName().equals(Predicate.predicateParams.toString());
}
}) == null;
}
});
L'exemple suivant, recherche une instance dans une collection, et renvoie le premier élément de la collection comme valeur par défaut si l'instance n'est pas trouvée :
MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));
MISE À JOUR (après la sortie de Java 8) :
Cela fait plusieurs années que j'ai (Alan) posté cette réponse pour la première fois, et je n'arrive toujours pas à croire que j'accumule des points SO pour cette réponse. Quoi qu'il en soit, maintenant que Java 8 a introduit les closures dans le langage, ma réponse serait considérablement différente et plus simple. Avec Java 8, il n'y a pas besoin d'une classe utilitaire statique distincte. Donc si vous voulez trouver le 1er élément qui correspond à votre prédicat.
final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).findFirst();
L'API du JDK 8 pour les optionnels permet de get()
, isPresent()
, orElse(defaultUser)
, orElseGet(userSupplier)
y orElseThrow(exceptionSupplier)
ainsi que d'autres fonctions "monadiques" telles que map
, flatMap
y filter
.
Si vous voulez simplement collecter tous les utilisateurs qui correspondent au prédicat, utilisez l'option Collectors
pour terminer le flux dans la collection souhaitée.
final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).collect(Collectors.toList());
Voir aquí pour plus d'exemples sur le fonctionnement des flux Java 8.