Maison  >  Article  >  Java  >  Amélioration Java (treize) -----Chaîne

Amélioration Java (treize) -----Chaîne

黄舟
黄舟original
2017-02-10 11:22:301117parcourir

Il peut être prouvé que l'opération sur chaîne est le comportement le plus courant en programmation informatique.


1. Chaîne

Tout d'abord, nous devons préciser que String n'est pas un type de données de base, mais un objet, et c'est un objet immuable. En regardant le code source, vous constaterez que la classe String est finale (bien sûr, elle ne peut pas être héritée), et en consultant la documentation du JDK, vous constaterez que presque chaque opération qui modifie un objet String crée en fait un nouvel objet String. .

La chaîne est un objet, donc avant initialisation, sa valeur est nulle Il faut mentionner "", null, new String() ici La différence. entre les trois. null signifie que la chaîne n'est pas encore nouvelle, ce qui signifie que la référence à l'objet n'a pas encore été créée et qu'aucun espace mémoire ne lui a été alloué. Cependant, "" et new String() indiquent qu'elle est nouvelle. , mais il est vide en interne, mais il a été créé. Une référence à un objet nécessite une allocation d'espace mémoire. Par exemple : un verre vide, tu ne peux pas dire qu'il n'y a rien dedans, car il y a de l'air à l'intérieur, bien sûr tu peux aussi en faire un vide, nul et " ", New String () est la même chose que le vide et l'air.

Il y a un endroit très spécial dans la chaîne, c'est-à-dire le pool de cordes. Chaque fois nous créons un objet chaîne, nous vérifions d'abord s'il existe une chaîne avec une valeur nominale égale dans le pool de chaînes. S'il y en a, il ne la créera pas et remettra directement la référence à l'objet dans le pool de chaînes. Créez-le, puis placez-le dans le pool de chaînes et renvoyez une référence à l'objet nouvellement créé. Ce mécanisme est très utile car il peut améliorer l'efficacité et réduire l'utilisation de l'espace mémoire. Par conséquent, il est recommandé d'utiliser l'affectation directe (c'est-à-dire lors de l'utilisation de chaînes). ). String s="aa"), un nouvel objet String (c'est-à-dire String s = nouvelle chaîne ("aa")).

L'utilisation des ficelles n'est rien de plus que ces aspects :

1. Comparaison de chaînes

   equals() ------ Déterminez si le contenu est le même.

      compareTo() ------ Déterminez la relation de taille des chaînes.

       compareToIgnoreCase(String int) ------Ignorer la casse des lettres lors de la comparaison.

                                                                                                                                                              

equalsIgnoreCase() ------ Déterminez si le contenu est le même tout en ignorant la casse.

ReagionMatches () ----------------------------- --------- veuillez vous référer à l'API pour plus de détails.

2. Recherche de chaîne

charAt(int index ) ------Renvoie le caractère à la position d'index spécifiée, la plage d'index commence à 0.

                                                                                                                                                         .

Indexof (String Str, int FROMINDEX -----------------------); ----------------------------------- commencez à récupérer STR à partir du caractère FROMINDEX de la chaîne.

                                                                                                                          lastIndexOf(String str)------Trouver la position de la dernière occurrence.

                                                                                                                                                                                   .

starWith(String prefix, int toffset)-----Test si la sous-chaîne de cette chaîne à partir de l'index spécifié commence par le préfixe spécifié.

starWith(String prefix)------Testez si cette chaîne commence par le préfixe spécifié.

                endsWith(Suffixe de chaîne)------Testez si cette chaîne se termine par le suffixe spécifié.

3. Interception de chaînes

public String subString(int BeginIndex)------Renvoie une nouvelle chaîne, qui est une sous-chaîne de cette chaîne.

public String subString(int BeginIndex, int EndIndex)------La chaîne renvoyée est une chaîne commençant par BeginIndex jusqu'à EndIndex-1.

4. Remplacement de chaîne

remplacement de chaîne publique (char oldChar, char newChar).

public String replace (CharSequence target, CharSequence replacement)------Remplacez la sous-séquence etarget d'origine par la séquence de remplacement et renvoyez une nouvelle chaîne.

    public String replaceAll (String regex, String replacement)------Utilisez des expressions régulières pour faire correspondre les chaînes. Notez que le premier paramètre de replaceAll est une expression régulière et j'en ai beaucoup souffert.

5. Pour plus de méthodes, veuillez vous référer à l'API


2. StringBuffer

