Tips para programadores

Aprende un nuevo lenguaje

Es sabido que no debes enfocarte en una sola tecnología o lenguaje de programación.   Pero el sentido de este consejo no es sólo que escojas una tecnología que te permita ganar más dinero (que también es una buena idea), sino que además de eso te permita experimentar y hacer cosas diferentes. Por ejemplo, si siempre has estado enfocado a aplicaciones WEB, puedes comenzar a experimentar con el control de motores eléctricos o para obtener datos desde sensores o hardware que no hayas usado anteriormente, o probar también con aplicaciones para móviles, tendrás una perspectiva más amplia de lo que es el desarrollo de software.

Ten un  «Pet Project»

Todos tenemos ideas para una aplicación o desarrollo que nos gustaría programar.  Sin embargo pocas veces las materializamos.  Esto no sólo es malo porque pierdes la oportunidad de llevar a cabo una buena idea, sino que también es posible que nunca sepas si esa idea es mala o que en realidad no sea tan útil, o peor aún, que ya exista algo parecido porque no habías investigado demasiado y te enfoques mejor en otra cosa.  Adquiere el hábito de tener al menos un proyecto y ve agregando características poco a poco pero de forma constante.

Relaciónate con personas que hagan cosas diferentes

No sólo se trata de encontrar gente que use otras tecnologías, sino otras formas de hacer negocios y de ganar dinero.  Es posible que encuentres oportunidades donde otros no las han visto, tan sólo porque no ha llegado nadie para propornerlas.  No te enfoques sólo a entender los problemas de los clientes de la empresa donde trabajes.

Haz que tu trabajo se vea elegante

Son muchos los desarrolladores que descuidan el aspecto visual de su trabajo y sólo se preocupan porque funcione correctamente.  Sin embargo una apariencia visual o usabilidad deficientes, pueden hacer que el usuario tenga una impresión equivocada sobre como funcionan tus desarrollos y llegue a pensar que tiene errores aún cuando esto no sea verdad, recuerda que haces desarrollo para facilitarle la vida a personas que no siempre tienen un conocimiento técnico silimar al tuyo.

No inventes cosas que ya están bien hechas

Lenguajes como Java o C# no son los más ampliamente usados por su sintaxis o su facilidad de uso, sino por la inmensa variedad de librerías o herramientas que existen y que puedes usar libremente, con la seguridad de que van a funcionar correctamente. No gastes tu tiempo tratndo de hacer algo que ya existe si no lo vas a superar.

Comparte y acepta críticas a tu código

Es universal. Ocurre en todas las profesiones. A nadie le gusta que le digan como hacer cosas que uno supone hace bien.  Pero compartir ideas y tomar en cuenta las recomendaciones de otros es casi tan útil como Google para aprender cosas nuevas.  Además mejoras tu ambiente laboral.

Crea librerías de ejemplos o soluciones

No es que tengas que desarrollar librerías nuevas, se trata más bien de esos ejemplos, como conectarte a bases de datos, nombres de drivers, herramientas, comandos, funciones o técnicas de desarrollo que quizá aplicarás en tus proyectos más de una vez. En cualquier momento puedes usar el buscador y encontrar prácticamente todo lo que necesites, pero tener cosas ya probadas previamente por tí, es muy útil.

Descansa lejos de la computadora

Esto debes hacerlo por puro amor propio y no sólo es descansar, ejercítate.  Algunos problemas de espalda y ojos derivados de pasar horas sentados frente a la computadora pueden agravarse y son difíciles de tratar.  Cuida tu cuerpo.

 

El método main en Java: por qué public static void, y qué cambió en Java 25

Durante casi treinta años, todo programa de Java empezó por public static void main(String[] args). ¿Por qué cada una de esas palabras? ¿Qué pasa si lo declaras privado? Y una novedad: desde Java 25 ya no hace falta escribirlo así.

Si es privado, no arranca

public class Privado {
    private static void main(String[] args) {
        System.out.println("hola");
    }
}
javac Privado.java
java Privado
salidaError: Main method not found in class Privado, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
[código 1]

