Apex Academy
Módulo 8·01·30 min

try, catch y finally

Hasta ahora, cuando algo fallaba, la transacción entera se paraba. Con try, catch y finally decides tú qué pasa: qué se intenta, qué se hace si falla y qué se hace siempre.

En Admin esEl fault path de un elemento de Flow

✓ En esta sub-lección

  1. 01Explicar qué pasa cuando una excepción no se captura y por qué se deshace la transacción.
  2. 02Rodear con try solo la parte que puede fallar y capturar un tipo concreto de excepción.
  3. 03Usar finally para lo que tiene que ocurrir siempre, haya fallo o no.

La nutria: ¿Te acuerdas? · Repaso del Módulo 7

¿Qué hace un return; como primera línea del trigger cuando el usuario tiene el permiso de bypass?

Hasta ahora, cuando algo fallaba en tu código (un null, un límite, un registro que no se podía guardar), Apex lanzaba una excepción, la transacción entera se paraba y todo lo hecho se deshacía. Es un buen comportamiento por defecto, pero no siempre es el que quiere el negocio. En este módulo aprendes a decidir tú qué pasa cuando algo falla.

El encargo de este módulo

Cada noche, el ERP de Northwind deja en un objeto intermedio, ERP_Renewal__c, las renovaciones que se firmaron ese día: el código de la cuenta en el ERP y el importe. Hay que convertirlas en oportunidades de renovación en Salesforce antes de que llegue el equipo de Ventas. El problema es que los datos del ERP no son perfectos: importes mal escritos, códigos de cuenta que no existen, propietarios que ya no están en la empresa. Los seis talleres construyen ese puente, pieza a pieza, hasta que ninguna fila mala pueda tumbar a las buenas.

La nutria: ¿Y por qué no un Flow? Porque ya lo intentamos

Te lo cuento porque lo viví: primero lo montamos con clics. Un Scheduled Flow que cada noche hacía un Get Records de ERP_Renewal__c, recorría la colección con un Loop y, dentro del Loop, un Create Records por fila con un fault path que guardaba un registro de log. La primera noche llegaron 320 filas: un DML por vuelta, y en la 151 saltó «Too many DML statements: 151». La transacción entera se deshizo, también las 150 renovaciones ya creadas, y ese límite no se puede capturar: no hay fault path que lo salve. Sacamos el Create Records del Loop y chocamos con lo siguiente: una fila con una cuenta equivocada hacía fallar el elemento entero. Activamos la opción de éxito parcial que Create Records tiene desde Winter '25 y guardó las buenas, sí, pero sin decirnos cuáles habían fallado ni por qué, y el ERP necesita esa respuesta fila a fila. Ahí decidimos que era trabajo para Apex.

La nutria: Las seis piezas del puente con el ERP

1 · Que un importe mal escrito no tumbe la importación. 2 · Reconocer qué ha fallado: no es lo mismo una cuenta que no existe que un guardado rechazado. 3 · Sacar la validación de cada fila a un método que avise cuando algo no cuadra. 4 · Errores con nombre propio, los del negocio de Northwind. 5 · Que Salesforce rechace una segunda renovación abierta para la misma cuenta, fila a fila. 6 · La entrega: la importación nocturna completa, con su informe para el ERP.

Qué es una excepción, y qué pasa si nadie la atrapa

Una es la forma que tiene Apex de decir «no puedo seguir»: convertir 'doce' en un número, leer un campo de un null, guardar un registro que una regla de validación rechaza. En el momento en que ocurre, Apex deja de ejecutar la línea siguiente y busca, hacia arriba, alguien que se haga cargo. Si nadie lo hace, la excepción llega hasta la plataforma: la transacción se detiene, todos sus cambios se deshacen y el usuario (o el correo del Admin) recibe el mensaje de error.

try, catch y finally

Con tres palabras decides tú. En try va lo que puede fallar. En catch, lo que haces si falla, y solo se ejecuta cuando salta una excepción del tipo que indicas entre paréntesis. En finally, lo que tiene que ocurrir siempre, haya fallado o no. Cuando un catch se hace cargo, el error se considera tratado: la transacción no se deshace y el código sigue en la línea siguiente a todo el bloque.

Apex
try {
    Decimal amount = Decimal.valueOf('12.500,00');   // ← falla: no es un número para Apex
    System.debug('Importe: ' + amount);              // no llega a ejecutarse
} catch (TypeException e) {
    System.debug('Importe no válido: ' + e.getMessage());
} finally {
    System.debug('Fila procesada');                  // se ejecuta siempre
}
System.debug('Y el código sigue');
La e del catch es la propia excepción: getMessage() te da el motivo. Apex espera el punto como separador decimal, así que '12.500,00' no es un número válido.

La nutria: El fault path de tus flows

Tú ya has hecho esto con clics, como yo: en un elemento de Flow que puede fallar (un Create Records, un Update Records) arrastras el conector de fallo (fault path) hacia otro camino, por ejemplo uno que manda un aviso. El elemento es tu try y el fault path es tu catch. Lo que Flow no tiene es finally: un tramo que se ejecute tanto si el elemento fue bien como si falló, sin tener que dibujarlo dos veces.
for (String raw : rawAmounts) {
    total += Decimal.valueOf(raw);
}
  • '12500.00'
  • '8300.50'
  • '12.500,00'
  • ''
  • '4100'

importadas

0

failed

0

processed

—

Paso 1 de 6

Cinco importes del ERP; dos vienen mal escritos. Pulsa Reproducir.

Procesa las filas del ERP con y sin try/catch, y mira qué camino toma cada una.

Dónde poner el try

La pregunta clave es qué quieres que siga funcionando cuando algo falla. Si el try rodea todo el bucle, el primer importe malo te saca del bucle entero: las filas siguientes ni se intentan. Si el try va dentro del bucle, alrededor de cada fila, una fila mala se captura y el bucle sigue con la siguiente. Para una importación fila a fila, casi siempre quieres lo segundo.