8
votes

Dans les flux Java, l'utilisation de .peek () est considérée comme étant uniquement utilisée à des fins de débogage, la journalisation serait-elle considérée comme un débogage?

J'ai donc une liste d'objets dont je souhaite que tout ou partie soit traité, et je voudrais enregistrer les objets qui ont été traités.

Prenons un exemple fictif:

List<ClassInSchool> classes;
classes
.stream()
.filter(verifyClassInSixthGrade())
.filter(classHasNoClassRoom())
.peek(classInSchool -> log.debug("Processing classroom {} in sixth grade without classroom.", classInSchool)
.forEach(findMatchingClassRoomIfAvailable());


1 commentaires

Non, la réponse choisie n'est pas claire dans ce qui est considéré comme une utilisation non intentionnelle de l'API basée sur les documents de l'API, qui est ma question exacte. La journalisation est-elle considérée comme un débogage dans cette instance, ou l'utilisation de peek est-elle réellement limitée au code temporaire lors de la création de la chaîne de flux réelle?


4 Réponses :


2
votes

Peek doit être évité car pour certaines opérations de terminal, il peut ne pas être appelé, voir cette réponse . Dans cet exemple, il serait probablement préférable de faire la journalisation dans l'action de forEach plutôt que d'utiliser peek . Le débogage dans cette situation signifie un code temporaire utilisé pour corriger un bogue ou diagnostiquer un problème.


2 commentaires

@tterag si je comprends correctement le fonctionnement des opérations de terminal, il n'appelle pas .peek () dans le cas où le .forEach () ne serait pas appelé pour cet objet dans le flux, ce qui est en fait plus logique. Dans ce cas, je ne consignerais pas les objets qui ne sont pas traités.


Le problème réside dans le fonctionnement du terminal sous le capot. Ce comportement peut changer à tout moment car il n'est pas défini. La journalisation des objets au fur et à mesure qu'ils passent par l'opérateur du terminal est le moyen le plus fiable de faire ce que votre exemple essaie de faire.



1
votes

Dans les flux Java, l'utilisation de .peek () est considérée comme étant uniquement utilisée à des fins de débogage, la journalisation serait-elle considérée comme un débogage?

Cela dépend du fait que votre code de journalisation sera ou non un élément permanent de votre code.

Vous seul pouvez vraiment connaître le véritable objectif de votre journalisation ...

Notez également que javadoc dit:

Dans les cas où l'implémentation du flux est capable d'optimiser la production de certains ou de tous les éléments (comme avec des opérations de court-circuit comme findFirst , ou dans l'exemple décrit dans count () ), l'action ne sera pas appelée pour ces éléments.

Ainsi, vous êtes susceptible de constater que dans certaines circonstances, peek ne sera pas un moyen fiable de consigner (ou déboguer) votre pipeline.

En général, l'ajout de peek est susceptible de modifier le comportement du pipeline et / ou la capacité de la JVM à l'optimiser ... dans une JVM de génération actuelle ou future.


3 commentaires

À mon avis, les opérations de court-circuit ne définissent pas ma journalisation, car je veux uniquement que l'objet traité par toute la chaîne soit enregistré. Je ne suis pas intéressé par 400 lignes de connexion qui masquent réellement ce qui s'est passé, car il se peut qu'il n'y en ait eu que 40 traitées par l'opération de terminaison. Si c'était la raison de ne pas utiliser .peek (), par cette logique, vous ne devriez pas utiliser .map () non plus parce que vous pourriez ne pas utiliser d'opération de terminaison et de cette façon .map () ne traiterait aucun objet ...


@Jonas si vous voulez par toute la chaîne - faites-le dans l'opération du terminal. Si vous ne pouvez pas, faites-le ensuite sur le résultat de l'opération du terminal. peek est uniquement pour vous aider à comprendre votre pipeline de flux et à le configurer correctement, rien de plus.


@Jonas - Vous êtes libre d'ignorer les conseils que vous recevez de différentes personnes. (Mais si vous allez faire ça ... pourquoi demander conseil?)



0
votes

Eh, c'est un peu ouvert à l'interprétation. L'intention n'est pas toujours facile à déterminer.

Je pense que la note API a été principalement ajoutée pour décourager une utilisation trop zélée de peek alors que presque tous les comportements souhaitables peuvent être accomplis sans lui. Il était tout simplement trop utile pour les développeurs de l'exclure complètement, mais ils voulaient qu'il soit clair que son inclusion ne devait pas être considérée comme une approbation sans réserve; ils ont vu le potentiel d'utilisation abusive et ils ont essayé d'y remédier.

Je soupçonne - même si je ne fais que spéculer - qu'il y avait des opinions partagées sur l'opportunité de l'inclure, et que l'inclusion d'une version avec une mise en garde dans le JavaDoc était le compromis.

Dans cet esprit, je pense que ma suggestion pour décider quand utiliser peek serait simplement: ne l'utilisez pas à moins d'avoir une très bonne raison de le faire.

Dans votre cas, vous n'avez certainement pas de bonne raison de le faire. Vous parcourez tout et passez le résultat à la méthode findMatchingClassRoomIfAvailable (enfin, probablement - votre exemple n'était pas très bon). Si vous souhaitez enregistrer quelque chose pour chaque élément du flux, enregistrez-le simplement en haut de cette méthode.

S'agit-il d'une mauvaise utilisation? Je ne pense pas. Est-ce que je l'écrirais de cette façon? Non.


0 commentaires

4
votes

Le la documentation de peek décrit l'intention comme

Cette méthode existe principalement pour prendre en charge le débogage, où vous souhaitez voir les éléments au fur et à mesure qu'ils passent à un certain point dans un pipeline.

Une expression de la forme .peek (classInSchool -> log.debug ("Traitement de la classe {} en sixième année sans classe.", classInSchool) remplit cet objectif, car il s'agit de signaler le traitement d'un élément. Peu importe que vous utilisiez le framework de journalisation ou que vous imprimiez simplement des instructions, comme dans l'exemple de la documentation, .peek (e -> System.out.println (" Valeur filtrée: "+ e)) . Dans les deux cas, l'intention est importante, pas l'approche technique. Si quelqu'un a utilisé peek avec l'intention d ' imprimer tous les éléments , ce serait faux, même s'il utilisait la même approche technique que l'exemple de la documentation ( System.out.println ).

La documentation ne vous oblige pas à faire la distinction entre l'environnement de production et l'environnement de débogage, pour supprimer l'utilisation de peek pour le premier. En fait, votre utilisation répondrait même à cela, car le cadre de journalisation vous permet de désactiver cette action via le niveau de journalisation configurable.

Je suggérerais tout de même de garder à l'esprit que pour certains pipelines, l'insertion d'une opération peek peut entraîner plus de surcharge que l'opération réelle (ou entraver les optimisations de la boucle de la JVM à un tel degré). Mais si vous ne rencontrez pas de problèmes de performances, vous pouvez suivre l'ancien conseil pour ne pas essayer d'optimiser à moins d'avoir une vraie raison…


5 commentaires

car je veux seulement que l'objet traité par toute la chaîne soit consigné - le commentaire OP sous l'une des réponses; dans un tel cas, se fier à peek serait faux


@Eugene J'ai le sentiment, vous sur-interprétez ce commentaire. Pour moi, il semble que le PO essaie de dire qu'il est d'accord pour ne consigner que les éléments qui ont été réellement traités.


peut être. Je veux dire par toute la chaîne pour moi, c'est tout ce qui a frappé l'opération du terminal, en utilisant peek pourrait enregistrer plus que cela, non?


@Eugene, il n’ya aucune garantie que le code du consommateur final s’est terminé, mais la grammaire du message de journalisation suggère qu’il est prévu de se connecter au démarrage. Puisque tous les éléments qui ont passé ce point sont destinés à être passés à l'état de traitement suivant, c'est-à-dire le consommateur final, cela peut être la sémantique correcte / voulue, même en cas d'achèvement inattendu, en particulier dans le cas de forEach < / code>, où seule une exception pourrait provoquer cela.


ah! bon point, vous avez pris le code de la question beaucoup plus près que moi. Je ne pensais à cela que pour être un exemple, pas pour quelque chose de réel dont traite le PO.