Compila sin protestar, porque para el compilador es un método privado más. El que falla es el lanzador, el programa java, al buscar por dónde empezar: no encuentra un main que pueda llamar y termina con código 1. Es el mismo mensaje en Java 21 y en Java 25.

Cada palabra, y por qué está

PalabraPor qué
publicQuien llama al método es el lanzador, desde fuera de la clase y del paquete. Necesita poder verlo.
staticAl arrancar no existe ningún objeto de la clase. Un método estático se puede llamar sin crear uno.
voidEl programa no devuelve su resultado con return. El código de salida que ve el sistema operativo se fija con System.exit(n).
String[] argsLos argumentos de la línea de órdenes, ya separados. args[0] es el primero, no el nombre del programa.

El void es el que más se explica mal. No tiene que ver con que Java sea multiplataforma: un int es igual en todas partes. Es una decisión de diseño. En Java el programa puede tener varios hilos, y terminar main no tiene por qué terminar el programa, así que no tendría sentido que su return fuera el código de salida. Para eso está System.exit:

public class Codigo {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.err.println("falta el nombre del archivo");
            System.exit(2);
        }
        System.out.println("procesando " + args[0]);
    }
}
java Codigo  /  java Codigo datos.csvfalta el nombre del archivo
[código 2]
procesando datos.csv
[código 0]

Si main termina con normalidad, el código es 0. Si se escapa una excepción, el programa termina con código 1, sin necesidad de llamar a nada:

java Fallaantes del error
Exception in thread "main" java.lang.NumberFormatException: For input string: "doce"
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
	at java.base/java.lang.Integer.parseInt(Integer.java:565)
	at java.base/java.lang.Integer.parseInt(Integer.java:662)
	at Falla.main(Falla.java:4)
[código 1]

Lo que cambió en Java 25

Java 25 incorpora de forma definitiva los archivos fuente compactos y los main de instancia. Para un programa pequeño basta con esto:

void main() {
    IO.println("hola desde un main de Java 25");
}
java Moderno.javahola desde un main de Java 25

Sin clase, sin public, sin static y sin args. El compilador envuelve el archivo en una clase implícita, e IO.println es un atajo nuevo para escribir en la consola. Dentro de una clase normal, el main también puede ser de instancia:

public class Instancia {
    private final String saludo = "hola desde un main de instancia";

    void main() {
        System.out.println(saludo);
    }
}
java Instanciahola desde un main de instancia

Si el main no es estático, el lanzador crea primero un objeto con el constructor sin parámetros y después llama al método. Por eso aquí se puede usar el campo saludo directamente.

En Java 21 nada de esto funciona sin activar las funciones en pruebas: el archivo compacto no compila, y la clase Instancia da el mismo «Main method not found» que la de antes.

