-tandis que avec Java8-Facultatif

Je suis souvent à l'aide de le faire-tout-en-checkNextForNull-getNext boucle motif (ne sais pas si il y a un nom officiel) dans certains de mes projets. Mais dans Java8, l'utilisation de l'Option est considérée comme nettoyeur de code de vérification de références nulles en client-code. Mais lors de l'utilisation en Option dans cette boucle motif, le code est un peu verbeux et moche, mais parce que l'Option a une certaine pratique de méthodes, je m'attends à ce qu'il doit exister une façon plus propre que celle que j'ai trouvé ci-dessous.

Exemple:

Compte tenu de la classe suivante.

class Item {
    int nr;

    Item(nr) {
        this.nr = nr;
        //an expensive operation
    }

    Item next() {
        return ...someCondition....
            ? new Item(nr + 1)
            : null;
    }
}

Dans lequel le premier élément a toujours nr==1 et chaque élément détermine l'élément suivant, et vous ne voulez pas créer inutilement de nouveaux éléments.

J'pouvez utiliser la boucle do-while-checkNextForNull-getNext modèle client-code:

Item item = new Item(1);
do {
    //do something with the item ....
} while ((item = item.next()) != null);

Avec Java8-en Option, la classe devient:

class Item {
    ....

    Optional<Item> next() {
        return ...someCondition....
            ? Optional.of(new Item(nr + 1))
            : Optional.empty();
    }
}

Et puis, le faire-tout-en-checkNextForNull-getNext boucle motif devient un peu moche et verbose:

Item item = new Item(1);
do {
    //do something with the item ....
} while ((item = item.next().orElse(null)) != null);

La orElse(null)) != null partie se sent mal à l'aise.

J'ai regardé pour d'autres types de boucles, mais je n'ai pas trouvé mieux. Est-il une solution plus propre?

Mise à jour:

Il est possible d'utiliser une boucle for-each, tout en évitant en même temps null références (l'utilisation de null-références est considéré comme une mauvaise pratique). Cette solution a été proposée par Xavier Delamotte, et n'a pas besoin de Java8-Facultatif.

Mise en œuvre avec un générique itérateur:

public class Item implements Iterable<Item>, Iterator<Item> {
    int nr;

    Item(int nr) { 
        this.nr = nr;
        //an expensive operation
    }

    public Item next() {
        return new Item(nr + 1);
    }

    public boolean hasNext() {
        return ....someCondition.....;
    }

    @Override
    public Iterator<Item> iterator() {
        return new CustomIterator(this);
    }
}

et

class CustomIterator<T extends Iterator<T>> implements Iterator<T> {
    T currentItem;
    boolean nextCalled;

    public CustomIterator(T firstItem) {
        this.currentItem = firstItem;
    }

    @Override
    public boolean hasNext() {
        return currentItem.hasNext();
    }

    @Override
    public T next() {
        if (! nextCalled) {
            nextCalled = true;
            return currentItem;
        } else {
            currentItem = currentItem.next();
            return currentItem;
        }
    }
}

Puis code client devient très simple/nettoyage:

for (Item item : new Item(1)) {
    //do something with the item ....
}

Même si cela peut être considéré comme une violation de l'Itérateur contrat en raison de la new Item(1) objet est inclus dans la boucle, alors que normalement, la boucle serait immédiatement appel à next() et donc de sauter le premier objet. En d'autres termes: pour le premier objet, next() est violé parce qu'il renvoie le premier objet lui-même.

Avez-vous vraiment l'utilisation de ce modèle? Pourriez-vous classe implémente Iterable et vous donne un Iterator à la place ? Vous avez juste à mettre en œuvre hasNext() (ce qui est votre condition booléenne) et next, au lieu de la mise en œuvre uniquement next().
d'accord, cela sent (encore une autre), la surutilisation de l'Java8 featureset. c'est une bonne question, OP.
Iterator est notoirement difficile à mettre en œuvre sur IO sources. Pour savoir si c'est hasNext, il a fait de lire et de mettre en cache l'élément suivant. Curseur-comme les expressions idiomatiques, en s'appuyant uniquement sur la méthode unique, sont en fait préféré. Par exemple, Spliterator utilise cette approche, avec une torsion.
En effet. Cependant Goyave offres pour l'utilisation de AbstractIterator pour simplifier la mise en œuvre de ces itérateurs. code.google.com/p/guava-libraries/wiki/...
Le wrapper toujours pas aider le fait que hasNext est censé être un effet secondaire de la méthode avec des pas de temps de latence. Surtout noter les difficultés résultant de la nécessité de signal erreurs d'e/S pour le client.

OriginalL'auteur Devabc | 2015-02-26