Est Objets.requireNonNull moins efficace que l'ancienne façon?

Depuis JDK 7, j'utilise heureusement la méthode qu'il a introduite pour rejeter les valeurs null qui sont transmises à une méthode qui ne peut pas les accepter:

private void someMethod(SomeType pointer, SomeType anotherPointer) {
    Objects.requireNonNull(pointer, "pointer cannot be null!");
    Objects.requireNonNull(anotherPointer, "anotherPointer cannot be null!");
    // Rest of method
}

Je pense que cette méthode rend le code très bien rangé qui est facile à lire, et j'essaie d'encourager les collègues à l'utiliser. Mais un collègue (particulièrement bien informé) est résistant, et dit que l'ancienne voie est plus efficace:

private void someMethod(SomeType pointer, SomeType anotherPointer) {
    if (pointer == null) {
        throw new NullPointerException("pointer cannot be null!");
    }
    if (anotherPointer == null) {
        throw new NullPointerException("anotherPointer cannot be null!");
    }
    // Rest of method
}

Il dit que l'appel requireNonNull implique de placer une autre méthode sur la pile d'appels JVM et résultat en pire performance qu'un simple == null Vérifier.

Donc, ma question: y a-t-il des preuves d'une pénalité de performance encourue en utilisant les méthodes Objects.requireNonNull?

50
demandé sur conapart3 2015-04-25 14:37:12

7 réponses

Regardons l'implémentation de requireNonNull dans le JDK D'Oracle:

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

Donc c'est très simple . La JVM (Oracle, de toute façon) inclut un compilateur juste à temps en deux étapes pour convertir le bytecode en code machine. Il intégrera des méthodes triviales comme celle-ci s'il peut obtenir de meilleures performances de cette façon.

Donc, non, pas susceptible d'être plus lente, pas de manière significative, pas n'importe où, qui aurait de l'importance.

Donc ma question: est-il preuves d'un pénalité de performance encourue en utilisant les méthodes Objects.requireNonNull?

La seule preuve qui importerait serait des mesures de performance de votre base de code, ou de code conçu pour être très représentatif de celui-ci. Vous pouvez tester cela avec n'importe quel outil de test de performance décent, mais à moins que votre collègue ne puisse pointer vers un exemple réel d'un problème de performance dans votre base de code lié à cette méthode (plutôt qu'un benchmark synthétique), j'aurais tendance à supposer que vous et il / elle a de plus gros poissons à frire.


Comme un peu d'aparté, j'ai remarqué que votre méthode d'exemple est une méthode private. Donc, seul le code que votre équipe écrit l'appelle directement. Dans ces situations, vous pouvez vérifier si vous avez un cas d'utilisation pour assertions plutôt que des vérifications d'exécution. Les Assertions ont l'avantage de ne pas s'exécuter dans le code "libéré" du tout, et donc d'être plus rapide que l'une ou l'autre alternative dans votre question. Évidemment, il y a des endroits où vous avez besoin de vérifications d'exécution, mais ce sont habituellement aux points de contrôle, méthodes publiques et autres. Juste FWIW.

63
répondu T.J. Crowder 2015-04-25 11:59:12

Formellement parlant, votre collègue a raison:

  • Si someMethod() ou la trace correspondante n'est pas suffisamment chaude, le code d'octet est interprété et un cadre de pile supplémentaire est créé

  • Si someMethod() est appelé sur le 9ème niveau de profondeur à partir du point chaud, les appels requireNonNull() ne doivent pas être MaxInlineLevel Option JVM

  • Si la méthode n'est pas inline pour l'une des raisons ci-dessus, l'argument de T. J. Crowder entre en jeu, si vous utilisez concaténation pour produire un message d'erreur

  • Même si requireNonNull() est inline, JVM perd du temps et de l'espace pour effectuer cela.

D'un autre côté, il existe une option FreqInlineSize JVM, qui interdit l'insertion de méthodes trop grandes (dans les bytecodes). Les bytecodes de la méthode sont comptés par eux-mêmes, sans tenir compte de la taille des méthodes, appelées dans cette méthode. Ainsi, extraire des morceaux de code dans des méthodes indépendantes pourrait être utile parfois, dans l'exemple avec requireNonNull() ceci l'extraction est déjà faite pour vous.

17
répondu leventov 2015-04-25 17:53:07

Si vous voulez preuves ... ensuite, la façon de l'obtenir est d'écrire un micro-benchmark.

(Je recommande de regarder d'abord le projet Calliper! Ou JMH ... selon la recommandation de Boris. De toute façon, n'essayez pas d'écrire un micro-benchmark à partir de zéro. Il y a trop de façons de se tromper.)

Cependant, vous pouvez dire à votre collègue deux choses:

  • Le compilateur JIT fait un bon travail d'insertion de petits appels de méthode, et il est probable que cela se produira dans ce cas.

  • S'il n'a pas intégré l'appel, les chances sont que la différence de performance ne serait qu'un 3 à 5 instructions, et il est très peu probable que cela fasse une différence significative.

5
répondu Stephen C 2015-04-25 11:43:48

Votre collègue a probablement tort.

La JVM est très intelligente et intégrera probablement la méthode Objects.requireNonNull(...). La performance est discutable mais il y aura certainement des optimisations beaucoup plus sérieuses que cela.

Vous devez utiliser la méthode utilitaire de JDK.

1
répondu Crazyjavahacking 2015-04-25 11:39:50

En règle générale, la lisibilité et la maintenabilité devraient l'emporter sur l'optimisation.

Cette règle protège contre l'optimisation spéculative des personnes qui pensent savoir comment fonctionne un compilateur même si elles n'ont jamais tenté d'en écrire une et qu'elles n'ont jamais regardé à l'intérieur d'une.

Votre collègue a tort à moins qu'il ne prouve que la pénalité de performance est perceptible et intenable pour les utilisateurs.

0
répondu punkstarman 2018-04-27 19:53:02

Java efficace {[2] } par Joshua Bloch

Article 67: Optimiser judicieusement

Il y a trois aphorismes concernant l'optimisation que tout le monde devrait connaître:

Plus de péchés informatiques sont commis au nom de l'efficacité (sans nécessairement l'atteindre) que pour toute autre raison unique - y compris la stupidité aveugle.
- William A. Wulf [Wulf72]

Nous devrions oublier les petites efficacités, disons environ 97% de temps: l'optimisation prématurée est la racine de tout mal.
- Donald E. Knuth [Knuth74]

Nous suivre deux règles en matière d'optimisation:
La règle 1. Ne pas le faire.
Article 2 (pour les experts seulement). Ne le faites pas encore qui est, pas jusqu'à ce que vous avoir une solution parfaitement claire et non optimisée.
-M. A. Jackson [Jackson75]

0
répondu Michael G 2018-08-01 09:49:09

Objets.requireNonNull est plus optimisé comme si vous étiez réutilisable. Aussi dans Oracle requireNonNull si défini comme

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
} 

Donc c'est déjà en bytecode.

-3
répondu richa ojha 2017-05-09 08:41:36