javac Moderno.java  —  Java 21Moderno.java:1: error: unnamed classes are a preview feature and are disabled by default.
void main() {
^
  (use --enable-preview to enable unnamed classes)

Las reglas nuevas

FormaJava 21Java 25
public static void main(String[] args)SíSí
static void main(), sin public ni parámetrosNoSí
void main() de instancia, en una claseNoSí
void main() suelto, sin claseNoSí
private static void main(String[] args)NoNo

El main puede ser público, protegido o de paquete, pero nunca privado. Y si una clase tiene dos main válidos, gana el que recibe String[] args:

public class Ambos {
    public static void main(String[] args) {
        System.out.println("el de String[] args");
    }
    static void main() {
        System.out.println("el que no tiene parámetros");
    }
}
java Ambosel de String[] args

La forma clásica sigue funcionando igual, y es la que encontrarás en casi todo el código existente. Las nuevas están pensadas para empezar y para programas cortos, como los de nuestro curso de Java.

Entrada publicada en 2012 y revisada en octubre de 2026. Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio; las salidas están copiadas de esa ejecución.

String, StringBuffer y StringBuilder en Java: diferencias y cuándo usar cada uno

En Java hay tres clases para trabajar con texto: String, StringBuilder y StringBuffer. La diferencia cabe en una línea: String no se puede modificar, las otras dos sí, y de esas dos solo StringBuffer está sincronizada para usarse desde varios hilos. Lo interesante es lo que eso significa en la práctica, y aquí lo vemos con ejemplos probados en Java 25.

StringStringBuilderStringBuffer
¿Se puede modificar?No (inmutable)SíSí
¿Segura entre hilos?Sí, porque no cambiaNoSí, sus métodos están sincronizados
Velocidad al construir textoLenta si se concatena en un bucleLa más rápidaAlgo más lenta que StringBuilder
DesdeJava 1.0Java 5Java 1.0
Úsala para…Casi todo: valores, claves, parámetrosConstruir texto por partesCódigo antiguo o un búfer compartido entre hilos

String es inmutable

Un objeto String no cambia nunca después de crearse. Cuando parece que lo modificas, por ejemplo con +, replace o toUpperCase, en realidad Java crea un String nuevo y deja el original como estaba. Con StringBuilder pasa lo contrario: append modifica el mismo objeto, y cualquier variable que apunte a él ve el cambio.

public class Inmutable {
    public static void main(String[] args) {
        String saludo = "Hola";
        String otro = saludo;
        saludo = saludo + " mundo";      // crea un String nuevo

        System.out.println(saludo);      // Hola mundo
        System.out.println(otro);        // Hola: el original no cambió

        StringBuilder sb = new StringBuilder("Hola");
        StringBuilder mismo = sb;
        sb.append(" mundo");             // modifica el mismo objeto

        System.out.println(sb);          // Hola mundo
        System.out.println(mismo);       // Hola mundo: es el mismo objeto
    }
}
java InmutableHola mundo
Hola
Hola mundo
Hola mundo

La inmutabilidad no es un capricho. Permite que Java comparta las cadenas literales en memoria, que un String sirva sin riesgo como clave de un HashMap y que se pueda pasar a cualquier método o hilo sabiendo que nadie lo va a alterar. Lo explicamos con más detalle en qué es un objeto inmutable en Java.

El problema de concatenar en un bucle

La inmutabilidad tiene un coste cuando se construye un texto poco a poco. Cada s += algo crea un String nuevo y copia en él todo lo que había antes. En un bucle de cien mil vueltas, eso son cien mil copias de un texto cada vez más largo. StringBuilder, en cambio, va añadiendo al final de un búfer interno que solo crece de vez en cuando.

public class Bucle {
    static final int N = 100_000;

    static String conMas() {
        String s = "";
        for (int i = 0; i < N; i++) {
            s += i % 10;                 // copia todo el texto en cada vuelta
        }
        return s;
    }

    static String conBuilder() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < N; i++) {
            sb.append(i % 10);           // añade al final del mismo búfer
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        for (int ronda = 0; ronda < 3; ronda++) {   // la primera ronda calienta la JVM
            long t0 = System.nanoTime();
            String a = conMas();
            long t1 = System.nanoTime();
            String b = conBuilder();
            long t2 = System.nanoTime();
            System.out.printf("ronda %d: con + %d ms | con StringBuilder %,.2f ms | iguales: %b%n",
                    ronda + 1, (t1 - t0) / 1_000_000, (t2 - t1) / 1e6, a.equals(b));
        }
    }
}
java Bucleronda 1: con + 751 ms | con StringBuilder 3.91 ms | iguales: true
ronda 2: con + 559 ms | con StringBuilder 0.59 ms | iguales: true
ronda 3: con + 499 ms | con StringBuilder 0.46 ms | iguales: true

El resultado es el mismo texto, pero con + tarda unas doscientas veces más en la primera ronda y más de mil veces más en las siguientes. El tiempo exacto depende del equipo y cambia en cada ejecución, pero la diferencia de escala no: con + el trabajo crece con el cuadrado del número de vueltas, y con StringBuilder, de forma lineal. La primera ronda es más lenta en los dos casos porque la máquina virtual todavía no ha optimizado el código.

