Pourquoi Java String n'a-t-il pas de méthodes de manipulation de chaînes statiques?

17

Pourquoi les concepteurs Java n'ont-ils pas créé des versions statiques des méthodes de manipulation de chaînes dans la java.lang.Stringclasse? Je fais référence aux méthodes suivantes, mais la question peut également être étendue à d'autres méthodes non statiques de la classe.

concat(String)                        substring(int, int)
replace(char, char)                   toLowerCase()
replace(CharSequence, CharSequence)   toLowerCase(Locale)
replaceAll(String, String)            toString()
replaceFirst(String, String)          toUpperCase()
split(String)                         toUpperCase(Locale)
split(String, int)                    trim()
substring(int)

Le fait de n'avoir que des versions non statiques de ces méthodes force une vérification nulle explicite partout où une telle méthode doit être appelée. Par exemple, un simple appel example = example.trim()entraînerait NullPointerException if String example = null. Le programmeur doit donc effectuer la vérification nulle du passe-partout suivante:

if (example != null)
    example = example.trim();
// OR:
example = (example==null) ? null : example.trim();
example = (example==null) ? null : example.substring(5);

J'imagine qu'il aurait été beaucoup plus pratique d' Stringavoir eu des versions statiques de ces méthodes (peut-être même exclusivement ), qui prendraient la chaîne d'entrée comme premier argument:

example = String.trim(example);
example = String.replace(example, 'a', 'b');
example = String.substring(example, 5);

Cela aurait conduit à un code plus propre écrit par les programmeurs qui aurait automatiquement pris en charge les cas nuls en renvoyant simplement null, plutôt que de forcer les programmeurs à gérer explicitement les cas nuls. Le retour de null a du sens pour moi, car la manipulation d'une chaîne nulle devrait entraîner une chaîne nulle , pas une erreur.

Pourquoi les concepteurs Java n'ont-ils pas pensé à cela lorsqu'ils ont conçu la Stringclasse en Java 1 ou Java 2, ou même ajouté une telle fonctionnalité dans une version Java ultérieure?

ADTC
la source
17
Je suggérerais de remplacer "Pourquoi les concepteurs Java n'ont-ils pas pensé à X" par "Pourquoi les concepteurs Java ont-ils décidé contre X". Donnez-leur le mérite de ne pas être aveugle à l'option.
Avner Shahar-Kashtan
5
nullest un état exceptionnel et doit être traité explicitement.
CodesInChaos
2
@KonradMorawski: Personnellement, je trouve que c'est une mauvaise utilisation grossière des méthodes d'extension. Si vous avez une valeur nulle, que diable faites-vous en train d'appeler des méthodes dessus, vous allez simplement confondre tous ceux qui lisent ce code. C'est une mauvaise réimplémentation d'un Maybe<T>type, je suppose?
Phoshi
1
@Phoshi, il faut garder à l'esprit que les méthodes d'extension ne sont PAS de vraies méthodes, elles sont juste du sucre de syntaxe. Mais je conviens que c'est controversé. Je souhaite que C # / Java offre une sorte de sécurité nulle syntaxique intégrée, comme - disons - Kotlin. string name = employee?.personalData?.name. Tout comme un raccourci pour tous ces if (employee != null)s répétitifs . Question SO connexe: stackoverflow.com/questions/1196031/…
Konrad Morawski
2
@ADTC Erm, vous vous rendez compte qu'un programme ne peut pas prédire à l'avance qu'une valeur est nulle, non? - Vous devez définir les contrats entre vos interfaces d'une manière dont vous pouvez être sûr si une valeur peut être nulle ou non. Une vérification nulle partout signifie que vous avez un problème de conception de programme.
Uooo

Réponses:

30

Le retour de null a du sens pour moi, car la manipulation d'une chaîne nulle devrait entraîner une chaîne nulle, pas une erreur

Eh bien, c'est votre opinion. D'autres peuvent argumenter que les opérations String sur un objet nul, qui ne contient pas de chaîne, n'ont aucun sens et devraient donc lever une exception

