Operaciones de cadenas comunes en Java

En pocas palabras, una cadena se utiliza para almacenar texto, es decir, una secuencia de caracteres. La clase más utilizada de Java es la clase String, sin duda, y con un uso tan alto...

Introducción

En pocas palabras, una ‘Cadena’ se usa para almacenar texto, es decir, una secuencia de caracteres. La clase más utilizada de Java es la clase String, sin duda, y con un uso tan alto, es obligatorio que los desarrolladores de Java estén completamente familiarizados con la clase y sus operaciones comunes.

Cuerda

Hay mucho que decir sobre Strings, desde las formas en que puede inicializarlos en String Literal Pool, sin embargo, en este artículo nos centraremos en las operaciones comunes, en lugar de la clase en sí.

Aunque, si desea leer más sobre las diversas formas de crear cadenas en Java, debe consultar Cadena frente a StringBuilder frente a StringBuffer.

Aquí, asumimos que está familiarizado con el hecho de que las Strings son inmutables, ya que es algo muy importante que debe saber antes de manipularlas. De lo contrario, consulte el artículo vinculado anteriormente donde se explica en detalle.

La clase String viene con muchos métodos auxiliares que nos ayudan a procesar nuestros datos textuales:

Concatenación de cadenas

Antes de comenzar a usar cualquiera de estos métodos en cadenas, deberíamos echar un vistazo a la concatenación de cadenas, ya que es algo bastante común. Comencemos con el operador +. La clase String sobrecarga ese operador y se usa para concatenar dos cadenas:

1
2
3
4
5
6
String aplusb = "a" + "b";

// The operands can be String object reference variables as well
String a = "a";
String b = "b";
aplusb = a + b;

El operador + es muy lento. Los objetos String son inmutables, por lo que cada vez que deseamos concatenar n cadenas, Java tiene que copiar los caracteres de todas las cadenas en un nuevo objeto String. Esto nos da complejidad cuadrática (O(n^2)).

Esto no es un problema con cadenas pequeñas, o cuando estamos concatenando varias cadenas al mismo tiempo (String abcd = "a" + "b" + "c" + "d";). Java usa automáticamente StringBuilder para concatenar varias cadenas a la vez, por lo que la fuente de la pérdida de rendimiento es la concatenación en bucles. Por lo general, para algo así, usaríamos la clase StringBuilder antes mencionada.

Funciona como un objeto String mutable. Omite todas las copias en la concatenación de cadenas y nos brinda una complejidad lineal (O(n)).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int n = 1000;

// Not a good idea! Gives the right result, but performs poorly.
String result = "";
for (int i = 0; i < n; i++) {
    result += Integer.valueOf(i);
}

// Better, performance-friendly version.
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < n; i++) {
    sb.append(i);
}

También podemos concatenar usando el método concat():

1
2
String str1 = "Hello";
System.out.println(str1.concat("World"));

Producción:

1
Hello World

Nota: cuando se usa la concatenación de cadenas con otros tipos de datos, implícitamente se convierten a su representación de cadena:

1
System.out.println("2 = " + 2); 

Esto da el resultado esperado "2 = 2".

1
System.out.println("2 = " + 1 + 1);

En circunstancias normales, 1+1 se evaluaría primero, ya que Java se ocupa de las operaciones de derecha a izquierda. Sin embargo, esta vez no lo hará: el resultado es "2 = 11". Esto se debe a algo llamado "precedencia de operadores".

Esencialmente, cuando se encuentran dos o más operadores "+" (sin otros operadores presentes, ni paréntesis), Java comenzará con el operador "+" más a la izquierda y continuará desde allí. Si quisiéramos que la salida fuera "2 = 2" nuevamente, necesitaríamos agregar paréntesis en el lugar apropiado.

1
System.out.println("2 = " + (1 + 1));

Por otro lado, si intentamos usar el método concat() con un tipo de datos diferente:

1
2
String str1 = "Hello";
System.out.println(str1.concat(53));

Nos recibirían con una excepción:

1
incompatible types: int cannot be converted to String

Cuando se usa el operando +, Java convierte automáticamente el tipo de datos en una cadena, mientras que cuando se usa el método concat(), no lo hace.