¿Y fuera de los bucles? Concatenar con + en una sola expresión, como "Hola, " + nombre + ".", está bien y es lo más legible. El texto original de esta entrada, de 2012, decía que Java lo convierte internamente en un StringBuffer o un StringBuilder. Eso era cierto hasta Java 8. Desde Java 9, el compilador genera una llamada a makeConcatWithConstants y la máquina virtual elige la mejor forma de unir las piezas al ejecutar el programa. Se puede ver con javap.
public class Concat {
    static String saludo(String nombre, int edad) {
        return "Hola, " + nombre + ". Tienes " + edad + " años.";
    }
    public static void main(String[] args) {
        System.out.println(saludo("Ana", 30));
    }
}
javap -c Concat (extracto)  static java.lang.String saludo(java.lang.String, int);
    Code:
         0: aload_0
         1: iload_1
         2: invokedynamic #7,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;
         7: areturn

Los métodos de StringBuilder

StringBuilder y StringBuffer tienen exactamente los mismos métodos. Los más usados son append para añadir al final, insert para meter texto en una posición, delete y replace para quitar o sustituir un tramo, setCharAt para cambiar un carácter, reverse para darle la vuelta y toString para obtener el String final.

public class Metodos {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("decodigo");
        sb.append(".com");               // decodigo.com
        sb.insert(0, "https://");        // https://decodigo.com
        System.out.println(sb);

        sb.replace(0, 8, "");            // quita "https://"
        sb.setCharAt(0, 'D');            // Decodigo.com
        System.out.println(sb);

        sb.delete(sb.length() - 4, sb.length());   // quita ".com"
        System.out.println(sb.reverse());          // ogidoceD
        System.out.println("longitud " + sb.length() + ", capacidad " + sb.capacity());
    }
}
java Metodoshttps://decodigo.com
Decodigo.com
ogidoceD
longitud 8, capacidad 24

La capacidad es el tamaño del búfer interno: al crear un StringBuilder a partir de un texto, Java reserva su longitud más 16 caracteres, por eso sale 24. Cuando el texto no cabe, el búfer se amplía solo. Si sabes de antemano que vas a construir un texto grande, puedes indicar la capacidad inicial con new StringBuilder(10_000) y te ahorras esas ampliaciones.

StringBuffer y los hilos

La única diferencia entre StringBuffer y StringBuilder es que los métodos de StringBuffer están sincronizados: si dos hilos llaman a append a la vez, uno espera a que termine el otro. En este ejemplo, dos hilos añaden cien mil caracteres cada uno al mismo objeto.

public class Hilos {
    public static void main(String[] args) throws InterruptedException {
        for (int prueba = 1; prueba <= 3; prueba++) {
            StringBuilder builder = new StringBuilder();
            StringBuffer buffer = new StringBuffer();
            Runnable tarea = () -> {
                for (int i = 0; i < 100_000; i++) {
                    builder.append('x');
                    buffer.append('x');
                }
            };
            Thread h1 = new Thread(tarea), h2 = new Thread(tarea);
            h1.start(); h2.start();
            h1.join(); h2.join();
            System.out.printf("prueba %d: StringBuilder %d | StringBuffer %d (esperado 200000)%n",
                    prueba, builder.length(), buffer.length());
        }
    }
}
java Hilosprueba 1: StringBuilder 193695 | StringBuffer 200000 (esperado 200000)
prueba 2: StringBuilder 196891 | StringBuffer 200000 (esperado 200000)
prueba 3: StringBuilder 176761 | StringBuffer 200000 (esperado 200000)

Con StringBuilder se pierden caracteres, y en cada ejecución una cantidad distinta: los dos hilos escriben a la vez en la misma posición del búfer. A veces el programa incluso falla con una ArrayIndexOutOfBoundsException. Con StringBuffer siempre salen los 200000.

Entonces, ¿uso StringBuffer? Casi nunca. Lo normal es que cada hilo construya su propio texto en una variable local, y para eso StringBuilder es lo correcto y no necesita sincronización. Compartir un búfer de texto entre hilos es raro, y la sincronización de StringBuffer solo protege cada llamada por separado: dos append seguidos de un hilo pueden quedar intercalados con los de otro. StringBuffer existe sobre todo por compatibilidad con el código anterior a Java 5, cuando no había otra opción.