Il est difficile de savoir pourquoi les «concepteurs Java» ont fait ou non quelque chose.

Il existe déjà des bibliothèques qui peuvent effectuer des opérations String sans danger, par exemple StringUtils d'Apache Commons. Vous pouvez utiliser cela ou des bibliothèques similaires si vous en avez besoin.


Ajout basé sur vos commentaires

En lisant les commentaires, il semble que le vrai problème auquel vous êtes confronté est que vous devez vérifier nullpartout votre code. Cela peut être un indicateur d'une mauvaise conception de programme sans contrats clairement définis entre les interfaces. Vous voudrez peut-être lire Éviter les instructions «! = Null» en Java?

Uooo
la source
1
Merci pour vos commentaires. Je suppose que la vraie question est, pourquoi devons-nous dépendre d'une bibliothèque externe ou de classes maison quand une telle fonctionnalité de base peut être intégrée à Java standard?
ADTC
4
@ADTC posons la question dans l'autre sens: pourquoi les "concepteurs Java" devraient-ils inclure quelque chose dans le langage, s'il y a déjà beaucoup de bonnes bibliothèques, bien testées et documentées? La façon de définir une «fonction de base» est basée sur l'opinion. La plupart des projets n'ont-ils pas besoin d'une bibliothèque externe pour les "fonctionnalités de base" (test unitaire, simulation, date et heure, ...)? Ce n'est pas grave, n'est-ce pas?
Uooo
Une façon de gérer les valeurs nulles consiste à utiliser Guava Optional- code.google.com/p/guava-libraries/wiki/…
Konrad Morawski
10

IMO l'approche "if arg is null return null" des méthodes d'écriture augmente inutilement la complexité cyclomatique de votre programme.

Les premières bibliothèques Java utilisaient l'approche return null, mais les gars JDK se gardaient toujours de null avec des exceptions.

Avec le temps, je pense que cette dernière approche est apparue comme le gagnant clair.

Pourquoi? Puisque les champs nuls cassent beaucoup de principes oo. Vous ne pouvez tout simplement pas les traiter comme des membres d'une classe polymorphe. Cela signifie que vous devez toujours coder des cas spéciaux pour null, et donc votre complexité cyclomatique monte en flèche lorsque vous devez supposer que les choses peuvent être nulles.

Afin de résoudre vos problèmes, envisagez d'utiliser le modèle d'objet nul au lieu de vous fier aux champs nuls.

Alexander Torstling
la source
2
Mais Stringn'est-ce pas polymorphe, non? Et comment utilisez-vous le modèle d'objet nul pour un type déjà existant comme String?
svick
La chaîne n'est pas polymorphe, non. Mais même ainsi, vous souhaitez savoir que vous pouvez appeler des méthodes d'instance sur n'importe quelle référence de chaîne que vous avez. Cela fonctionne pour toutes les références non nulles. La chaîne a déjà un objet nul: la chaîne vide. Tout comme les listes ont la liste vide. Alors demandez-vous pourquoi la chaîne vide ne suffit pas dans votre cas. Je suppose que vous utilisez une chaîne nulle pour signaler un cas spécial. Demandez-vous si vous pouvez utiliser un drapeau distinct pour ce cas particulier.
Alexander Torstling
@AlexanderTorstling: Un champ de type par intdéfaut est zéro plutôt que null. Conceptuellement, il devrait être possible d'avoir un stringtype dont la valeur par défaut serait une chaîne vide plutôt que null[un tel type pourrait sémantiquement être vers Stringce qui intdoit être Integer]. Le fait qu'un non-vide stringcontienne en interne une référence à un objet tas serait un détail d'implémentation; il n'y a aucune raison qu'il ne puisse pas se comporter sémantiquement comme une primitive.
supercat
@supercat: d'accord. Je pense qu'il aurait été préférable d'interdire les valeurs nulles pour les références à moins qu'elles ne soient explicitement activées. Champs par défaut non nuls et finaux. De nombreux types ont déjà des objets à comportement nul
Alexander Torstling
@AlexanderTorstling: Avoir des emplacements de stockage de tous les types par défaut à tous les octets-zéro, et fournir des types de structure pouvant être attribués via une copie à tous les octets, simplifie considérablement un cadre, mais implique à peu près que les types avec une sémantique de référence mutable doivent être définis par défaut sur nul. Il aurait cependant été utile d'avoir une prise en charge du cadre pour les types de valeur qui encapsuleraient une référence unique et "encadreraient" ce type de référence - et pourraient le décompresser .
supercat
3

Cela ne veut pas dire que c'est la raison, mais à l'exception de toString, toutes ces méthodes sont facilement encapsulées dans une classe d'assistance statique, tandis que l'inverse n'est pas vrai.

C'est-à-dire si vous voulez Stings.toUpper (entrée de chaîne), le code pour cela est facile à écrire, mais si vous voulez instance.toUpper et tout ce que vous avez est String.toUpper, eh bien, c'est impossible ... à moins qu'ils n'introduisent des méthodes d'extension, ce qui n'était probablement pas envisagé à l'époque.

jmoreno
la source
Bon point, bien que plus d'un commentaire qu'une réponse. Mais même compte tenu de cela, pourquoi devons-nous dépendre d'une bibliothèque externe ou de classes maison quand une telle fonctionnalité de base peut être intégrée à Java standard?
ADTC
2
Pour l'instant, vous avez String.format(statique), mais vous ne pouvez pas "something %s".format(id).
Konrad Morawski
@adtc: car ce n'est pas une fonctionnalité de base du langage de le faire via une classe statique. À partir de cette prémisse, il existe de nombreuses raisons de ne pas le faire - code inutile / surcharge de code, fonctionnalité en double, coût de développement / maintenance.
jmoreno
-2

En java, cette chaîne est un objet. C'est un choix de conception.

Les références d'objets peuvent être nulles et sont nulles si aucun objet ne leur est affecté. Si vous appelez un tel objet, une NullPointerException est levée. C'est un oo-comportement standard.

Les concepteurs Java ont fait le choix d'avoir des chaînes comme objet et de disposer de ces méthodes pour lancer des exceptions de pointeur nul, c'est ce que vous obtenez si vous voulez que les chaînes soient des objets.

Pourquoi les concepteurs Java n'ont-ils pas pensé à cela lorsqu'ils ont conçu la classe String en Java 1 ou Java 2, ou même ajouté une telle fonctionnalité dans une version Java ultérieure?

Ils y ont probablement réfléchi et ont choisi d'incorporer un oo-comportement.

Pieter B
la source
Puis-je savoir, comment crée des méthodes statiques pour prendre en charge les cas nuls et non le comportement OO ? Pour être clair, je ne dis pas que c'est le cas, mais j'essaie de comprendre pourquoi vous dites que la décision de conception est d'incorporer le comportement OO.
ADTC
Les méthodes statiques ressemblent plus à des fonctions. Et pour l'usage que vous voulez, ils ne devraient même pas faire partie de la classe de chaînes plutôt faire partie d'une classe d'utilité. Tout comme les fonctions de classe de mathématiques.
Pieter B
4
Ce n'est pas parce que les chaînes sont des objets que la classe String ne peut pas avoir de méthodes statiques. Et en effet, il en a déjà, par exemple. String.format. (Pareil en C #, d'ailleurs). Donc, si c'est un choix de conception, cela ne peut pas venir uniquement du fait que les chaînes sont des objets, et ce n'est pas appliqué de manière cohérente.
Konrad Morawski
@PieterB Je ne me plaindrais pas si au moins de telles méthodes étaient fournies dans une Stringsclasse utilitaire, comme nous avons la Arraysclasse utilitaire ( bien que je comprenne qu'elle a été créée par pure nécessité en raison des tableaux étant une sorte de croisement étrange entre les primitives et les objets: ) ) .. tant qu'il faisait partie de Java standard et ne nécessitait pas de dépendances.
ADTC