Mòdul 3

Pràctica 5: Paraules, frases, versos: tot són cadenes  
Tornar presentació tema
Pràctica 1 Pràctica 2 Pràctica 3 Pràctica 4 Pràctica 5 Pràctica 6  
     
  La classe java.lang.String  
     
  Ja portes força pràctiques en què fas anar cadenes de caràcters de text, paraules, tipificades com a objectes de la classe String. Les classes java.lang.String i java.lang.StringBuffer, amb els seus mètodes, són les eines fonamentals que ofereix el SDK de Java per a la manipulació dels elements de text. Ara toca un estudi més extens d'això. Ens restringim, però, a la classe String i no direm res més de la classe StringBuffer.  
     
  Una cadena ("string" en anglès, en el sentit de "enfilall", "reguitzell": sèrie de coses que vénen una darrera l'altra sense interrupció) és això: una tirallonga de caràcters de text posats en un cert ordre. Els objectes de la classe java.lang.String representen cadenes.  
     
  La manera més senzilla de construir una cadena és aquesta:  
     
 
String unaCadena="La Tia Maria";
String unaAltraCadena="Setze jutges mengen fetge d'un penjat";
String encaraUnaAltraCadena="569%$7)!!!-pw¿àH>*Ç}";
 
     
 

Es tracta, doncs, de delimitar els caràcters que componen la cadena per una parella de cometes dobles "".

 
     
Una primera cosa que se't pot ocórrer és: com s'ha de fer per tal que unes cometes,""", siguin de la cadena? El compilador no les interpretarà com a "final de cadena" i se'n perdrà la continuació?  
     
  Sí, sí, és clar que sí! Això introdueix el tema dels caràcters d'escapament: aquests són caràcters precedits d'una contrabarra, "\", que, d'una banda, tenen una funció especial i, de l'altra, permeten que els caràcters amb significat especial puguin ser inclosos en cadenes, perdent així aquest significat especial. Els més corrents són aquests:  
     
 
  Nom Ús
\n Canvi de línia Per passar a la línia següent
\t Tabulador (8 espais) Per tabular
\" Cometes Per poder posar """ com a component d'una cadena
\\ Contrabarra Per poder posar "\" com a component d'una cadena
 
     
  Vegem com funcionen. Obre un nou projecte que es digui Cadenes i afegeix-li aquesta classe:  
     
/**
* La classe CaractersEscapament té un únic mètode que serveix per
* comprovar la funció dels caràcters d'escapament \n, \t, \" i \\.
*
* @author Carles Romero
* @version 2003/02/29
*/

public final class CaractersEscapament {

    /**
     * Mètode que serveix per comprovar la funció dels caràcters
     * d'escapament \n, \t, \" i \\ i la funció de l'operador +
     * per enganxar cadenes una a continuació d'una altra.
     */

    public static void metodeDeMostra () {
        String ambCanviDeLinia=
            "Aquesta és la primera línia\ni "+
              "aquesta és la segona";
        String ambTabuladors=
            "Dada 1\tDada 2\t\tDada 4\nDada 5\t"+
             "Dada 6\tDada 7\tDada 8";
        String ambCometesIContrabarres=
            "El caràcter \\ es diu "+
             "una \"contrabarra\"";
        System.out.println
            ("====================================");
        System.out.println("Canvis de línia:");
        System.out.println(ambCanviDeLinia);
        System.out.println
            ("====================================");
        System.out.println("Tabuladors:");
        System.out.println(ambTabuladors);
        System.out.println
            ("====================================");
        System.out.println("Cometes i contrabarres:");
        System.out.println(ambCometesIContrabarres);
        System.out.println
            ("====================================");
    }

}

 
     
  Compila i, com que l'únic mètode que té la classe és static, no cal crear-ne cap objecte. El pots cridar directament:  
     
 
 
     
  i veure'n els resultats. Naturalment, et suggerim que facis canvis a les cadenes ambCanviDeLinia, ambTabuladors i ambCometesIContrabarres i, també, que en creis de noves.  
     
  Els mètodes de la classe java.lang.String:  
     
 

La classe java.lang.String conté els mètodes necessaris per a...

  • determinar la longitud (nombre de caràcters) d'una cadena

  • examinar individualment els caràcters que conté

  • comparar cadenes lexicogràficament

  • buscar i extreure subcadenes d'una cadena

  • transformar tots els seus caràcters a majúscules o a minúscules

  • ...i d'altres mètodes per executar procediments ben diversos.

A més, com ja has vist en l'exemple anterior, es pot fer servir l'operador "+" per a enganxar dues cadenes i formar-ne una de sola.

Tot seguit tens uns quants exemples de la sintaxi adequada:

 
     
 
  • public int length(). Retorna la longitud de la cadena, és a dir, el nombre de caràcters que conté. Així:

    String cadena="Això és una cadena";
    int n=cadena.length();

    posa un 18 a la variable n.
 
     
 
  • public String substring(int inici). Extreu una subcadena que té com a primer caràcter el que ocupava el lloc inici a la cadena original i , com a darrer, el darrer de la cadena. Així, a

    String cadena="Això és una cadena";
    String subcadenaU=cadena.substring(2);
    String subcadenaDos=cadena.substring(5);

    resulta subcadenaU="xò és una cadena " i subcadenaDos="és una cadena".

    Fes atenció a que...

    • inici no superi la longitud de la cadena, perquè et trobaries amb una excepció del tipus StringIndexOutOfBoundsException que t'aturaria el programa!

    • La primera posició correspon al 0, la segona a l'1, etc. Per aquesta raó cadena.substring(2) comença a la x de "Això...
 
     
 
  • public String substring(int inici,int final). Extreu una subcadena que té com a primer caràcter el que ocupava el lloc inici a la cadena original i , com a darrer, el que ocupava el lloc final-1 a la inicial. Així, a

    String cadena="Això és una cadena";
    String subcadenaU=cadena.substring(2,9);
    String subcadenaDos=cadena.substring(5,6);
    String subcadenaTres=cadena.substring(4,5);
    String subcadenaQuatre=cadena.substring(1,1);

    resulta subcadenaU="xò és u", subcadenaDos="é", subcadenaTres=" " i subcadenaQuatre="". Novament, vigila que ni inici ni final superin la longitud de la cadena, perquèm, com en el cas anterior, et trobaries amb una excepció StringIndexOutOfBoundsException!
 
     
 
  • public String toUpperCase() i public String toLowerCase() retornen, respectivament, cadenes que resulten del pas a majúscula i a minúscula dels caràcters de la cadena original:

    String cadena="Títol: El Rector de Vallfogona";
    String cadena_A=cadena.toUpperCase();
    String cadena_A=cadena.toLowerCase();


    El resultats són: cadena_A="TÍTOL: EL RECTOR DE VALLFOGONA" i cadena_B="títol: el rector de vallfogona".
 
     
 
  • public boolean equals(Object unObjecte). Retorna true si, i només si, l'objecte unObjecte és una instància de la classe String que representa exactament la mateixa successió de caràcters. Exemple:

    String cadena="Balsareny";
    String cadena_A="Gironella";
    String cadena_B="BalSareny";
    String cadena_C="Balsareny";
    boolean laA=cadena.equals(cadena_A);
    boolean laB=cadena.equals(cadena_B);
    boolean laC=cadena.equals(cadena_C);


    Resulta: laA=false, laB=false i laC=true.

    És totalment aconsellable fer servir la formulació anterior per definir els booleans i, en canvi, és completament desaconsellable plantejar-ho amb la sintaxi següent:

    boolean laA=(cadena==cadena_A);
    boolean laB=(cadena==cadena_B);
    boolean laC=(cadena==cadena_C);


    perquè, malgrat que dues cadenes continguin exactament els mateixos caràcters, són objectes diferents, és a dir, a la memòria, resideixen en llocs diferents i tenen, probablement, identificadors, també diferents. Ens podem trobar (depèn del sistema i de la manera com hagin estat construïdes les cadenes) que Java ens digui que "Tres quarts de quinze"=="Tres quarts de quinze" és false!
 
     
 
  • public boolean equalsIgnoreCase(String unaCadena). Retorna true si, i només si, la cadena unaCadena representa exactament la mateixa successió de caràcters, però fent cas omís de si són majúscules o minúscules:

    String cadena="Balsareny";
    String cadena_A="Gironella";
    String cadena_B="balSareny";
    String cadena_C="Valsareny";
    boolean laA=cadena.equalsIgnoreCase(cadena_A);
    boolean laB=cadena.equalsIgnoreCase(cadena_B);
    boolean laC=cadena.equalsIgnoreCase(cadena_C);

    Resulta: laA=false, laB=true i laC=false. Ep! Java no passa pas de l'ortografia!

 
     
 

  • public int compareTo(String unaCadena). Fa la comparació lexicogràfica de la cadena propietària del mètode (l'ordre d'un diccionari) amb la cadena unaCadena. El resultat és un nombre negatiu si unaCadena li és posterior, i positiu si unaCadena li és anterior. Si les dues cadenes són iguals, aleshores retorna un zero:

    String cadena="Balsareny";
    String cadena_A="Gironella";
    String cadena_B="Avià";
    String cadena_C="Balsareny";
    int laA=cadena.compareTo(cadena_A);
    int laB=cadena.compareTo(cadena_B);
    int laC=cadena.compareTo(cadena_C);


    Resulta: laA=<nombre negatiu>, laB=<nombre positiu> i laC=0.
 
     
 

Pots trobar més mètodes i les explicacions a la documentació de la classe java.lang.String.

A la pràctica 2 del mòdul 4 t'expliquem idees generals sobre la documentació dels projectes de Java i com la podràs confegir per als teus projectes. Ara bé, les classes públiques elaborades pels programadors de Sun Microsystems, com és ara la java.lang.String, tenen documentacions excel·lents que ens faciliten tots els detalls que ens permetran importar-les i aprofitar-les per als nostres projectes. Pots veure-ho si enllaces amb la pàgina web "oficial" de Java; per a la classe String, la documentació es troba a

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html

per a la darrera versió oficial del programa quan s'han redactat aquests materials, a saber, J2SE 1.4.2 SDK. Allà trobaràs molts més mètodes i més explicacions.

 
     
  De nombres a cadenes:  
     
  Sovint convé representar valors numèrics (enters, reals) com a cadenes: moltes vegades necessitaràs que el nombre int n=51 es representi per la cadena de caràcters de text "51". La classe java.lang.String, tot fent una bona exemplificació de sobrecàrrega, (donar el mateix nom a mètodes diferents, en l'argot dels programadors, es diu "sobrecàrrega de mètodes". La màquina els distingeix, no pel nom, que és el mateix, sinó pels paràmetres, que han de ser, obligatòriament diferents!) té aquests mètodes static, que fan precisament això:  
     
 
  • public static String valueOf(boolean b). Retorna la representació com a cadena del valor de veritat de la variable boolean b:

    boolean b_1=(2==3);
    boolean b_2=(3==3);
    String cadenaB_1=String.valueOf(b_1);
    String cadenaB_2=String.valueOf(b_2);

    Aleshores, b_1=false, b_2=true, cadenaB1="false" i cadenaB_2="true". Observa que, com que el mètode és static, cal cridar-lo tot posant com a prefix el nom de la classe, "String", no pas el de cap objecte de la classe String. (Mira la corresponent explicació a la pràctica 5 del mòdul 2)
 
     
 
  • public static String valueOf(int n). Retorna la representació com a cadena del valor numèric de la variable int n:

    int n_1=-436;
    int n_2=2004;
    String cadenaN_1=String.valueOf(n_1);
    String cadenaN_2=String.valueOf(n_2);

    Resulta n_1=-436, n_2=2004 i cadenaN_1="-436", cadenaN_2="2004".

    Observa que n_1+n_2=1568, però cadenaN_1+cadenaN_2="-4362004". Igualment, n_1-n_2=-2440, però cadenaN_1-cadenaN_2 no té sentit.

    Observa, a més, que aquest mètode té el mateix nom que l'anterior: valueOf, però el paràmetre és ara int n, en lloc de boolean b. Això és, precisament, la sobrecàrrega de mètodes.
 
     
 
  • public static String valueOf(double db), public static String valueOf(float fl)i public static String valueOf(long lng) fan la mateixa feina, però per a valors numèrics dels tipus double, float i long respectivament. (Més sobrecàrrega!)
 
     
 

Les conversions inverses (de String a int, de String a float, etc.) no són, com és lògic, mètodes de la classe String, sinó que són mètodes static de les corresponents classes Integer, Float, etc:

  • static int Integer.parseInt(String string)

  • static float Float.parseFloat(String string)

  • static double Double.parseDouble(String string).
 
     
  Posem a funcionar tot això:  
     
 

Ara escriuràs una classe que serà capaç de detectar els nombres de quadrat automòrfic (uix!) que hi ha entre zero i un cert valor màxim.

Es diu que un nombre és de quadrat automòrfic si coincideix amb les darreres xifres del seu quadrat.

  • 25 és de quadrat automòrfic, perquè les dues darreres xifres del seu quadrat, que és 625 configuren, precisament, la cadena "25".

  • 376 també ho és perquè 3762 = 141376.

  • En canvi 45 no ho és perquè 452 = 2025. La cadena de les dues darreres xifres del quadrat és "25", diferent de la "45" inicial.
 
     
Al projecte Cadenes afegeix-li la classe NombresAutomorfics amb aquest codi:  
     
 

/**
* Per a cercar els nombres de quadrat automòrfic, és a
* dir, els nombres que coincideixen amb les darreres
* xifres del seu quadrat.
*
* @author Santiago Manrique
* @version 2004/01/26
*/

public class NombresAutomorfics {

    /**
     * El màxim dels nombres que es comprovaran. 
     */

    private int maxim;

    /**
     * Mètode constructor per a objectes de la classe
     * NombresAutomorfics.
     * @param elMaxim el màxim dels nombres que es comprovaran
     */

    public NombresAutomorfics (int elMaxim) { // constructor
        maxim=elMaxim;
    }

    /**
     * Imprimeix una llista els nombres de quadrat automòrfic
     * menors que el maxim indicat.
     */

    public void llistarAutomorfic () { 
        System.out.println("\tNombre:\tQuadrat:");
            for (int i=0; i<=maxim;i++) {
                String valor=String.valueOf(i);
                String quadrat=String.valueOf(i*i);
                int longValor=valor.length();
                int longQuadrat=quadrat.length();
                String perComparar=                   quadrat.substring(longQuadrat-longValor);
                    if (valor.equals(perComparar)) {
                        System.out.println("\t"+valor+
                                           "\t"+quadrat);
                    }
            }
    }

}

 
     
  Anàlitzem ara el codi:  
     
 
  • Es comença per declarar la variable d'instància int maxim:

        private int maxim;

    que contindrà el nombre màxim que la classe comprovarà per veure si és de quadrat automòrfic o no.
 
     
  Després vé el mètode constructor:

    public NombresAutomorfics (int elMaxim) { 
        //constructor

        maxim=elMaxim;
    }

que es limita a dipositar el valor int elMaxim, que rep com a paràmetre, a la variable d'instància int maxim.

Per què s'ha de fer això? Perquè ara, aquest valor ja està a la disposició de qualsevol altre mètode de la classe.
 
     
 
  • Finalment, hi ha el mètode public void llistarAutomorfic (), el qual analitza els nombres de 0 a elMaxim, i imprimeix els que siguin de de quadrat automòrfic.

    • A la primera línia d'aquest mètode s'imprimeix una capçalera per a la taula de nombres de quadrat automòrfics que imprimirà després. Observa l'ús del caràcter de tabulació "\t":

              System.out.println("\tNombre:\tQuadrat:");

    • Aleshores comença una estructura for(...) {...} per fer l'anàlisi de tots i cadascun dels nombres de 0 a elMaxim. La primera acció és convertir aquests nombres i els seus quadrats a cadenes de caràcters:

                      String valor=String.valueOf(i);
                      String quadrat=String.valueOf(i*i);

    • Després se'n demana la longitud, és a dir el nombre de caràcters (xifres, en aquest cas) de cadascuna de les dues cadenes:

                      int longValor=valor.length();
                      int longQuadrat=quadrat.length();

    • Ara cal mirar les últimes xifres de la cadena quadrat per poder-les comparar amb la cadena valor completa. Es tracta d'extreure'n la subcadena que comença just a la posició longQuadrat-longValor:

               StringperComparar=
                   quadrat.substring(longQuadrat-longValor);
 
     
 
  • Ja està tot a punt. Es tracta de mirar si la cadena valor i la cadena perComparar són iguals:

                        if (valor.equals(perComparar)) {

    Si ho són, que vol dir que i (la variable comptador del bucle, que s'ha transformat a cadena valor pel mètode String.valueOf(i)) és de quadrat automòrfic, imprimeix les cadenes amb les xifres del nombre i les del seu quadrat:

                            System.out.println("\t"+valor+
                                               "\t"+quadrat);

    amb els corresponents caràcters "\t" de tabulació, per tal d'aconseguir una taula clara i fàcilment legible.
 
     
  Ara ja pots compilar i comprovar que tot funciona bé. Crea un objecte d'aquesta classe, amb 10000 com a paràmetre del mètode constructor, l'inspecciones per comprovar que el camp int maxim conté, efectivament, 10000, i després executa el mètode public void llistarAutomorfic ():  
     
 
 
     
  i  
     
 
 
     
  Voilà!  
    Tornar al principi