Cuidado al comparar

Un error clásico: StringBuilder no redefine equals, así que dos objetos con el mismo texto no son «iguales» para Java. Para comparar el contenido, hay que pasarlos a String, usar compareTo, disponible desde Java 11, o contentEquals.

public class Comparar {
    public static void main(String[] args) {
        StringBuilder a = new StringBuilder("java");
        StringBuilder b = new StringBuilder("java");

        System.out.println(a.equals(b));                 // false: compara si son el mismo objeto
        System.out.println(a.toString().equals(b.toString()));  // true
        System.out.println(a.compareTo(b) == 0);         // true (desde Java 11)
        System.out.println("java".contentEquals(a));     // true
    }
}
java Compararfalse
true
true
true

Alternativas modernas

Muchas veces ni siquiera hace falta un StringBuilder. Para unir una lista con un separador están String.join y Collectors.joining; para repetir un texto, repeat; para dar formato, formatted; y para textos de varias líneas, los bloques de texto con tres comillas. Por debajo usan StringBuilder o algo equivalente, y el código queda más claro.

import java.util.List;
import java.util.stream.Collectors;

public class Modernos {
    public static void main(String[] args) {
        List<String> lenguajes = List.of("Java", "Go", "Rust");

        System.out.println(String.join(", ", lenguajes));                         // Java, Go, Rust
        System.out.println(lenguajes.stream().collect(Collectors.joining(" | ", "[", "]")));
        System.out.println("-".repeat(20));                                        // Java 11
        System.out.println("%s tiene %d letras".formatted("Java", 4));            // Java 15

        String json = """
                {"lenguaje": "Java", "version": 25}
                """;                                                               // bloque de texto, Java 15
        System.out.print(json);
    }
}
java ModernosJava, Go, Rust
[Java | Go | Rust]
--------------------
Java tiene 4 letras
{"lenguaje": "Java", "version": 25}

Cuál usar

  • String para casi todo: guardar un texto, pasarlo entre métodos o usarlo como clave. Y + para concatenar en una sola expresión.
  • StringBuilder cuando construyes un texto en un bucle o por partes. Es la opción por defecto para texto que cambia.
  • StringBuffer solo si mantienes código antiguo que ya lo usa o si de verdad varios hilos escriben en el mismo búfer, y aun así conviene pensar si no es mejor que cada hilo tenga el suyo.
  • String.join, Collectors.joining, repeat o los bloques de texto cuando encajan, porque hacen lo mismo con menos código.

Si estás empezando con Java, en el curso de Java tienes los tipos y métodos explicados desde cero, y en medir el rendimiento en Java, cómo comparar tiempos como los de este artículo con más rigor.

Todos los ejemplos se compilaron y ejecutaron con Java 25 (Eclipse Temurin 25.0.4). Los tiempos y los recuentos de la prueba con hilos cambian en cada ejecución. Referencias: documentación de StringBuilder y StringBuffer, y JEP 280: concatenación con invokedynamic.

Anti-patrones en Java: concatenar cadenas en un bucle

Ir sumando trozos a una cadena con += dentro de un bucle es de esos errores que no se notan con diez elementos y que, con cien mil, dejan un proceso parado varios segundos. Lo medimos, y vemos de paso que la versión clásica tiene además un fallo con las listas vacías.

El código del problema

record Persona(String nombre) {}

String conMas(List<Persona> personas) {
    String s = "";
    for (Persona p : personas) s += ", " + p.nombre();
    return s.substring(2);
}

Funciona, y con tres nombres devuelve Ana, Luis, Marta. El problema es que las cadenas de Java no se pueden modificar: cada += crea una cadena nueva y copia en ella todo lo que ya había más el trozo nuevo. En la vuelta mil se copian los 999 nombres anteriores; en la diez mil, los 9,999. El trabajo total crece con el cuadrado del número de elementos.

Medido

Comparamos esa función con la versión de StringBuilder que hay más abajo, tomando la mejor de cinco ejecuciones para cada tamaño:

long medir(java.util.function.Supplier<String> f) {
    long mejor = Long.MAX_VALUE;
    for (int r = 0; r < 5; r++) {
        long t = System.nanoTime(); f.get(); mejor = Math.min(mejor, System.nanoTime() - t);
    }
    return mejor;
}
java Medir.javapersonas        +=   StringBuilder
     10,000       70 ms       1.18 ms
     20,000      260 ms       0.47 ms
     40,000     1001 ms       0.62 ms
     80,000     4338 ms       0.91 ms

Los milisegundos dependen de la máquina; lo que hay que mirar es cómo crecen. Cada vez que se dobla la lista, += tarda unas cuatro veces más: 70, 260, 1001, 4338. Es la firma de un algoritmo cuadrático. StringBuilder se queda en torno al milisegundo en todos los casos (a esas escalas el ruido de la medida pesa más que el trabajo, y por eso no crece de forma ordenada).

Y además falla con la lista vacía

El substring(2) del final quita la coma y el espacio que sobran al principio. Pero si la lista está vacía, no hay nada que quitar:

conMas(List.of())  —  salida recortadaException in thread "main" java.lang.StringIndexOutOfBoundsException: Range [2, 0) out of bounds for length 0
	...
	at Concatenar.conMas(Concatenar.java:9)

Es el típico arreglo que funciona en todas las pruebas hasta el día en que llega una lista vacía.

La versión con StringBuilder

String conBuilder(List<Persona> personas) {
    var sb = new StringBuilder();
    for (Persona p : personas) {
        if (sb.length() > 0) sb.append(", ");
        sb.append(p.nombre());
    }
    return sb.toString();
}

StringBuilder sí se puede modificar: va añadiendo al final de un búfer que crece cuando hace falta, así que cada nombre se copia una sola vez. Y la coma se pone antes de cada elemento salvo el primero, con lo que no hay nada que quitar al final y la lista vacía devuelve una cadena vacía.

Se le puede pasar una capacidad inicial, new StringBuilder(personas.size() * 16), para que no tenga que crecer por el camino. Es una mejora pequeña: el crecimiento ya es eficiente, y la diferencia de verdad está entre += y StringBuilder, no entre poner o no la capacidad.

Sin escribir el bucle

Para el caso más común, unir elementos con un separador, ni siquiera hace falta el StringBuilder:

IO.println(String.join(", ", tres.stream().map(Persona::nombre).toList()));
IO.println(tres.stream().map(Persona::nombre).collect(Collectors.joining(", ", "[", "]")));
var sj = new StringJoiner(" | ");
for (Persona p : tres) sj.add(p.nombre());
IO.println(sj);
salidaAna, Luis, Marta
[Ana, Luis, Marta]
Ana | Luis | Marta
Para…Se usa
Unir una lista de cadenas con un separadorString.join(", ", lista)
Unir mientras transformas, con prefijo y sufijoCollectors.joining(sep, prefijo, sufijo)
Ir añadiendo en un bucle con separadorStringJoiner
Construir un texto con formato libre en un bucleStringBuilder

¿Y el + fuera de los bucles?

No hay que tenerle miedo. Una expresión como "Hola, " + nombre + ". Tienes " + n + " mensajes" se resuelve en una sola operación: desde Java 9 el compilador la traduce a una llamada especializada que calcula el tamaño final y copia cada parte una vez. Cambiarla por un StringBuilder escrito a mano solo la hace más difícil de leer. El problema es acumular en un bucle, no el operador.

Entrada publicada en 2011 y revisada en octubre de 2026. Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio; las salidas están copiadas de esa ejecución.

Invocar al recolector de basura

Java y otros lenguajes tienen un mecanismo de liberación de memoria llamado Garbage Collector, el cual permite reutilizar la memoria durante la ejecución de un programa. Se puede llamar al recolector de basura utilizando System.gc() o Runtime.getRuntime.gc(). Aunque hacer esto no se considera buena práctica ya que tiene repercusiones importantes en el rendimiento de una aplicación. La mejor práctica es no tener que llamar a estos métodos haciendo un buen diseño y uso de los recursos.