Por cierto, con todos los métodos que exploraremos en este artículo, no necesitamos proporcionar una variable de referencia, a veces, por brevedad, es más fácil simplemente usarlos en un literal:

1
2
3
4
5
6
// Instead of this...
String ourString = "this is just some string";
System.out.println(ourString.substring(5,10));

// ...we can do this:
System.out.println("this is just some string".substring(5,10));

Realmente, cualquier forma está bien, pero la segunda produce menos código.

Determinar la longitud de la cadena {#determinar la longitud de la cadena}

length() devuelve el número total de caracteres en nuestra String.

isEmpty() devuelve verdadero o falso dependiendo de si nuestra String está vacía o no. Esto significa que isEmpty() devuelve true para el mismo caso en que length() devuelve 0.

Por ejemplo:

1
2
3
4
if (s.length() == 0) // or s.isEmpty() {
    System.out.println("s is empty");
}
else System.out.println("s isn't empty, it's: " + s + "\n");

Aquí mostramos cómo puede usar estos métodos para buscar una cadena vacía. La verificación condicional también podría reemplazarse con s.isEmpty() y funcionaría igual.

Búsqueda de caracteres y subcadenas

Dado que una ‘Cadena’ es una secuencia inmutable de caracteres, podemos preguntar qué carácter está en qué posición, o encontrar la posición de un carácter. La indexación de un String comienza en 0, como estamos acostumbrados con las matrices.

charAt(int index) devuelve el valor del carácter en un índice dado.

indexOf() está sobrecargado y, por lo tanto, tiene múltiples usos:

  • indexOf(int ch) devuelve la primera posición de índice que coincide con el valor de carácter dado
  • indexOf(int ch, int fromIndex) devuelve el primer índice que coincide con el valor del carácter dado DESPUÉS de fromIndex
  • indexOf(String substring) devuelve la (primera) posición inicial de substring en el objeto String en el que fue llamado
  • indexOf(String substring, int fromIndex) igual que el método anterior, pero la búsqueda comienza en fromIndex en lugar de 0

Todos los métodos indexOf() sobrecargados devuelven -1 si no se encuentra el índice.

lastIndexOf() también está sobrecargado y tiene firmas de método equivalentes a indexOf(), y también devuelve -1 si no se encuentra un índice apropiado. Busca el objeto String hacia atrás a menos que se especifique un fromIndex.

El índice pasado al método tiene que estar dentro del rango [0, ejemplo.longitud() - 1] para que sea válido. De lo contrario, se lanza una StringIndexOutOfBoundsException.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
String example = "This should be complicated enough to show some things we should show";

// Find the characters at the indexes given
System.out.println(example.charAt(0));
System.out.println(example.charAt(5));

// An StringIndexOutOfBoundsException is thrown in both these cases:
// System.out.println(example.charAt(-1));
// System.out.println(example.charAt(200));

// Find the index of characters or substrings
System.out.println(example.indexOf('s')); // returns the first occurence of 's'
System.out.println(example.indexOf('s', 4)); // the first 's' after index 4
System.out.println(example.indexOf("should")); // the index of the first "should" in our string
System.out.println(example.indexOf("should", 15)); // the index of the first "should" in our
                                                   // string _after_ index 15

// Find the last index of characters or substrings
System.out.println(example.lastIndexOf('s')); // returns the first occurence of 's' when we look backwards from the end of the string
System.out.println(example.lastIndexOf('s', 45)); // searches for 's' backwards from the position 45
System.out.println(example.lastIndexOf("should")); // returns the position at which the substring 'should' appears, looking backwards from the end of the string
System.out.println(example.lastIndexOf("should", 20)); // finds substring 'should' from position 20 backwards, and returns the position at which it begins

Esto generará lo siguiente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
T
s
3
5
5
57
64
42
57
5

Nota: indexOf(int ch, int fromIndex) se usa a menudo en bucles, cuando queremos hacer algo para cada aparición de un carácter en una String.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int foundAt = -1;
String example = "This should be complicated enough to show some things we should show";
while (true) {
    foundAt = example.indexOf('s', foundAt + 1);
    if (foundAt == -1)
        break;
    else {
        // do something with that information
    }
}

