{"id":263,"date":"2025-10-05T16:24:35","date_gmt":"2025-10-05T14:24:35","guid":{"rendered":"https:\/\/carlosarranz.es\/?p=263"},"modified":"2025-10-05T16:24:36","modified_gmt":"2025-10-05T14:24:36","slug":"cookbook-de-trampas-comunes-en-java","status":"publish","type":"post","link":"https:\/\/carlosarranz.es\/en\/cookbook-de-trampas-comunes-en-java\/","title":{"rendered":"Common Java Pitfalls Cookbook"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Cookbook de trampas comunes en Java<\/h2>\n\n\n\n<p>Este documento recopila errores comunes y comportamientos sutiles en Java que pueden generar bugs dif\u00edciles de detectar. Cada entrada sigue el esquema <strong>problema \u2192 soluci\u00f3n \u2192 discusi\u00f3n<\/strong> para que puedas identificar, entender y evitar estos fallos en tu c\u00f3digo.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">1. Comparaci\u00f3n de Integer fuera del rango cacheado<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> El operador <code class=\"\" data-line=\"\">==<\/code> devuelve <code class=\"\" data-line=\"\">false<\/code> para enteros mayores a 127 (o menores a -128) aunque los valores num\u00e9ricos sean iguales.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa <code class=\"\" data-line=\"\">.equals()<\/code> para comparar valores de <code class=\"\" data-line=\"\">Integer<\/code>. Para rendimiento o simplicidad, usa <code class=\"\" data-line=\"\">int<\/code> si no necesitas nulos.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> Java cachea los <code class=\"\" data-line=\"\">Integer<\/code> en el rango [-128, 127]. Fuera de ese rango, <code class=\"\" data-line=\"\">Integer.valueOf()<\/code> devuelve instancias distintas; <code class=\"\" data-line=\"\">==<\/code> compara referencias, no contenido.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">2. Comparaci\u00f3n de String con ==<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> <code class=\"\" data-line=\"\">==<\/code> entre cadenas a veces da <code class=\"\" data-line=\"\">true<\/code> y otras <code class=\"\" data-line=\"\">false<\/code> para el mismo texto, lo que confunde a principiantes.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Compara cadenas con <code class=\"\" data-line=\"\">.equals()<\/code> o <code class=\"\" data-line=\"\">.equalsIgnoreCase()<\/code>.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> El <em>string pool<\/em> puede hacer que dos literales apunten a la misma referencia, pero objetos creados con <code class=\"\" data-line=\"\">new String()<\/code> no. <code class=\"\" data-line=\"\">==<\/code> compara referencias; <code class=\"\" data-line=\"\">.equals()<\/code> compara contenido.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">3. Modificar una colecci\u00f3n durante la iteraci\u00f3n<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Eliminar o a\u00f1adir elementos a una colecci\u00f3n mientras se recorre con <code class=\"\" data-line=\"\">for-each<\/code> lanza <code class=\"\" data-line=\"\">ConcurrentModificationException<\/code>.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa un <code class=\"\" data-line=\"\">Iterator<\/code> y su <code class=\"\" data-line=\"\">remove()<\/code>, o recopila primero y modifica despu\u00e9s; alternativamente, usa colecciones concurrentes.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> Muchas colecciones detectan cambios estructurales durante la iteraci\u00f3n. Las colecciones concurrentes (p. ej., <code class=\"\" data-line=\"\">CopyOnWriteArrayList<\/code>) tienen sem\u00e1nticas diferentes y coste adicional.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">4. NullPointerException al hacer unboxing<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Convertir un <code class=\"\" data-line=\"\">Integer<\/code> <code class=\"\" data-line=\"\">null<\/code> a <code class=\"\" data-line=\"\">int<\/code> produce <code class=\"\" data-line=\"\">NullPointerException<\/code>.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Valida <code class=\"\" data-line=\"\">null<\/code> antes del unboxing o usa <code class=\"\" data-line=\"\">OptionalInt<\/code> \/ valores por defecto.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> El unboxing invoca internamente <code class=\"\" data-line=\"\">intValue()<\/code> sobre la referencia; si es <code class=\"\" data-line=\"\">null<\/code>, falla. Ev\u00edtalo donde sea posible usando tipos primitivos.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">5. Arrays no hacen copia profunda<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Asignar un array a otra variable copia la referencia; cambios en una vista afectan a la otra.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa <code class=\"\" data-line=\"\">Arrays.copyOf()<\/code> o <code class=\"\" data-line=\"\">clone()<\/code> para copiar el array; para matrices\/objetos, implementa una copia profunda expl\u00edcita.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> La copia por referencia es r\u00e1pida pero sorprende a quienes esperan independencia de datos. Para estructuras anidadas, copia cada nivel.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">6. Falta de break en switch (fall-through)<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Olvidar <code class=\"\" data-line=\"\">break<\/code> ejecuta casos adicionales inesperadamente.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> A\u00f1ade <code class=\"\" data-line=\"\">break<\/code> o usa <code class=\"\" data-line=\"\">switch<\/code> con expresiones (Java 14+) y <code class=\"\" data-line=\"\">-&gt;<\/code>, que no hace <em>fall-through<\/em> por defecto.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> El <em>fall-through<\/em> es \u00fatil en casos agrupados, pero suele ser fuente de bugs. Las expresiones <code class=\"\" data-line=\"\">switch<\/code> modernas reducen este riesgo.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">7. Llamadas virtuales en constructores (inicializaci\u00f3n incompleta)<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Llamar a m\u00e9todos sobreescritos desde un constructor puede usar campos a\u00fan no inicializados de la subclase.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> No invoques m\u00e9todos sobreescritos en constructores; usa m\u00e9todos <code class=\"\" data-line=\"\">final<\/code> o inicializaci\u00f3n expl\u00edcita.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> El constructor de la superclase se ejecuta antes de inicializar los campos de la subclase. La llamada virtual accede a estado incompleto.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">8. Arrays de tipos gen\u00e9ricos<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> No se pueden crear arrays de tipos gen\u00e9ricos concretos, p. ej., <code class=\"\" data-line=\"\">new ArrayList&lt;String&gt;[10]<\/code>.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa <code class=\"\" data-line=\"\">List&lt;?&gt;[]<\/code> o preferentemente colecciones, evitando arrays de gen\u00e9ricos.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> Los arrays son covariantes y reificados; los gen\u00e9ricos usan borrado de tipos. La mezcla rompe seguridad de tipos en tiempo de ejecuci\u00f3n.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">9. Claves mutables en HashMap\/HashSet<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Modificar una clave despu\u00e9s de insertarla impide encontrarla de nuevo.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa claves inmutables (por ejemplo, <code class=\"\" data-line=\"\">record<\/code> o clases inmutables) o no modifiques las claves tras usarlas.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> <code class=\"\" data-line=\"\">hashCode()<\/code> y <code class=\"\" data-line=\"\">equals()<\/code> determinan la ubicaci\u00f3n. Si cambian, el mapa pierde la referencia a la entrada.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">10. Optional.get() sin verificar presencia<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Llamar a <code class=\"\" data-line=\"\">get()<\/code> sobre un <code class=\"\" data-line=\"\">Optional<\/code> vac\u00edo lanza <code class=\"\" data-line=\"\">NoSuchElementException<\/code>.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa <code class=\"\" data-line=\"\">orElse()<\/code>, <code class=\"\" data-line=\"\">orElseGet()<\/code>, <code class=\"\" data-line=\"\">orElseThrow()<\/code> o <code class=\"\" data-line=\"\">ifPresent()<\/code>.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> <code class=\"\" data-line=\"\">Optional<\/code> pretende evitar <code class=\"\" data-line=\"\">null<\/code>; usar <code class=\"\" data-line=\"\">get()<\/code> rompe su intenci\u00f3n. Prefiere API expresivas.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">11. Shadowing de variables (ocultamiento de campos)<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> El par\u00e1metro del m\u00e9todo oculta el campo de instancia y asignaciones como <code class=\"\" data-line=\"\">nombre = nombre;<\/code> no hacen nada \u00fatil.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa <code class=\"\" data-line=\"\">this.nombre = nombre;<\/code> o cambia el nombre del par\u00e1metro.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> El sombreado dificulta el mantenimiento y causa bugs silenciosos. Activar inspecciones del IDE ayuda a detectarlo.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">12. Concurrencia: falta de <code class=\"\" data-line=\"\">volatile<\/code> (visibilidad)<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Un hilo no observa cambios de otro hilo sobre una variable sin sincronizaci\u00f3n.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Declara la variable como <code class=\"\" data-line=\"\">volatile<\/code> o sincroniza accesos (<code class=\"\" data-line=\"\">synchronized<\/code>, <code class=\"\" data-line=\"\">Lock<\/code>).<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> El modelo de memoria de Java permite reordenamientos y cach\u00e9s por hilo. <code class=\"\" data-line=\"\">volatile<\/code> garantiza visibilidad y orden de publicaci\u00f3n\/lectura.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">13. Concurrencia: incrementos no at\u00f3micos<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> Operaciones como <code class=\"\" data-line=\"\">valor++<\/code> pierden actualizaciones bajo concurrencia.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa <code class=\"\" data-line=\"\">AtomicInteger.incrementAndGet()<\/code>, bloques <code class=\"\" data-line=\"\">synchronized<\/code> o acumuladores (<code class=\"\" data-line=\"\">LongAdder<\/code>).<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> <code class=\"\" data-line=\"\">valor++<\/code> implica leer-modificar-escribir. Sin exclusi\u00f3n mutua, dos hilos pueden sobrescribir resultados.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">14. Calendar: mes base cero<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> <code class=\"\" data-line=\"\">Calendar#set(a\u00f1o, mes, d\u00eda)<\/code> interpreta enero como 0; <code class=\"\" data-line=\"\">10<\/code> es noviembre, no octubre.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Usa constantes (<code class=\"\" data-line=\"\">Calendar.OCTOBER<\/code>) o migra a <code class=\"\" data-line=\"\">java.time<\/code>.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> La API antigua de fechas es propensa a errores. <code class=\"\" data-line=\"\">java.time<\/code> (JSR-310) es m\u00e1s clara e inmutable.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">15. LocalDate.parse() con formatos no ISO<\/h3>\n\n\n\n<p><strong>Problema:<\/strong> <code class=\"\" data-line=\"\">LocalDate.parse(&quot;05\/10\/2025&quot;)<\/code> lanza <code class=\"\" data-line=\"\">DateTimeParseException<\/code>.<\/p>\n\n\n\n<p><strong>Soluci\u00f3n:<\/strong> Define un formateador: <code class=\"\" data-line=\"\">DateTimeFormatter.ofPattern(&quot;dd\/MM\/yyyy&quot;)<\/code> y p\u00e1salo a <code class=\"\" data-line=\"\">parse()<\/code>.<\/p>\n\n\n\n<p><strong>Discusi\u00f3n:<\/strong> Por defecto, <code class=\"\" data-line=\"\">parse()<\/code> espera <code class=\"\" data-line=\"\">yyyy-MM-dd<\/code>. Para otros formatos debes indicar el patr\u00f3n expl\u00edcitamente.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This document compiles common errors and subtle behaviors in Java that can lead to difficult-to-detect bugs. <\/p>","protected":false},"author":1,"featured_media":264,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[5,4],"tags":[],"class_list":["post-263","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-buenas-practicas","category-desarrollo"],"_links":{"self":[{"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/posts\/263","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/comments?post=263"}],"version-history":[{"count":1,"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/posts\/263\/revisions"}],"predecessor-version":[{"id":265,"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/posts\/263\/revisions\/265"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/media\/264"}],"wp:attachment":[{"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/media?parent=263"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/categories?post=263"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/carlosarranz.es\/en\/wp-json\/wp\/v2\/tags?post=263"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}