5.1 Usando String y StringBuilder - ajpaez/OCA GitHub Wiki

(OCA Objectives 2.7 and 2.6)

Para el examen, lo único que necesita saber sobre la clase StringBuffer es que tiene exactamente los mismos métodos que la clase StringBuilder, pero StringBuilder es más rápido porque sus métodos no están sincronizados. Ambas clases, StringBuilder y StringBuffer, le dan a los objetos de String la posibilidad de manejar algunas de sus deficiencias (como la inmutabilidad).

La clase String

Esta sección cubre la clase String, y los conceptos claves para entender que cuando un objeto String se crea, nunca puede ser cambiado.

Los Strings son objetos inmutables

En Java, los Strings son objetos. Al igual que otros objetos, tu puedes crear una instancia de String con la palabra clave new, String s = new String(); Podemos asignar un valor a la instancia anterior de la siguiente forma s = "abcd"; También podemos crear una nueva instancia y asignar un valor al String a la par String s = new String(abcd); Hay algunas diferencias sutiles entre estas dos opciones, se verán mas adelante, pero todas ellas tienen algo en común, crean un nuevo objeto String con el valor abcd y lo asigna a la variable de referencia s. Podemos crear otra variable de referencia s2 y asignarla a s, String s2 = s;

La diferencia sutil tiene su origen en la inmutabilidad, la inmutabilidad es la propiedad que tienen los objetos de tipo String e impide que una vez se haya asignado un valor, dicho valor no se pueda cambiar. OJO! inmutable es el valor, no la variable, s o s2 pueden cambiar de valor tantas veces como quieran ( no son finales).

Esto como impacta en los Strings? Si hacemos lo siguiente: s = s.concat("1234"); La JVM tomará el valor del String "abcd" y le agregará 1234 al final, resultando el valor abcd1234. Dado que los Strings son inmutables la JVM no puede añadir la cadena 1234 al final de abcd , por lo que se produce es un nuevo String con el valor abcd1234 y se asigna a s. Tras la ejecución de esta linea tenemos tres objetos String, el primero que creamos "abcd", el nuevo resultante de la concatenación "abcd1234" y el argumento que usa concat, "1234", ya que es en su mismo un String.

Si no asignamos el valor resultante de concat, la cadena resultante de la concatenación se perderá ya que no estará referenciada por ninguna variable.

Otro ejemplo, Cuál es la salida de este código y cuantos objetos String se construyen?

String s1 = "spring ";
String s2 = s1 + "summer ";
s1.concat("fall ");
s2.concat(s1);
s1 += "winter ";
System.out.println(s1 + " " + s2);

La salida es "spring winter spring summer", existen dos variables de referencia: s1 y s2. Un total de 8 objetos Strings son creados: "spring ", "summer " (lost), "spring summer ", "fall " (lost), "spring fall " (lost), "spring summer spring " (lost), "winter " (lost), "spring winter " (at this point "spring " is lost). Solo dos de los ocho objetos String no se pierden en el proceso.

#Hechos importantes sobre Strings y la memoria En este apartado veremos como Java maneja los objetos String en memoria y algunas hechos que ocurren detrás de estos comportamientos. Uno de los objetivos de un cualquier lenguaje de programación es hacer un uso eficiente de la memoria. A medida que crece una aplicación, es muy común que los literales de String ocupen grandes cantidades de memoria. Para hacer que Java sea mas eficiente en cuanto a memoria, la JVM tiene un espacio de memoria reservado que se conoce como String constant pool. Cuando es compilador encuentra un literal String, comprueba el pool para ver si ya existe una cadena idéntica. Si encuentra una coincidencia, la referencia al nuevo literal se dirige a la cadena existente y no se crea ningún nuevo literal String ( la cadena existente simplemente tiene una referencia mas hacia ella) Otro motivo de que los String sean inmutables y existan en el pool, es que si dos variables de referencia apuntan al mismo literal String y alguna de ellas cambia el valor, la otra no será consciente de esto.

La clase String es final

##Creando nuevos Strings Dos son las formas mas comunes de crear nuevos String (supongamos que los literales no existen en el pool a la hora de crearlos):

  • String s = "abc". Se crea el literal "abc" en el pool y se crea a demás una variable de referencia s a dicho objeto.
  • String s = new String("xyz"). Al usar new se está creando un objeto normal en la memoria (nonpool) y s se referirá a dicho objeto, ademas se creara un literal "xyz" en el pool.

#Métodos mas usados en la clase String

##public char charAt(int index) Devuelve el carácter localizado en el String especificado en el index establecido. String index comienza en 0.

String x = "airplane";
System.out.println( x.charAt(2) );       //  output is 'r'

##public String concat(String s) Devuelve un String con el valor del String pasado al método concatenado al final del String especificado. El operados += funciona igual para String.