Comparación de cadenas

El método compareTo() compara lexicográficamente nuestra String con otra. La comparación real de las dos cadenas se basa en el valor Unicode de cada carácter de la cadena. El método devuelve un número positivo, un número negativo o 0.

Si todos los caracteres de nuestra cadena estuvieran en minúsculas (o en mayúsculas), el valor de retorno del método compareTo() se puede interpretar como "si el valor de retorno fuera negativo, mi cadena vendría antes que la otra cadena en un diccionario".

Hago hincapié en el punto de que las letras deberían estar en el mismo caso, ya que, de lo contrario, la función podría producir un resultado inesperado.

El método compareTo() no pasa por todos los caracteres de nuestras cadenas, regresa tan pronto como llega al final de cualquiera de las cadenas, o tan pronto como encuentra un carácter que no coincide. En cuyo caso, la función devuelve (valor Unicode del carácter no coincidente en nuestra cadena) - (valor Unicode del carácter no coincidente en la cadena dada).

Para cualquiera que tenga curiosidad - ASCII es parte de Unicode. Lo que significa que a-z y A-Z están en el mismo orden que en la codificación ASCII, es decir, todos están uno tras otro en sus respectivos casos. Es decir, a-z son códigos entre 97-122 y A-Z es 65-90. Así que el valor de 'a' es 97, el valor de 'b' es 98 y así sucesivamente. De esta forma, cuando restamos el valor Unicode para 'b' de 'a', obtenemos -1. Lo que significa que 'a' es una letra antes de 'b', que es.

1
2
3
4
5
System.out.println("a".compareTo("a"));
System.out.println("a".compareTo("b"));
System.out.println("1".compareTo("12345678"));
System.out.println("2".compareTo("12345678"));
System.out.println("abcd".compareTo("abgggggggggg"));
1
2
3
4
5
0
-1
-7
1
-4

En la tercera línea del código anterior, en este caso, compareTo devuelve la diferencia en las longitudes de las cadenas, ya que no encontró un carácter que no coincidiera antes de que se “agotara” los caracteres en una cadena.

Y en la última línea vemos que -4 está impreso debido a 'c' - 'g', ya que esa es la primera discrepancia que encontró, y no le importa el resto.

Nota: La parte "inesperada" al usar compareTo() ocurre cuando comparamos cadenas con diferentes casos.

1
System.out.println("ORANGE".compareTo("apple")); 

Podríamos esperar que el método devuelva un valor positivo, ya que "manzana" debe ir antes de "NARANJA". Sin embargo, el valor Unicode para 'O' es menor que el valor Unicode para 'a'.

A veces, este puede ser el comportamiento preferido, pero en caso de que no lo sea, usamos compareToIgnoreCase(). Ese método hace esencialmente lo mismo que compareTo(), solo finge que todo está en el mismo caso y nos da un orden de diccionario "adecuado".

Nota: compareTo() y compareToIgnoreCase() se usan a menudo cuando creamos un Comparador para una clase personalizada.

Por ejemplo, digamos que tenemos un objeto Persona como el siguiente:

1
2
3
4
5
class Person {
    String firstName;
    String lastName;
    // ...
}

Ahora digamos que tenemos una ArrayList llamada "personas" de muchos objetos Persona, sin ningún orden en particular. Nos gustaría ordenar esa ArrayList para que se ordenen en orden lexicográfico según su apellido, y si las personas tienen el mismo apellido, nos gustaría ordenarlas según su nombre.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Comparator<Person> personComparator = new Comparator<Person>() {
    @Override
    public int compare(Person p1, Person p2) {
        if (p1.firstName.compareTo(p2.firstName) != 0) {
            return p1.firstName.compareTo(p2.firstName);
        }
        else return p1.lastName.compareTo(p2.lastName);
    }
};
Collections.sort(people, personComparator);

Extracción de subcadenas

Una "subcadena" es un subconjunto de (o parte de) otra cadena. El método substring() devuelve una nueva cadena que es una subcadena de la cadena en la que usamos el método.