StringBuffer et Strings sont tous utilisés pour stocker des chaînes, mais en raison de leurs implémentations internes différentes, les plages qu'ils utilisent sont différentes. Pour StringBuffer, lorsqu'il traite une chaîne, s'il la modifie, il ne génère pas de nouvel objet chaîne. , c'est donc mieux que String en termes d'utilisation de la mémoire.

En fait, de nombreuses méthodes de StringBuffer sont similaires à celles de la classe String, et les fonctions qu'elles représentent sont presque exactement les mêmes, sauf que StringBuffer se modifie lorsqu'il est modifié. , tandis que la classe String génère un nouvel objet, ce qui constitue la plus grande différence entre eux.

En même temps, StringBuffer ne peut pas être initialisé en utilisant =. Il doit générer une instance StringBuffer, ce qui signifie que vous devez l'initialiser via sa méthode de construction.

En termes d'utilisation de StringBuffer, il se concentre davantage sur les modifications apportées aux chaînes, telles que l'ajout, la modification et la suppression. Les méthodes correspondantes sont : <.>

 1. append() : ajoute le contenu spécifié à la fin de l'objet StringBuffer actuel, similaire à la connexion de chaînes, où le contenu de l'objet StringBuffer changera.

2. insert : Cette méthode insère principalement du contenu dans l'objet StringBuffer.

3. delete : Cette méthode est principalement utilisée pour supprimer le contenu de l'objet StringBuffer.


3. StringBuilder

StringBuilder est également un objet chaîne mutable La différence avec. StringBuffer est qu'il n'est pas sécurisé pour les threads. Sur cette base, sa vitesse est généralement plus rapide que StringBuffer. Comme StringBuffer, les principales opérations de StringBuider sont également les méthodes append et insert. Les deux méthodes convertissent efficacement les données données en chaîne, puis ajoutent ou insèrent les caractères de cette chaîne dans le générateur de chaînes.

Ce qui précède présente simplement String, StringBuffer et StringBuilder. En fait, pour ces trois-là, nous devrions prêter plus d'attention aux différences qu'ils ne voient que. en clarifiant la différence entre eux, vous pouvez mieux les utiliser.


  4. Utilisez String, StringBuffer, correctement StringBuilder

Regardons d'abord le tableau suivant :



Je ne sais pas très bien si String est thread-safe ici. La raison : String l'est. immuable, donc tout Il est impossible de modifier sa valeur par n'importe quelle opération. Il est difficile de dire s'il existe une sécurité des threads ? Mais si vous insistez sur la sécurité des fils de discussion, parce que le contenu est immuable, il est toujours sûr.

En termes d'utilisation, puisque String doit générer un nouvel objet à chaque fois qu'il est modifié, il est préférable de choisir StringBuffer ou StringBuilder pour les chaînes qui ont souvent besoin pour modifier leur contenu. Pour StringBuffer, chaque opération est effectuée sur l'objet StringBuffer lui-même et ne génère pas de nouveaux objets. Par conséquent, StringBuffer est particulièrement adapté aux situations où le contenu de la chaîne change fréquemment.

Mais toutes les opérations sur les chaînes String ne seront pas plus lentes que StringBuffer. Dans certains cas particuliers, la concaténation des chaînes String sera analysée par la JVM dans l'épissage d'objets StringBuilder. , dans ce cas, String est plus rapide que StringBuffer. Tels que :

String name = ”I ” ” suis ” ” chenssy ” ;

StringBuffer name = new StringBuffer(”I ”).append(” am ”).append(” chenssy ”);

Pour ces deux méthodes, Vous constaterez que la première méthode est beaucoup plus rapide que la deuxième méthode et que l'avantage de StringBuffer est ici perdu. La vraie raison est que la JVM a fait quelques optimisations. En fait, String name = "I" "am" "chenssy"; aux yeux de la JVM, c'est String name = "I am chenssy"; cette méthode est vraiment efficace. Cela ne prend pas de temps. Mais si nous y ajoutons un objet String, la JVM construira l'objet String conformément à la spécification d'origine.

Les scénarios dans lesquels ces trois sont utilisés sont résumés comme suit (référence : "Writing Quality Code : 151 Suggestions for Improving Java Programs") :

1, String : Vous pouvez utiliser la classe String dans la scène où la chaîne n'est pas souvent modifiée, comme : une déclaration de constante, une petite quantité d'opérations variables, etc.

2. StringBuffer : Si vous effectuez fréquemment des opérations de chaîne (épissage, remplacement, suppression, etc.) et exécutez dans un environnement multithread, vous pouvez envisager Utilisez StringBuffer, comme l'analyse XML, l'analyse et l'encapsulation des paramètres HTTP, etc.

