web-dev-qa-db-fra.com

Pourquoi le type de données de votre instruction switch ne peut-il pas être long, Java?

Voici un extrait de Sun's Java tutorials :

Un commutateur fonctionne avec les types de données primitifs byte, short, char et int. Il fonctionne également avec les types énumérés (abordés dans les classes et l'héritage) et quelques classes spéciales qui "encapsulent" certains types primitifs: Character, Byte, Short et Integer (discuté dans Simple Data Objects).

Il doit y avoir une bonne raison pour laquelle le type de données primitif long n'est pas autorisé. Quelqu'un sait-il ce que c'est?

74
Fostah

Je pense que dans une certaine mesure, il s'agissait probablement d'une décision arbitraire basée sur l'utilisation typique d'un commutateur.

Un commutateur peut essentiellement être implémenté de deux manières (ou en principe, une combinaison): pour un petit nombre de cas, ou ceux dont les valeurs sont largement dispersées, un commutateur devient essentiellement l'équivalent d'une série d'if sur une variable temporaire (le la valeur activée ne doit être évaluée qu'une seule fois). Pour un nombre modéré de cas dont la valeur est plus ou moins consécutive, une table de commutation est utilisée (l'instruction TABLESWITCH en Java), où l'emplacement vers lequel sauter est effectivement recherché dans une table.

L'une ou l'autre de ces méthodes pourrait en principe utiliser une valeur longue plutôt qu'un entier. Mais je pense que ce n'était probablement qu'une décision pratique pour équilibrer la complexité du jeu d'instructions et du compilateur avec les besoins réels: les cas où vous avez vraiment besoin de basculer sur une longue sont suffisamment rares pour qu'il soit acceptable d'avoir à réécrire en tant que série d'instructions IF, ou contournez d'une autre manière (si les valeurs longues en question sont proches les unes des autres, vous pouvez dans votre Java basculer le résultat int de soustraire la valeur la plus faible).

46
Neil Coffey

Parce qu'ils n'ont pas implémenté les instructions nécessaires dans le bytecode et que vous vraiment ne voulez pas écrire autant de cas, peu importe le niveau de "production prêt" votre code est ...

[EDIT: extrait des commentaires sur cette réponse, avec quelques ajouts en arrière-plan]

Pour être exact, 2³² est un lot de cas et tout programme avec une méthode suffisamment longue pour contenir plus que cela va être tout à fait horrible! Dans n'importe quelle langue. (La fonction la plus longue que je connaisse dans n'importe quel code dans n'importe quelle langue est un peu plus de 6k SLOC - oui, c'est un gros switch - et c'est vraiment ingérable.) Si vous êtes vraiment coincé avec un long où vous ne devriez avoir qu'un int ou moins, alors vous avez deux vraies alternatives.

  1. Utilisez une variante sur le thème des fonctions de hachage pour compresser le long en int. Le plus simple, à utiliser uniquement lorsque vous avez un mauvais type, est de simplement lancer! Il serait plus utile de le faire:

    (int) ((x&0xFFFFFFFF) ^ ((x >>> 32) & 0xFFFFFFFF))
    

    avant d'activer le résultat. Vous devrez également déterminer comment transformer les cas que vous testez. Mais vraiment, c'est toujours horrible car cela ne résout pas le vrai problème de beaucoup de cas.

  2. Une bien meilleure solution si vous travaillez avec un très grand nombre de cas est de changer votre conception en utilisant un Map<Long,Runnable> ou quelque chose de similaire pour rechercher comment répartir une valeur particulière. Cela vous permet de séparer les cas en plusieurs fichiers, ce qui est beaucoup plus facile à gérer lorsque le nombre de cas devient volumineux, bien qu'il soit plus complexe d'organiser l'enregistrement de l'hôte des classes d'implémentation impliquées (les annotations peuvent vous aider en vous permettant de construire le code d'enregistrement automatiquement).

    FWIW, je l'ai fait il y a de nombreuses années (nous sommes passés au J2SE 1.2 nouvellement sorti en cours de projet) lors de la construction d'un moteur de bytecode personnalisé pour simuler du matériel massivement parallèle (non, la réutilisation de la JVM n'aurait pas été appropriée en raison de la radicalité différents modèles de valeur et d'exécution impliqués) et cela a énormément simplifié le code par rapport au grand switch que la version C du code utilisait.

Pour réitérer le message à retenir, vouloir switch sur un long est une indication que vous avez les mauvais types dans votre programme ou que vous construisez un système avec autant variation impliquée que vous devriez utiliser des classes. Il est temps de repenser dans les deux cas.

19
Donal Fellows

Parce que l'index de la table de recherche doit être de 32 bits.

4
JRL