En otras palabras, si quisiéramos una nueva cadena que contuviera los primeros tres caracteres de nuestra cadena, usaríamos ourString.substring(0, 3).

El método substring() tiene dos variaciones:

  • substring(int startIndex) devuelve una String que contiene todos los caracteres desde startIndex (inclusive) hasta el final de nuestra String. Se comporta igual que substring(int startIndex, ourString.length()).
  • substring(int startIndex, int endIndex) devuelve una String que contiene todos los caracteres desde startIndex (inclusive) hasta endIndex (exclusivo, es decir, el carácter en endIndex no se devuelve)

Nota: Los índices proporcionados aún deben estar en el intervalo [0, ourString.length()-1]. ¡Java, a diferencia de otros lenguajes, NO admite índices negativos en el método substring()! Java lanzará una StringIndexOutOfBoundsException por cualquiera de las siguientes razones:

  • startIndex es negativo
  • endIndex es mayor que la longitud de nuestro objeto String
  • startIndex es mayor que endIndex

Aunque la documentación no dice explícitamente que "no se permiten valores negativos en absoluto" (uno podría tener la costumbre de dar -1 como endIndex de otros lenguajes de programación), esa regla se puede derivar de ese hecho que startIndex no puede ser negativo, y que endIndex tiene que ser mayor que startIndex.

Sin embargo, Java solo nos hace dar el paso extra de escribir nuestraCadena.longitud() - algúnNúmero como índiceFin en lugar de simplemente - algúnNúmero.

1
2
3
4
5
6
7
String ourString = "abcdef";
System.out.println(ourString.substring(0,3));
System.out.println(ourString.substring(2));
System.out.println(ourString.substring(1,3));

// If we want the last few characters
System.out.println(ourString.substring(ourString.length()-3));
1
2
3
4
abc
cdef
bc
def