La descripción en la documentación para estos métodos es la siguiente:


System.gc()

Hace correr al recolector de basura.

Al llamar al método gc se sugiere a la máquina virtual realice un esfuerzo de reciclaje de objetos no utilizados con el fin de hacer que la memoria que estos objetos ocupan esté disponible para su uso rápido. Cuando se devuelve el control de la llamada al método, la maquina virtual de java ha hecho su mejor esfuerzo para recuperar el espacio de los objetos desechados.

La llamada System.gc() es efectivamente equivalente a la llamada Runtime.getRuntime.gc()


Runtime.getRuntime.gc()


Hace correr al recolector de basura. Al llamar a este método se sugiere a la maquina virtual realice su mayor es fuerzo de reciclaje de objetos no utilizados con el fin de hacer que la memoria que estos objetos ocupan esté disponible para su uso rápido. Cuando se devuelve el control de la llamada a al método, la máquina virtual ha hecho su mejor esfuerzo para recuperar el espacio de los objetos desechados.

La maquina virtual lleva a cabo este proceso de reciclaje de forma automática cuando es necesario, en un hilo separado, incluso si el método gc no se invoca explícitamente.

El método System.gc() es el medio convencional y conveniente de la invocación de este proceso. En algunas ocasiones esta invocación no tendrá mayor efecto, ya que la liberación de recursos nunca está garantizada.

Java versión 7

Oracle ha lanzado la versión 7 de Java. Algunas de las mejoras las listamos a continuación.

Maquina Virtual

  • JSR 292: Soporte para lenguajes escritos dinámicamente (InvokeDynamic)
  • Revisión estricta de archivos clase

Lenguaje

  • JSR 334: Mejoras pequeñas al lenguaje (Project Coin)

Core

  • Actualización de la arquitectura de carga de clases
  • Método para cerrar un URLClassLoader
  • Actualizaciones a concurrencia y colecciones (jsr166y)

Internacionalización

  • Soporte a Unicode 6.0
  • Mejoras en la API Locale
  • Localización de usuario separada y localización interfaz de usuario

IO y Networking

  • JSR 203: Nuevas APIs IO para la plataforma Java (NIO.2)
  • Un proveedor de sistema de archivos NIO.2 para archivos zip/jar
  • SCTP (Protocolo de transmisión de control de flujos)
  • SDP (Protocolo directo de sockets )
  • Uso de la pila IPv6 de Windows Vista
  • Soporte para TLS 1.2

Seguridad y Criptografía

  • Implementación de criptografía elliptic-curve (ECC)

Conectividad y Bases de Datos

  • JDBC 4.1

Cliente

  • XRender para Java 2D
  • Permite crear nuevas plataformas para gráficas 6u10
  • Nuevo look-and-feel Nimbus
  • Componente JLayer para Swing
  • Sintetizador de sonido Gervill

Web

  • Actualización de la pila de XML

Administración

  • MBeans mejorados

Mejoras diferidas a la versión de JDK8 o superiores

  • JSR 294: Soporte a la máquina virtual y al lenguaje para programación modular
  • JSR308: Anotaciones sobre tipos de java
  • JSR TBD: Proyecto Lambda
  • Modularización (Proyecto Jigsaw)
  • JSR 296: Marco de trabajo para aplicaciones Swing
  • Componente Swing JDatePicker
Puedes ver mas detalle en el artículo original de openjdk.java.net en:

Commons IO: leer un archivo y listar directorios con FileUtils

FileUtils, de Apache Commons IO, resume en una línea tareas con archivos que con java.io llevaban diez. Este es el ejemplo de siempre, leer un archivo y listar los de ciertas extensiones, puesto al día. Y al lado, la versión con java.nio, que hoy hace casi lo mismo sin añadir nada.

La dependencia

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.22.0</version>
</dependency>

Es la última versión publicada en Maven Central. Si no usas Maven, basta con descargar el .jar y añadirlo al classpath.

El ejemplo

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;