String x = "taxi";
System.out.println( x.concat(" cab") ); // output is "taxi cab"

##public boolean equalsIgnoreCase(String s) Devuelve un valor booleano dependiente de si el valor del String pasado al método es igual que el del String especificado sin importar mayúsculas o minúsculas.

String x = "Exit";
System.out.println( x.equalsIgnoreCase("EXIT"));   // is "true"
System.out.println( x.equalsIgnoreCase("tixe"));   // is "false"

##public int length() Devuelve la longitud del string especificado.

String x = "01234567";
System.out.println( x.length() );     // returns "8"

NOTA: Los arrays tiene un atributo (NO un metodo) length para conocer la longitud del array. Cuidado con las preguntas trampa que usan length() en arrays!!!

##public String replace(char old, char new) Devuelve un String con el valor del String especificado en el que se han sustituido los caracteres indicados en old por los caracteres indicados en new.

String x = "oxoxoxox";
System.out.println( x.replace('x', 'X') );   // output is "oXoXoXoX"

##public String substring(int begin) and public String substring(int begin, int end) Devuelve un String con una subparte del valor del String especificado. El argumento begin representa el índice del carácter desde el que se comenzara a devolver (basado en cero). Si no se especifica el segundo argumento se devolverá hasta el final de String, si se especifica el segundo se devolverá hasta la posición indicada, excluida. Si se indica (3,6) se comenzará a devolver la cadena desde el carácter con índice 3 y hasta el carácter con indice 6-1.

String x = "0123456789"; // the value of each char is the same as its index!
System.out.println( x.substring(5) );    // output is  "56789"
System.out.println( x.substring(5, 8));  // output is "567"

##public String toLowerCase() Devuelve un String con los caracteres en minúscula del valor del String especificado.

String x = "A New Moon";
System.out.println( x.toLowerCase() );   // output is "a new moon"

##public String toUpperCase() Devuelve un String con los caracteres en mayúscula del valor del String especificado.

String x = "A New Moon";
System.out.println( x.toUpperCase() );  // output is "A NEW MOON"

##public String toString()

##public String trim() Devuelve un String con los espacios en blanco eliminados del valor del String especificado.

String x = "  hi  ";
System.out.println( x + "t" );          // output is "  hi  t"
System.out.println( x.trim() + "t");    // output is "hit"

La clase StringBuilder

La clase java.lang.StringBuilder debe ser usada cuando se presente hacer muchas modificaciones en los caracteres de un string. Como se comente en la sección anterior, los objetos String son inmutables , por lo que si se realizan muchas manipulaciones con objetos String, se terminará por crear una gran cantidad de objetos String, acabando estos abandonados en el String pool.

##StringBuilder vs StringBuffer La clase StringBuilder fue añadida en Java 1.5. Tiene exactamente la misma API que StringBuffer, salvo que StringBuilder no es thread-safe, sus métodos no están sincronizados. Por esto , StringBuilder es mas rápido.

##Usando StringBuilder

StringBuilder sb = new StringBuilder("abc");
sb.append("def");
System.out.println("sb = " + sb);     // output is "sb = abcdef"
sb.delete(0, sb.length());
sb.append("def").reverse().insert(3, "---");
System.out.println( sb );              // output is  "fed---cba"

#Métodos importantes en la clase StringBuilder (aka SB)

##public StringBuilder append(String s) Actualiza el valor del SB (no devuelve nada) y añade al final el texto pasado como argumento s. Este método esta sobrecargado, con argumentos de tipo boolean, char, double, float, int, long, and otros.

StringBuilder sb = new StringBuilder("set ");
sb.append("point");
System.out.println(sb);       // output is "set point"
StringBuilder sb2 = new StringBuilder("pi = ");
sb2.append(3.14159f);
System.out.println(sb2);      // output is  "pi = 3.14159"

##public StringBuilder delete(int start, int end) Elimina del valor del SB (no devuelve nada) los caracteres comenzando por el indice start (con base 0) hasta el caracter end (con base 1).

StringBuilder sb = new StringBuilder("0123456789");
System.out.println(sb.delete(4,6));      // output is "01236789"

##public StringBuilder insert(int offset, String s) Actualiza el valor del SB (no devuelve nada) y añade el argumento s, en la posición indicada por offset (con base cero). Este metodo esta sobrecargado, con argumentos de tipo boolean, char, double, float, int, long, and otros.

StringBuilder sb = new StringBuilder("01234567");
sb.insert(4, "---");
System.out.println( sb );          //   output is  "0123---4567"

##public StringBuilder reverse() Actualiza el valor del SB (no devuelve nada), provocando que la secuencia de caracteres sea reemplazada por la secuencia pero en orden inverso

StringBuilder s = new StringBuilder("A man a plan a canal Panama");
sb.reverse();
System.out.println(sb); // output: "amanaP lanac a nalp a nam A"

##public String toString()