Cambio de mayúsculas y minúsculas {#cambio de mayúsculas y minúsculas}

Estos dos métodos simples se utilizan para cambiar el caso de los caracteres dentro de una cadena.

  • toLowerCase(): cambia todos los caracteres en mayúsculas a minúsculas (ignora todo lo demás)
  • toUpperCase(): cambia todos los caracteres en minúsculas a mayúsculas (ignora todo lo demás)
1
2
3
4
5
String ourString = "ThInK oF a ClEvEr StRiNg";

System.out.println(ourString.toLowerCase());
System.out.println(ourString.toUpperCase());
System.out.println(ourString);

Esto generará lo siguiente:

1
2
3
think of a clever string
THINK OF A CLEVER STRING
ThInK oF a ClEvEr StRiNg

Tenga en cuenta que el objeto ‘String’ inicial en sí mismo no ha cambiado.

Eliminación de espacios en blanco

Este método devuelve una copia del objeto ‘String’ inicial en el que se eliminan los espacios en blanco iniciales y finales (espacios, tabulaciones, saltos de línea).

1
2
String ourString = "      Any non-leading and non-trailing whitespace is  \n  preserved       ";
System.out.println(ourString.trim());

Producción:

1
2
Any non-leading and non-trailing whitespace is  
  preserved

trim() se usa a menudo cuando se procesa la entrada del usuario, ya que se asegura de que no tengamos espacios en blanco inútiles y no cambie la cadena si no lo hacemos.

Un uso muy común de trim() con la entrada del usuario es verificar si se ingresaron caracteres que no sean espacios en blanco:

1
2
3
4
5
6
7
8
9
// Usually we check for empty inputs like this:
if (userinput.isEmpty()) { ... }
// ...or the equivalent
if (userinput.length() != 0) { ... }

// But a better way to check would be this, which
// handles cases where the user entered only
// whitespace (i.e. "    ")
if (userinput.trim().isEmpty()) { ... }

Formateo de cadenas

El método format() devuelve una cadena formateada con un formato y argumentos dados. Se usa para simplificar la vida al formatear cadenas complejas en Java. Funciona de manera similar a printf en C:

1
public static String format(String form, Object... args)

La declaración de este método puede parecer complicada, pero echemos un vistazo más de cerca:

  • Para nuestros propósitos, la parte estática significa que este método se llama a través de la clase String, y no a través de un objeto de la clase String. Lo que significa que cuando queramos usar este método escribiremos String.format(...) y no ourString.format(...). Podemos llamar al método de la segunda manera, pero ourString no jugará un papel en el método de todos modos.
  • El ... (tres puntos) después de Objeto simplemente dice que aquí se puede pasar un número variable de argumentos. Uno o dos o cincuenta, todo depende de la ‘forma de cadena’.

Comencemos con un ejemplo simple.

1
2
3
4
5
6
7
int a = 2;
int b = 3;
int c = 4;
int d = 1;

// %d indicates we want to print an integer
System.out.println(String.format("%d", a));
1
2

El método format() pasa por la cadena form y busca caracteres especiales y los reemplaza con argumentos en args.

Los caracteres especiales comienzan con un %. En nuestro ejemplo, usamos %d, que Java entiende como "Intentaré analizar el argumento provisto en args como un número entero".

Un ejemplo un poco más perspicaz de cuándo es útil format():

1
2
3
4
5
// Very messy, hard to read, and hard to maintain
System.out.println("a = " + a + "\n" + "b = " + b + "\n" + "c = " + c + "\n" + "d = " + d + "\n");

// Much prettier
System.out.println(String.format("a = %d \nb = %d \nc = %d \nd = %d", a, b, c, d));

Como podemos ver en este ejemplo, Java hace coincidir los caracteres especiales que comienzan con % con los argumentos en orden. Lo que significa que cuando vea el primer ‘%d’ lo emparejará con ‘a’, el segundo ‘%d’ con ‘b’ y así sucesivamente.

Hay muchos caracteres especiales para format() y puede encontrar la lista completa en [los documentos](https://docs.oracle.com/javase/7/docs/api/java/util/Formatter. html) (incluyendo un montón de opciones de fecha/hora), pero las que verá y usará con mayor frecuencia son:

  • %d: tipos integrales (byte, short, int, long, BigInteger)
  • %s: Cadenas
  • %f: para float como un número decimal, %e se formatea como un número decimal en notación científica computarizada, y %g se imprime igual que %f o %e dependiendo de el valor de precisión después del redondeo.
  • %b: para valores booleanos. Si el valor es nulo, se imprime "falso"

En términos generales, el método format() tiene una sintaxis aparentemente complicada:

1
%[argument_index$][flags][width][.precision]conversion

argument_index, flags, width y precision son todos opcionales como lo indica [].

La precisión puede significar diferentes cosas para diferentes tipos de datos. Para flotantes/dobles, la precisión tiene el significado obvio de "cuántos dígitos se supone que debo mostrar después del punto decimal". Aparte de eso, la precisión especifica el número máximo de caracteres que se escribirán en la salida.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
double ourDouble = 1123.9303;
System.out.println(String.format("%f", ourDouble));
System.out.println(String.format("%.3f", ourDouble)); // specifies that we only want 3 digits after decimal point
System.out.println(String.format("%e", ourDouble));

String ourString  = "what does precision do with strings?";
System.out.println(String.format("%.8s", ourString)); // prints the first 8 characters of our string

int ourInt = 123456789;
// System.out.println(String.format("%.4d", ourInt)); // precision can't be used on ints

Esto generará:

1
2
3
4
1123.930300
1123.930
1.123930e+03
what doe

El width opcional especifica el ancho mínimo de la salida.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// If our number has less than 6 digits, this will
// add extra 0s to the beginning until it does
System.out.println(String.format("%06d", 12)); 

// If our number has more than 6 digits, it will just print it out
System.out.println(String.format("%06d", 1234567));

// We can specify output width, with the output being aligned
// to the right if it's shorter than the given space. If it's
// longer, everything gets printed. The || are added for
// demonstration purposes only
System.out.println(String.format("|%20d|", 12));
// Or we can align the output to the left
System.out.println(String.format("|%-20d|", 12));

// We can also easily print an octal/hexadecimal value of an integer
System.out.println(String.format("Octal: %o, Hex: %x", 10, 10));

Ejecutar este código producirá lo siguiente:

1
2
3
4
5
000012
1234567
|                  12|
|12                  |
Octal: 12, Hex: a

Regex y comprobación de subcadenas

contains(CharSequence s) devuelve true si s es parte de nuestro objeto String (s puede ser un String en sí mismo o un objeto StringBuilder, o realmente cualquier cosa que implemente CharSequence) , de lo contrario devuelve falso.

startsWith(String prefix) devuelve true si nuestro objeto String comienza literalmente con el prefijo dado, de lo contrario, devuelve false.

endsWith(String sufijo) devuelve verdadero si nuestro objeto String termina literalmente con el sufijo dado; de lo contrario, devuelve falso.

matches(String regex) devuelve true si toda nuestra String coincide con la [expresión regular] dada (https://en.wikipedia.org/wiki/Regular_expression).

Todos estos métodos son bastante sencillos. Aunque matches() presupone el conocimiento de expresiones regulares.

1
2
3
4
5
6
String ourString = "This string contains a contains.";

System.out.println(ourString.contains("contains"));
System.out.println(ourString.startsWith("T"));
System.out.println(ourString.endsWith(":)"));
System.out.println(ourString.matches(".*string.*"));

Estas operaciones generan lo siguiente:

1
2
3
4
true
true
false
true

Sustitución de caracteres y subcadenas {#reemplazo de caracteres y subcadenas}

replace(char oldChar, char newChar) reemplaza todas las apariciones de oldChar con newChar.

replace(CharSequence target, CharSequence replace) reemplaza todas las apariciones de la cadena target con la cadena replacement (lo que significa que podemos reemplazar subcadenas completas en lugar de solo caracteres).

replaceAll(String regex, String replace) reemplaza todas las subcadenas que coinciden con el argumento regex con la cadena replacement.

replaceFirst(String regex, String replace) reemplaza solo la primera subcadena que coincide con el argumento regex con la cadena replacement.

Para evitar confusiones, replace() también reemplaza TODAS las apariciones de una secuencia de caracteres, aunque hay un método llamado replaceAll(). La diferencia es que replaceAll() y replaceFirst() usan expresiones regulares para encontrar las secuencias de caracteres que necesitan ser reemplazadas.

1
2
3
4
5
6
String ourString = "We really don't like the letter e here";

System.out.println(ourString.replace('e', 'a'));
System.out.println(ourString.replace("here", "there"));
System.out.println(ourString.replaceAll("e(r+)", "a"));
System.out.println(ourString.replaceFirst("e(r+)", "a"));
1
2
3
4
Wa raally don't lika tha lattar a hara
We really don't like the letter e there
We really don't like the letta e hae
We really don't like the letta e here, only the first occurrence was replaced

División y unión de cadenas

Los métodos split() y join() son dos caras de la misma moneda.

split(String regex) divide esta cadena usando una expresión regular dada y devuelve una matriz de caracteres.

split(String regex, int limit) es similar al método anterior, pero solo divide un número límite de veces.

join(CharSequence delimiter, CharSequence... elementos) por otro lado, devuelve una String que contiene todos los elementos que enumeramos, unidos por el delimitador.

join(CharSequence delimitador, Iterable<? extiende CharSequence> elementos) es una forma muy complicada de decir que podemos usar join() en cosas como listas, para combinar todos los elementos en una String usando el dado delimitador.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
String ourString = "apples, oranges, pears, pineapples";
String[] fruits = ourString.split(",");

System.out.println(Arrays.toString(fruits));

// This is a great place to use the aforementioned trim() method
// to remove the space at the beginning of some of the words
for(int i = 0; i < fruits.length; i++) {
    fruits[i] = fruits[i].trim();
}

System.out.println(Arrays.toString(fruits)); // Arrays.toString() formats the output array on its own
1
2
[apples,  oranges,  pears,  pineapples]
[apples, oranges, pears, pineapples]

Tenga en cuenta que split() toma una expresión regular para decidir dónde dividir la cadena, así que tenga cuidado al usar caracteres que tienen un significado especial en las expresiones regulares.

Dado que esos caracteres son comunes (un problema particular es "." ya que eso significa "cualquier carácter" en expresiones regulares), una forma segura de usar split() es con Pattern.quote(".") lo que asegura que nada se entienda como un carácter especial de expresión regular.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
String ourString = "apples.oranges.pears.pineapples";

// This returns then prints an empty array, since every
// character is interpreted as something to be split at
// and ignored
System.out.println(Arrays.toString(ourString.split(".")));

// The "regex safe" way of doing this would be
System.out.println(Arrays.toString(ourString.split(Pattern.quote("."))));

// Splits our string to two substrings at most,
// completely ignoring all other occurrences of "."
System.out.println(Arrays.toString(ourString.split(Pattern.quote("."), 2))); 
1
2
3
[]
[apples, oranges, pears, pineapples]
[apples, oranges.pears.pineapples]

join() hace exactamente lo contrario de split(). Usamos join() cuando tenemos una matriz/lista/etc. de cadenas (o StringBuilders/StringBuffers) que queremos formar en una nueva String usando algún (o ningún) delimitador.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// A common use is to avoid repetitive concatenation,
// i.e. "1" + "," + "2" + "," + "3" + "," + "4"
System.out.println(String.join(",", "1", "2", "3", "4"));

// We can pass an array or any class that implements
// Iterable (containing character sequences) as the
// second parameter as well
String arrayOfStrings[] = {"1","2","3","4","5"};

System.out.println(String.join("-", arrayOfStrings));
System.out.println(String.join("-", Arrays.asList(arrayOfStrings))); // Works just fine with lists as well

// Join them with an empty string to convert an array
// of Strings to one single String without any extra data
System.out.println(String.join("", arrayOfStrings));
1
2
3
4
1,2,3,4
1-2-3-4-5
1-2-3-4-5
12345

Creación de matrices de caracteres

Este método convierte la String en la que se usa en una matriz de caracteres. Devuelve una nueva matriz de caracteres, que contiene todos los caracteres (en orden) que están en String.

toCharArray() una firma de método sencilla.

1
2
3
String ourString = "These will all become separate characters";

System.out.println(Arrays.toString(ourString.toCharArray()));

Esto imprimirá lo siguiente:

1
[T, h, e, s, e,  , w, i, l, l,  , a, l, l,  , b, e, c, o, m, e,  , s, e, p, a, r, a, t, e,  , c, h, a, r, a, c, t, e, r, s]

Igualdad de cadenas

equals(Object str) compara dos cadenas y devuelve true si las cadenas contienen los mismos caracteres en el mismo orden, y false en caso contrario. La comparación distingue entre mayúsculas y minúsculas (use equalsIgnoreCase() para una comparación que no distingue entre mayúsculas y minúsculas).

Es importante entender que equals() y == realizan dos operaciones diferentes. equals() compara los caracteres dentro de un objeto String, como se mencionó anteriormente, mientras que == compara la igualdad de las referencias de objetos, para ver si se refieren a la misma instancia. Mientras que declaraciones como 1 == 1 devolverán verdadero "string" == "string" podría no hacerlo.

La parte complicada aquí es que la salida de == depende de cómo hayamos inicializado los objetos String que estamos comparando:

1
2
3
4
5
6
7
8
9
String s1 = "Just a String";
String s2 = "Just a String";

System.out.println(s1 == s2);
System.out.println(s1.equals(s2));

s2 = new String("Just a String");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
1
2
3
4
true
true
false
true

equals() devuelve true en ambos casos. Por lo tanto, siempre debe usar equals () a menos que realmente desee ver si dos variables de referencia hacen referencia a la misma instancia, aunque esto es bastante raro.

Conclusión

Es importante comprender los matices de los métodos String y String en Java. Pueden ocurrir errores sutiles y difíciles de encontrar con cosas como split() y caracteres especiales específicos de expresiones regulares, o al usar erróneamente == cuando queríamos usar equals().

Lo mejor es observar siempre cómo funciona un método, probarlo usted mismo para recordar las cosas que debe tener en cuenta. Además, saber qué métodos tienes a tu disposición te ahorra el trabajo innecesario de implementar métodos ya disponibles por ti mismo. smo.

Licensed under CC BY-NC-SA 4.0