Cómo usar la clase Properties en Java

Cuando desarrollamos aplicaciones en Java, es muy común que no queramos incluir la configuración directamente en el código. Por ejemplo, datos sensibles como una API Key, contraseñas para bases de datos o credenciales para acceder a servicios externos no deberían estar hardcodeados. Esto es algo que puede valer para prototipos o ejemplos pequeños, pero en aplicaciones reales lo ideal es manejar esta configuración desde archivos externos o algún sistema que permita modificar estos datos sin tocar el código fuente.

Además, en ocasiones necesitamos guardar información localmente para consultarla en ejecuciones posteriores, como la hora de la última ejecución de un programa para decidir si realizar tareas de mantenimiento. Aunque podríamos crear un archivo de texto plano y guardar cada dato en una línea, esta solución no escala bien. Leer y escribir datos en orden, línea por línea, puede volverse complicado y propenso a errores.

Para evitar reinventar la rueda, Java nos ofrece la clase Properties dentro del paquete java.util. Esta clase nos permite almacenar pares clave-valor en memoria y luego guardarlos o cargarlos desde archivos o streams, facilitando la persistencia y recuperación de configuraciones o datos temporales.

Para empezar a usar Properties, simplemente creamos una instancia con su constructor vacío:

Properties props = new Properties();

Aunque internamente Properties se comporta como un mapa, está diseñado para trabajar exclusivamente con cadenas de texto. Por eso, en lugar de usar métodos genéricos como put o get, utilizamos setProperty para asignar valores y getProperty para recuperarlos. Por ejemplo, podemos definir propiedades relacionadas con la base de datos así:

props.setProperty("database.host", "localhost");
props.setProperty("database.username", "root");
props.setProperty("database.password", "1234");

Si queremos guardar números u otros objetos, debemos convertirlos a cadenas, por ejemplo usando toString(). Para recuperar las claves almacenadas, podemos usar el método stringPropertyNames(), que nos devuelve un conjunto de nombres de propiedades. Así, podemos iterar sobre ellas y obtener sus valores con getProperty:

for (String key : props.stringPropertyNames()) {
    System.out.println(key + " = " + props.getProperty(key));
}

Una forma más rápida de imprimir todas las propiedades es usar el método list, que acepta un PrintStream o PrintWriter. Por ejemplo, para imprimir en consola:

props.list(System.out);

Cuando queremos guardar estas propiedades en un archivo, utilizamos el método store. Este método escribe las propiedades en formato texto plano, con cada línea en la forma clave=valor. También podemos añadir un comentario que aparecerá al inicio del archivo:

try (OutputStream out = Files.newOutputStream(Paths.get("config.properties"))) {
    props.store(out, "Configuración de la aplicación");
}

Es importante no usar el método save, ya que está deprecado y no lanza excepciones en caso de error, lo que dificulta detectar problemas al guardar.

Si preferimos guardar las propiedades en formato XML, podemos usar storeToXML, que genera un archivo XML con las claves y valores, facilitando la interoperabilidad con otros sistemas o lenguajes:

try (OutputStream out = Files.newOutputStream(Paths.get("config.xml"))) {
    props.storeToXML(out, "Configuración XML");
}

Para cargar propiedades desde un archivo, usamos el método load, que acepta un InputStream o un Reader. Por ejemplo, para leer desde un archivo de texto:

Properties props = new Properties();
try (InputStream in = Files.newInputStream(Paths.get("config.properties"))) {
    props.load(in);
}

Si el archivo no existe o hay un error de lectura, se lanzará una excepción que podemos capturar para manejar el fallo.

Al recuperar propiedades, puede ocurrir que una clave no exista en el archivo. En ese caso, getProperty devuelve null. Para evitar problemas, podemos usar la sobrecarga que acepta un valor por defecto, que se devuelve si la clave no está presente:

String host = props.getProperty("database.host");
String port = props.getProperty("database.port", "3306");
System.out.println("Host: " + host);
System.out.println("Port: " + port);

Así, si database.port no está definido, se usará "3306" como valor predeterminado.

En resumen, la clase Properties nos ofrece una forma sencilla y eficiente de manejar configuraciones externas en Java, permitiendo guardar y cargar datos en archivos de texto o XML, con soporte para comentarios y valores por defecto. Esto mejora la flexibilidad y seguridad de nuestras aplicaciones al separar la configuración del código fuente.

Lista de reproducción
  1. 1
    ¿Cómo funciona Comparator en Java?
    10 minutos
  2. 2
    ¿Para qué sirve Override?
    4 minutos
  3. 3
    Cómo usar la clase Properties en Java
    14 minutos
  4. 4
    Interfaces funcionales y funciones flecha
    8 minutos
  5. 5
    Bloque static de Java: inicializadores estáticos y otros usos
    7 minutos
  6. 6
    import static, ¿para qué sirve?
    3 minutos
  7. 7
    Uso de Optional en Java
    10 minutos
  8. 8
    Introducción al Scanner de Java
    11 minutos
  9. 9
    ¿Para qué sirve el modificador static de Java?
    6 minutos
  10. 10
    Funciones variádicas en Java
    6 minutos
  11. 11
    Inner classes en Java
    8 minutos
  12. 12
    var en Java: una introducción para gente nueva
    7 minutos
  13. 13
    Switch expressions en Java
    10 minutos
  14. 14
    Java: del instanceof al Pattern Matching
    7 minutos
  15. 15
    Sealed classes en Java
    8 minutos
  16. 16
    Getters y setters o atributos públicos en Java, ¿qué es mejor?
    9 minutos
  17. 17
    El String[] args del método main de Java
    8 minutos
  18. 18
    Introducción a clases anónimas en Java
    6 minutos
  19. 19
    Introducción a enum en Java
    6 minutos