Java >> Tutoriel Java >  >> Tag >> String

Soyez prudent avec la méthode Substring de String en Java

De temps en temps, je rencontre une bibliothèque bien établie dans un langage de programmation qui a ses bizarreries. En tant qu'instructeur, je dois m'assurer que je suis conscient de ces bizarreries lorsque j'enseigne. Par exemple, la dernière fois, j'ai parlé un peu des différentes méthodes de saisie du scanner et du fait qu'elles ne se comportent pas toutes de la même manière. Eh bien aujourd'hui, je veux parler de la méthode substring de la bibliothèque String de Java.

Documents

Lorsque j'utilise une bibliothèque pour la première fois, je trouve utile de consulter la documentation. Mais avec une bibliothèque aussi établie, il est parfois idiot de fouiller dans la documentation. Après tout, de nombreux langages prennent en charge les chaînes. Personnellement, tout ce que j'ai besoin de savoir, c'est le nom de la commande avant de pouvoir comprendre le reste.

Cependant, de temps en temps, je tombe sur une fonction moins intuitive que je ne le pensais. Dans ce cas, je parle de la méthode de sous-chaîne de Java. Comme vous pouvez probablement l'imaginer, il récupère une sous-chaîne d'une chaîne et la renvoie. Alors, quel est le problème ?

Eh bien, pour commencer, la méthode substring est en fait une méthode surchargée. Par conséquent, il existe deux formes différentes de la même méthode dans la documentation. Jetez un œil :

public String substring(int beginIndex)

~

Renvoie une nouvelle chaîne qui est une sous-chaîne de cette chaîne. La sous-chaîne commence par le caractère à l'index spécifié et s'étend jusqu'à la fin de cette chaîne.

API Java, 2019

public String substring(int beginIndex, int endIndex)

~

Renvoie une nouvelle chaîne qui est une sous-chaîne de cette chaîne. La sous-chaîne commence au beginIndex spécifié et s'étend jusqu'au caractère à l'index endIndex - 1 . Ainsi, la longueur de la sous-chaîne est endIndex-beginIndex .

API Java, 2019

À ce stade, ne vous concentrez pas trop sur leurs descriptions car nous y reviendrons. Sachez simplement qu'il existe deux versions différentes de la même méthode.

Utilisation

À ce stade, j'aimerais prendre un moment pour montrer comment utiliser la méthode de sous-chaîne. Si c'est la première fois que vous explorez l'API Java, ce serait le bon moment pour suivre.

Tout d'abord, notez que l'en-tête de méthode ne fait pas contenir le statique mot-clé. En d'autres termes, la sous-chaîne est une méthode d'instance qui a du sens. Nous avons besoin d'une instance d'une chaîne pour obtenir une sous-chaîne :

String str = "Hello, World!";
String subOne = str.substring(7);
String subTwo = str.substring(0, 5);

Dans cet exemple, nous avons créé deux nouvelles sous-chaînes :une de la position 7 à la fin et l'autre de la position 0 à la position 5. Sans consulter la documentation, pouvez-vous déterminer quelles seront les chaînes résultantes ?

Notation d'intervalle

Avant de donner la réponse, je pense qu'il est important de discuter de la terminologie des mathématiques. En particulier, j'aimerais parler un peu de la notation par intervalles.

Dans la notation d'intervalle, le but est d'indiquer explicitement la plage d'un sous-ensemble. Par exemple, nous pouvons être intéressés par tous les entiers supérieurs à 0. En notation d'intervalle, cela ressemblerait à :

(0, +∞)

Dans cet exemple, nous avons choisi d'exclure la valeur de 0 dans la plage à l'aide de parenthèses. On aurait pu tout aussi bien définir l'intervalle commençant par 1 - attention aux parenthèses :

[1, +∞)

Dans les deux cas, nous décrivons le même ensemble :tous les entiers supérieurs à 0.

Alors, comment cela est-il lié à la méthode de sous-chaîne ? Il s'avère qu'une sous-chaîne est un sous-ensemble d'une chaîne, nous pouvons donc utiliser la notation d'intervalle pour définir notre sous-chaîne. Pourquoi ne pas essayer quelques exemples ? Étant donné "Hello, World !", déterminez la sous-chaîne en utilisant les intervalles suivants :

  • [0, 2]
  • (0, 5]
  • (1, 3)
  • (-1, 7]

Une fois que vous avez terminé, consultez les réponses ci-dessous :

  • "Hel"
  • "bonjour",
  • "l"
  • "Bonjour, W"

Nous devrons garder cette idée en tête pour aller de l'avant.

La vérité

La vérité est que la méthode de sous-chaîne est un peu bizarre. D'une part, nous pouvons utiliser un seul index pour spécifier le point de départ de notre nouvelle sous-chaîne. D'autre part, nous pouvons utiliser deux indices pour saisir un sous-ensemble arbitraire d'une chaîne.

Cependant, dans la pratique, je trouve que la deuxième option pose beaucoup de problèmes aux étudiants, et je ne les blâme pas. Après tout, les limites sont trompeuses. Par exemple, revoyons un peu de code ci-dessus :

String str = "Hello, World!";
String subOne = str.substring(7);
String subTwo = str.substring(0, 5);

Ici, nous pouvons prédire avec confiance que subOne a une valeur de "Monde!", Et nous aurions raison. Après tout, l'index 7 est 'W', la méthode saisit automatiquement le reste de la chaîne.

Quant à subTwo, nous devinerions probablement "Bonjour", et nous serions incorrects. C'est en fait "Bonjour" car l'index de fin est exclusif (c'est-à-dire [0, 5) ). Dans la section suivante, nous verrons pourquoi et ce que je ressens à ce sujet.

Mon avis

D'après ce que j'ai compris, le modèle inclusif/exclusif est la norme pour les plages de l'API Java. Cela dit, je remets parfois en question le choix de conception.

D'une part, il y a l'avantage de pouvoir utiliser la longueur de la chaîne comme point final de la sous-chaîne :

String jokerQuote = "Madness, as you know, is like gravity, all it takes is a little push.";
String newtonTheory = jokerQuote.substring(30, jokerQuote.length());

Mais, est-ce vraiment nécessaire ? Java fournit déjà une surcharge à la méthode substring qui capture exactement ce comportement.

Cela dit, il existe une belle explication mathématique à cette notation, et une partie de celle-ci a à voir avec la différence entre les points de départ et d'arrivée. En particulier, nous obtenons la longueur de la nouvelle sous-chaîne :

int length = endIndex - startIndex;

De plus, cette notation particulière permet aux sous-chaînes adjacentes de partager un point médian :

String s = "Luck is great, but most of life is hard work.";
String whole = s.substring(0, s.length()/2) + s.substring(s.length()/2, s.length());

Ces deux propriétés sont agréables, mais je pense qu'elles sont probablement un sous-produit de l'indexation par zéro (perpétuée par Dijkstra) qui n'est pas si intuitive Soit. Et pour ceux d'entre vous qui vont s'opposer à ce commentaire, sachez que je suis tout à fait pour l'indexation par zéro et cette convention de sous-ensemble inclusif/exclusif.

Tout ce que j'essaie de dire, c'est que j'ai vu mes propres étudiants trébucher sur les deux conventions, donc je ressens pour eux d'une certaine manière. C'est pourquoi je me suis donné tant de mal pour écrire cet article en premier lieu.

Faites-moi savoir si vous ressentez la même chose ou si je suis totalement hors de propos. Sinon, merci d'avoir pris le temps de lire mon travail. J'espère que ça vous a plu !


Balise Java