1 Cadenas¶
Introducción¶
El texto es uno de los tipos de datos más importantes y por ello java lo trata de manera especial. Las cadenas deben manejarse creando objetos de tipo String. Se pueden inicializar de dos maneras:
- Usando el operador asignación como los primitivos:
String s = "hola"
- Usando el constructor como los objetos:
String s = new String("hola");
Los literales cadena se escriben entre comillas dobles: "Esto es un literal cadena"
.
En Java existe también la cadena vacía o nula(""), es decir, una cadena sin ningún carácter.
Ejemplo: String s = "";
A la variable s se le está asignando la cadena vacía o nula.
Inmutabulidad¶
Uno de los conceptos que suele venir asociado a la programación funcional es el de la inmutabilidad. Si bien es cierto que la inmutabilidad es una idea que no es exclusiva de la programación funcional, sí que cobra una importancia vital en este tipo de lenguajes. La programación funcional se asienta sobre muchos conceptos matemáticos que requieren de la inmutabilidad para seguir siendo válidos. Aún así, es un concepto que es interesante conocer independientemente del tipo de paradigma de programación que se utilice.
¿Qué es la inmutabilidad?¶
La idea es muy sencilla de entender: algo es inmutable cuando no se puede modificar. En el contexto de la programación, una variable es inmutable cuando su valor no se puede modificar. Y un objeto lo es cuando su estado no puede ser actualizado tras la creación del objeto. Es por tanto una forma de asegurar que los objetos no se modifican en lugares inesperados afectando con ello la ejecución de nuestro programa.
La inmutabilidad genera muchas ventajas en las aplicaciones multihilo, donde la inmutabilidad simplifica mucho el tratamiento de la concurrencia. Si algo no se puede modificar, da igual que se acceda a ello desde distintos hilos a la vez, así como el orden en que se haga.
La inmutabilidad hace que el código sea mucho más predecible y más fácil de testear, porque se acota mucho más los lugares donde se producen modificaciones de estado.
La inmutabilidad tiene el sobrecoste de la generación de objetos nuevos cada vez que cambia el estado, así que esto puede penalizar bastante en el rendimiento. Así como guía muy general, es recomendable usar objetos mutables en cualquier situación que requiera de un estado que se modifica a menudo y/o la duplicación de ese estado sea costosa.
La inmutabilidad, por el contrario, presenta ventajas en las siguientes situaciones:
- En objetos que no vayan a requerir modificaciones de estado.
- En objetos que sean simples de duplicar.
- En situaciones de concurrencia.
Así que hay que hacer inmutable todo el código que sea posible ya que es un concepto muy potente que nos puede ayudar a simplificar la complejidad de comprensión de nuestro código y, por tanto, a disminuir las probabilidades de que se produzcan errores inesperados.
En java, los objetos String son inmutables.
Formatos de codificación de caracteres¶
En el Unicode, el Plano Multilingüe Básico (Basic Multilingual Plane, BMP) incluye los 65.536 caracteres cuyos códigos van desde U+0000 a U+FFFF, que son la mayoría de los caracteres utilizados más frecuentemente.
El número 65.536 es 2 elevado a 16, es decir, la cantidad máxima de combinaciones de bits que se pueden obtener en dos bytes.
El resto de caracteres se denominan caracteres complementarios.
Los formatos de codificación que se pueden usar con Unicode se denominan UTF-8, UTF-16 y UTF-32:
UTF-8 utiliza 1 byte para representar caracteres ASCII, dos bytes para caracteres en otros bloques alfabéticos y tres bytes para el resto del BMP. Para los caracteres complementarios se utilizan 4 bytes.
UTF-16 utiliza 2 bytes para cualquier carácter en el BMP y 4 bytes para los caracteres complementarios.
UTF-32 emplea 4 bytes para todos los caracteres.
En Java, las cadenas utilizan el formato de codificación UTF-16.
Formateo de cadenas¶
Hay un método estático en la clase String que sirve para construir una cadena con cierto formato. Funciona de la misma manera que el método printf
que vimos en el tema 1.12. Escritura en pantalla.
public class StringFormat {
public static void main(String[] args) {
String formattedString;
formattedString = String.format("Nombre: %s Edad: %d Sueldo: %.2f", "Juan", 20, 1896.23);
System.out.println(formattedString);
}
}
Métodos de la clase String¶
Si observamos en la API la clase String, incluye métodos para examinar los caracteres individuales de una cadena, para comparar cadenas, para buscar cadenas, para extraer subcadenas, para convertir cadenas a mayúsculas o minúsculas, etc.
Como vimos en el Tema 1.5 - Operadores, el operador concatenación +
es un operador binario que devuelve una cadena resultado para concatenar las dos cadenas que actúan como operandos. Si sólo uno de los operandos es de tipo cadena, el otro operando se convierte implícitamente en tipo cadena.
Obsérvese en la API en el método valueOf, es estático y está sobrecargado. Sirve para obtener la representación String de un valor u objeto.
public class StringConcatPlus {
public static void main(String[] args) {
int i = 100;
String string1, string2, string3, string4;
string1 = "Esto es un literal cadena"; //(1)!
System.out.println(string1);
System.out.println(string1 + " al cual le hemos concatenado este literal cadena"); //(2)!
string2 = "hola";
string3 = " que tal";
string4 = string2 + string3;
System.out.println(string4);
System.out.println(i + 100);
System.out.println(String.valueOf(i) + 100);
}
}
- Se le da un valor inicial con el operador asignación
- Se concatena otra cadena con el operador +
Otros métodos de las cadenas muy útiles son:
- charAt: devuelve el carácter de la cadena del especificado índice. Dicho índice empieza en cero, es decir, con el cero se obtiene el primer carácter de la cadena.
- length: devuelve la longitud de la cadena.
- equals: compara si dos cadenas son iguales. Las cadenas se comparan con equals como los objetos y los primitivos se comparan con
==
. - equalsIgnoreCase: hace lo mismo que el anterior pero no tiene en cuenta las mayúsculas y minúsculas.
public class StringMethods {
public static void main(String[] args) {
String string = "hola";
System.out.println(string.charAt(0));//h
System.out.println(string.charAt(1));//o
System.out.println(string.charAt(2));//l
System.out.println(string.charAt(3));//a
System.out.println(string.length());//4
System.out.println(string.equals("hola"));//true
System.out.println(string.equals("Hola"));//false
System.out.println(string.equals("adiós"));//false
System.out.println(string.equalsIgnoreCase("Hola"));//true
System.out.println(string.equalsIgnoreCase("HOLA"));//true
//También se le pueden aplicar métodos a un literal cadena:
System.out.println("hola".equals("hola")); //true
System.out.println("adios".equals("hola"));//false
}
}
Más métodos de cadenas interesantes:
- compareTo: compara dos cadenas lexicográficamente. La comparación se basa en el valor Unicode de cada carácter de las cadenas.
s1.compareTo(s2)
devuelve un número negativo si s1 es menor, un número positivo si s1 es mayor o cero si son iguales. - compareToIgnoreCase: hace lo mismo que el anterior pero no tiene en cuenta mayúsculas y minúsculas.
- concat: se utiliza para concatenar cadenas, como el operador
+
. - endsWith: devuelve true si la cadena termina con un determinado texto.
- startsWith: devuelve true si la cadena empieza con un determinado texto.
- indexOf: devuelve la primera posición en la que aparece un determinado texto en la cadena. En el caso de que el texto buscado no se encuentre, devuelve -1. Este método está sobrecargado para que el texto a buscar pueda ser char o String.
- lastIndexOf: es como el anterior pero busca desde el final.
- isEmpty: devuelve true si la cadena está vacía, es decir, si su longitud es cero.
- repeat: devuelve una cadena cuyo valor es la concatenación de la cadena repetida varias veces.
- replace: reemplaza todas las apariciones de un texto por otro texto. Este método está sobrecargado para que el texto pueda ser char o String.
- substring: obtiene una subcadena.
- toLowerCase: devuelve la cadena en minúsculas.
- toUpperCase: devuelve la cadena en mayúsculas.
- trim: elimina los espacios en blanco del principio y del final de la cadena.
public class StringOtherMethods {
public static void main(String[] args) {
String string1 = "hola", string2 = "adios", string3 = "Hola", string4;
//hola es mayor que adios
System.out.println(string1.compareTo(string2) > 0 ? String.format("%s es mayor que %s", string1, string2)
: String.format("%s es menor que %s", string1, string2));
//adios es menor que hola
System.out.println(string2.compareTo(string1) > 0 ? String.format("%s es mayor que %s", string2, string1)
: String.format("%s es menor que %s", string2, string1));
//En el Unicode, las mayúsculas están antes: Hola es menor que adios
System.out.println(string3.compareTo(string2) > 0 ? String.format("%s es mayor que %s", string3, string2)
: String.format("%s es menor que %s", string3, string2));
//Hola es mayor que adios si no tenemos en cuenta las mayúsculas y minúsculas
System.out.println(string3.compareToIgnoreCase(string2) > 0
? String.format("%s es mayor que %s si no tenemos en cuenta las mayúsculas y minúsculas", string3, string2)
: String.format("%s es menor que %s si no tenemos en cuenta las mayúsculas y minúsculas", string3, string2));
System.out.println(string4 = string1.concat(" que tal"));//string4="hola que tal"
System.out.println(string4.endsWith("tal"));//true
System.out.println(string4.endsWith("hola"));//false
System.out.println(string4.startsWith("hola"));//true
System.out.println(string4.startsWith("tal"));//false
System.out.println(string4.indexOf("hola"));//0
System.out.println(string4.indexOf("tal"));//9
System.out.println(string4.indexOf("que"));//5
System.out.println(string4.indexOf(string2));//-1
System.out.println(string4.indexOf(string3));//-1
System.out.println(string4.indexOf('a'));//3
System.out.println("hola que tal hola que tal".lastIndexOf("tal"));//22
System.out.println(string4.isEmpty());//false
System.out.println("".isEmpty());//true
System.out.println("ole ".repeat(6));//ole ole ole ole ole ole
System.out.println(string4.replace('a', '*'));//hol* que t*l
System.out.println("hola que tal hola que tal".replace("hola",
"buenas"));//buenas que tal buenas que tal
//Para hacer desaparecer partes de una cadena, se reemplazan por cadena vacía
System.out.println("hola que tal hola que tal".replace(" ",""));//holaquetalholaquetal
System.out.println(string4.substring(9));//tal
System.out.println(string4.substring(5, 8));//que
System.out.println("HOLA QUE TAL".toLowerCase());//hola que tal
System.out.println("hola que tal".toUpperCase());//HOLA QUE TAL
System.out.println(" Hola que tal ".trim());//Hola que tal
}
}
Ejercicios¶
Ejercicio 1
Realiza una función que reciba una cadena y devuelva el número de vocales que tiene.
Ejercicio 2
Realiza una función que reciba una cadena y devuelva otra cadena igual pero sin espacios en blanco. No se pueden utilizar métodos replace.
Ejercicio 3
Realiza una función que reciba una cadena y un carácter y devuelva otra cadena igual pero con todas las apariciones del carácter reemplazadas por un asterisco. No se pueden utilizar métodos replace.
Ejercicio 4
Realiza una función que reciba una cadena y un carácter y devuelva el número de apariciones del carácter en la cadena. No se pueden utilizar los métodos indexOf ni contains.
Ejercicio 5
Realiza una función que reciba una cadena y un carácter y devuelva el número de caracteres que hay entre la primera y la última aparición del carácter en la cadena. No se pueden utilizar los métodos indexOf ni contains.
Ejercicio 6
Realiza una función que reciba dos cadenas y devuelva la concatenación de ambas. El método concat o el operador + solamente se pueden utilizar a nivel de carácter.
Ejercicio 7
Realiza una función que reciba una cadena y un número y devuelva otra cadena con los primeros caracteres de cadena, tantos como indique el parámetro. No se puede utilizar el método substring. Por ejemplo, si recibe "Programación" y 5, devuelve "Progr".
Ejercicio 8
Realiza una función que reciba una cadena y un número y devuelva otra cadena con los últimos caracteres de la cadena, tantos como indique, el parámetro. No se puede utilizar el método substring. Por ejemplo, si recibe "Programación" y 5, devuelve "ación".
Ejercicio 9
Realiza una función que reciba una cadena y devuelva otra cadena con los caracteres en orden inverso. Por ejemplo, si recibe "hola", devuelve "aloh".
Ejercicio 10
Realiza una función que reciba una cadena y devuelva la suma de todos los dígitos que hay en ella. Por ejemplo, si recibe "abc12de3f4gh", devuelve 10.
Ejercicio 11
Realiza una función que reciba dos cadenas y devuelva el número de apariciones de una de ellas en la otra. No se pueden utilizar los métodos indexOf, contains ni substring. Hacer las comparaciones a nivel de carácter. Por ejemplo, si recibe "Estoy matriculado en Programación, en Entornos y en Marcas" y "en", devuelve 3. Si recibe "hola que tal, hola que pasa, hola" y "hola", devuelve 3.
Ejercicio 12
Realiza una función que reciba una cadena y devuelva el número de palabras que tiene. Hacer las comparaciones a nivel de carácter. No se pueden utilizar métodos replace, indexOf ni trim. Las palabras dentro de la cadena están separadas por un espacio. Por ejemplo, si recibe "Estoy matriculado en Programación en Entornos y en Marcas", devuelve 9. Si recibe " Estoy matriculado en Programación en Entornos y en Marcas ", es decir, con un espacio al principio y otro al final, devuelve 9.
Ejercicio 13
Realiza una función que reciba una cadena y devuelva el número de palabras que tiene. Hacer las comparaciones a nivel de carácter. No se pueden utilizar métodos replace ni indexOf. Las palabras dentro de la cadena pueden estar separadas por más de un espacio. No se pueden eliminar los espacios de la cadena. Por ejemplo, si recibe "Estoy matriculado en Programación en Entornos y en Marcas", devuelve 9.