3. StringBuilder : si vous effectuez fréquemment des opérations sur les chaînes (épissage, remplacement, suppression, etc.) et que vous les exécutez dans un environnement multithread, vous pouvez envisager Utilisez StringBuffer, comme l'assemblage d'instructions SQL, l'encapsulation JSON, etc. (il semble que j'utilise également |StringBuffer pour ces deux-là).

Pour plus d'informations sur les différences entre eux, veuillez vous référer à : http://www.php.cn/. Je n’ajouterai pas de bruit inutile et inutile.

 5. Méthode d'épissage des cordes

Pour les chaînes, nous avons souvent besoin de les assembler. Trois méthodes d'assemblage ont été ajoutées en Java : les méthodes , concat() et append(). Quelle est la différence entre ces trois ? Regardez d'abord l'exemple suivant :

public class StringTest {
    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void
     */
    public static void main(String[] args) {
        //+
        long start_01 = System.currentTimeMillis();
        String a = "a";
        for(int i = 0 ; i < 100000 ; i++){
            a += "b";
        }
        long end_01 = System.currentTimeMillis();
        System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫米");
        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = "c";
        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat("d");
        }
        long end_02 = System.currentTimeMillis();
        System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫米");
        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer("e");
        for(int i = 0 ; i < 100000 ; i++){
            e.append("d");
        }
        long end_03 = System.currentTimeMillis();
        System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫米");
    }
}

------------
Output:
  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米



public class StringTest {    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void     */
    public static void main(String[] args) {        //+
        long start_01 = System.currentTimeMillis();
        String a = "a";        for(int i = 0 ; i < 100000 ; i++){
            a += "b";
        }        long end_01 = System.currentTimeMillis();
        System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫米");        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = "c";        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat("d");
        }        long end_02 = System.currentTimeMillis();
        System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫米");        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer("e");        for(int i = 0 ; i < 100000 ; i++){
            e.append("d");
        }        long end_03 = System.currentTimeMillis();
        System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫米");
    }
}------------Output:  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米

Il ressort des résultats d'exécution ci-dessus que append() est le plus rapide, suivi de concat() et est le plus lent. Veuillez consulter la répartition ci-dessous pour les raisons :


                                                                                                                                          🎜>

Nous savons plus tôt que le compilateur l'a optimisé. Il utilise la méthode append() de StringBuilder pour le traiter. Nous savons que StringBuilder est plus rapide que StringBuffer, mais pourquoi fonctionne-t-il toujours à la même vitesse ? Principalement parce que le compilateur utilise la méthode append() pour l'ajouter et le convertir en chaîne String avec toString(). En d'autres termes, str = "b" équivaut à

 str = new StringBuilder(str).append("b").toString();

                                                                  et toString(), 100 000 objets StringBuilder sont créés ici, et ils doivent être convertis en String à chaque fois. N'est-ce pas lent ?

(2) méthode concat() pour épisser des chaînes

 

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    char buf[] = new char[count + otherLen];
    getChars(0, count, buf, 0);
    str.getChars(0, otherLen, buf, count);
    return new String(0, count + otherLen, buf);
    }


Ceci est le code source de concat() , cela ressemble à une copie numérique. Nous savons que le traitement du tableau est très rapide, mais comme la méthode se termine comme ceci : return new String(0, count otherLen, buf); cause profonde de sa lenteur.


(3) méthode append() pour épisser des chaînes

public synchronized StringBuffer append(String str) {    super.append(str);        return this;
    }
La méthode append() de StringBuffer consiste à utiliser directement la méthode append() de la classe parent AbstractStringBuilder Le code source de ceci. La méthode est la suivante :

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
        int len = str.length();
    if (len == 0) return this;
    int newCount = count + len;
    if (newCount > value.length)
        expandCapacity(newCount);
    str.getChars(0, len, value, count);
    count = newCount;
    return this;
    }
Le tableau est traité, allongé , puis copié, mais veuillez noter qu'il ne renvoie pas une nouvelle chaîne à la fin, mais se renvoie lui-même. En d'autres termes, au cours de cette boucle de 100 000 fois, il ne génère pas de nouvel objet chaîne.


Grâce à l'analyse ci-dessus, nous devons choisir la méthode d'épissage de chaîne appropriée à l'endroit approprié, mais il n'est pas nécessaire de choisir append() et concat( ), la raison est que, selon nos habitudes de programmation, nous n'envisagerons d'utiliser les méthodes append() et concat() que si cela peut vraiment améliorer l'efficacité de notre système. En même temps, je ne les utilise vraiment pas. beaucoup. Grâce à la méthode concat().

Ce qui précède est le contenu du chapitre sur l'amélioration de Java (13)-----String Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn