(String) ou .toString ()?

89

J'ai une méthode avec un Object o paramètre.

Dans cette méthode, je sais exactement qu'il y a un Stringin "o" qui n'est pas nul. Il n'est pas nécessaire de vérifier ou de faire autre chose. Je dois le traiter exactement comme un Stringobjet.

Juste curieux - qu'est-ce qui est moins cher - le lancer Stringou l'utiliser Object.toString()? Ou est-ce la même chose en fonction du prix time- / cpu- / mem-?

Mise à jour: La méthode accepte Objectcar c'est l'implémentation d'une interface. Il n'existe aucun moyen de modifier le type de paramètre.

Et ça ne peut pas être nulldu tout. Je voulais juste dire que je n'ai pas besoin de le vérifier pour une valeur nulle ou vide. Dans mon cas, il y a toujours une chaîne non vide.

Vugluskr
la source
1
Dans le monde .NET, nous l'avons mesuré et ToString () est plus rapide. Étant donné la raison pour laquelle il en est ainsi, la même chose est presque certainement vraie pour une JVM jitting.
Joshua

Réponses:

73

la conversion en String est moins chère car cela ne nécessite pas d'appel de fonction externe, juste une vérification de type interne.

euphorie83
la source
4
L'avez-vous testé sur plusieurs JRE? J'ai vu des résultats surprenants pour exaclty cette situation dans .NET. En réalité, je doute que les performances importent dans la vraie vie - mais le casting est meilleur du point de vue du codage défensif.
Jon Skeet
L'appel de méthode doit être incorporé. L'utilisation de génériques pour supprimer la distribution (explicite) serait la meilleure solution.
Tom Hawtin - tackline
@Jon Skeet: Je suis d'accord que la différence de performance ne sera pas beaucoup. @Tom Hawtin: Comme le type de l'objet qui sera reçu n'est pas connu au moment de la compilation, je ne vois pas comment l'appel de méthode peut être inséré. Pouvez-vous clarifier?
euphoria83
@ euphoria83: Intégré par le compilateur JIT, pas par javac.
Michael Myers
En fait, non, la méthode ne peut pas être intégrée. Le type est uniquement connu pour être Object, et l'implémentation réelle dépend du type d'exécution. Lequel est le plus rapide dépend toujours de la mise en œuvre, mais pour autant que je me souvienne (je l'ai en fait testé avec microbenchmark à un moment donné), le casting semble être plus rapide. Ce n'est pas une réponse évidente: la vérification de type n'est pas toujours plus rapide. Pour le type String, cela peut être puisque c'est un objet (pas une interface), et le dernier à cela.
StaxMan
45

J'utiliserais un plâtre. Cela valide votre "connaissance" qu'il s'agit d'une chaîne. Si, pour une raison quelconque, vous vous retrouvez avec un bogue et que quelqu'un passe autre chose qu'une chaîne, je pense qu'il serait préférable de lancer une exception (ce que fera un casting) que de continuer à exécuter avec des données défectueuses.

Jon Skeet
la source
7

Si vous savez que l'objet o est une chaîne, je dirais simplement de le convertir en chaîne et de l'appliquer de cette façon. Appeler toString () sur un objet dont vous savez avec certitude qu'il s'agit d'une chaîne peut simplement ajouter de la confusion.

Si Object o peut être autre chose qu'une chaîne, vous devrez appeler toString ().

Andy White
la source
C'est la bonne réponse pour moi. Pourquoi? Parce que la conversion (string)Registry.GetValue...lève une exception pour essayer de convertir un objet Int32, alors qu'elle Registry.GetValue...ToString()fonctionne comme prévu.
gravité
3

Je ne serais pas trop préoccupé par la performance, si cette opération était effectuée ne serait-ce que quelques milliers de fois par seconde - il n'y a pas de différence tangible.

Je serais cependant préoccupé de "connaître" l'entrée. Vous avez une méthode qui accepte un Objectet vous devez la traiter comme telle, c'est-à-dire que vous ne devez rien savoir du paramètre, à part qu'elle adhère à l' Objectinterface, qui se trouve avoir une toString()méthode. Dans ce cas, je suggère fortement d'utiliser cette méthode au lieu de simplement supposer quoi que ce soit.

OTOH, si l'entrée est toujours l' un Stringou l' autre ou null, changez simplement la méthode pour accepter Strings et vérifiez explicitement nulls (ce que vous devriez faire de toute façon lorsque vous traitez avec des non-primitives ...)

Henrik Paul
la source
J'ai dit que ma question n'a pas de sens valable :) Je suis juste curieux de savoir ce qui est théoriquement moins cher. Mais merci quand même
Vugluskr
Le coût dépendra de l'efficacité de la machine virtuelle lors des appels de méthode virtuelle par rapport à la vérification de type. C'est spécifique à la mise en œuvre.
Jon Skeet
2

Étant donné que le type de référence est un objet et que tous les objets ont un toString (), appelez simplement object.toString (). String.toString () renvoie simplement ceci.

  • toString () est moins de code à taper.
  • toString () est moins de bytecode.
  • le casting est une opération coûteuse VS un appel polymorphe.
  • le casting pourrait échouer.
  • Utilisez String.valueOf (object) qui appelle simplement object.toString () s'il n'est pas nul.
mP.
la source
1

Si ce que vous avez dans "o" est une chaîne, alors il n'y a pas beaucoup de différence (probablement la distribution est plus rapide, mais c'est une implémentation VM / Library).

Si "o" n'est peut-être pas une chaîne, mais qu'il est supposé être une chaîne, alors le cast est ce que vous voulez (mais vous devez faire en sorte que la méthode prenne une chaîne au lieu d'un objet).

Si "o" peut être de n'importe quel type, vous devez utiliser le toString - mais assurez-vous de vérifier d'abord la valeur null.

void foo(final Object o)
{
    final String str;

    // without this you would get a class cast exception
    // be wary of using instanceof though - it is usually the wrong thing to do
    if(o instanceof String)
    {
        str = (String)o;
    }    
}

ou

void foo(final Object o)
{
    final String str;

    // if you are 100% sure that o is not null then you can get rid of the else
    if(o != null)
    {
        str = o.toString();
    }
}

Je préfère coder le dernier comme:

void foo(final Object o)
{
    final String str;

    if(o == null)
    {
        throw new IllegalArgumentException("o cannot be null");
    }

    str = o.toString();
}
TofuBière
la source
Les 2 premiers extraits ne seront pas vraiment compilés (la finalvariable n'a peut-être pas été initialisée). Vous avez besoin d'un elsequi lèvera une exception ou s'initialisera strà quelque chose.
Bruno Reis le
1

J'ai trouvé bizarrement que la distribution était plus lente que la recherche de vtable impliquée par l'appel tostring.

Joshua
la source
1

Il ne peut pas y avoir de «chaîne nulle dans o». Si o est nul, il ne contient pas de chaîne nulle, il est simplement nul. Vérifiez d'abord o pour null. Si vous lancez ou ToString d'appel () sur null vous tomber en panne.

Ed S.
la source
2
La diffusion de null ne plantera pas. Il ne lancera même pas une NullPointerException, il appellera simplement null au nouveau type. :)
Bombe