public class Prueba {
    public static void main(String[] args) throws IOException {
        File archivo = new File("ejemplo.txt");
        String contenido = FileUtils.readFileToString(archivo, StandardCharsets.UTF_8);
        System.out.println("contenido: " + contenido.strip());

        String[] extensiones = {"xml", "java", "dat"};
        Collection<File> archivos = FileUtils.listFiles(new File("proy"), extensiones, true);
        for (File f : archivos) {
            System.out.println("> " + f.getPath());
        }
    }
}

Lo probamos con un ejemplo.txt de una línea y una carpeta proy con seis archivos, de los que solo tres tienen las extensiones que buscamos:

javac -cp commons-io-2.22.0.jar Prueba.java
java -cp .:commons-io-2.22.0.jar Prueba
salidacontenido: Hola desde decodigo.com
> proy/pom.xml
> proy/src/main/java/ejemplo/App.java
> proy/datos/clientes.dat

Encontró el .xml, el .java y el .dat, en cualquier nivel de subcarpetas, y dejó fuera el .txt, el .md y el .class. El orden es el que devuelve el sistema de archivos, que no tiene por qué ser alfabético.

Lo que cambió desde la versión de 2011

El código original llamaba a readFileToString(archivo) sin indicar la codificación. Ese método está obsoleto:

javac -Xlint:deprecationVieja.java:6: warning: [deprecation] readFileToString(File) in FileUtils has been deprecated
        System.out.println(FileUtils.readFileToString(new File("ejemplo.txt")).strip());
                                    ^
1 warning

Sin codificación, el archivo se lee con la del sistema, y el mismo programa puede leer bien los acentos en un equipo y mal en otro. Por eso hay que pasar siempre StandardCharsets.UTF_8 (o la que tenga el archivo). El otro cambio es de estilo: la lista ahora es una Collection<File> con tipo, y se recorre con un for normal, sin Iterator ni conversiones.

Lo mismo sin dependencias

import java.io.IOException;
import java.nio.file.*;
import java.util.Set;
import java.util.stream.Stream;

void main() throws IOException {
    String contenido = Files.readString(Path.of("ejemplo.txt"));
    IO.println("contenido: " + contenido.strip());

    Set<String> extensiones = Set.of("xml", "java", "dat");
    try (Stream<Path> rutas = Files.walk(Path.of("proy"))) {
        rutas.filter(Files::isRegularFile)
             .filter(p -> {
                 String n = p.getFileName().toString();
                 int punto = n.lastIndexOf('.');
                 return punto > 0 && extensiones.contains(n.substring(punto + 1));
             })
             .sorted()
             .forEach(p -> IO.println("> " + p));
    }
}
java SinDependencias.javacontenido: Hola desde decodigo.com
> proy/datos/clientes.dat
> proy/pom.xml
> proy/src/main/java/ejemplo/App.java

Files.readString lee en UTF-8 por omisión, y Files.walk recorre el árbol. Filtrar por extensión lleva unas líneas más que con FileUtils, pero no hace falta ningún .jar. Aquí además las ordenamos con sorted(). El try con recursos es necesario, porque Files.walk deja abiertos los directorios hasta que se cierra el stream.

Para…Commons IOjava.nio (JDK)
Leer un archivo enteroFileUtils.readFileToString(f, UTF_8)Files.readString(ruta)
Escribir un archivoFileUtils.writeStringToFile(f, texto, UTF_8)Files.writeString(ruta, texto)
Listar por extensión, recursivoFileUtils.listFiles(dir, exts, true)Files.walk + filtro
Copiar un directorio enteroFileUtils.copyDirectory(a, b)a mano, con Files.walk
Borrar un directorio con contenidoFileUtils.deleteDirectory(dir)a mano, con Files.walk al revés

Para leer y escribir, java.nio basta. Commons IO sigue ahorrando trabajo en las operaciones con directorios enteros, como copiarlos o borrarlos. Las vemos, con sus salidas, en FileUtils de Commons IO.

Entrada publicada en 2011 y revisada en octubre de 2026. Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio con Commons IO 2.22.0; las salidas están copiadas de esa ejecución.