Skip to content

Dominando las colecciones de Apex ☁️

Esta es una traducción que desde EGA Futura ofrecemos como cortesía a toda la Ohana y comunidad de programadores , consultores , administradores y arquitectos de Salesforce para toda Iberoamérica .

El enlace a la publicación original, lo encontrarás al final de este artículo.

Este tema fue presentado originalmente por Philippe Ozil durante una sesión de Apex Hours el 4 de septiembre de 2021.

Trabajar con colecciones como List, Map y Set es parte de una rutina diaria para los desarrolladores de Apex. Si bien su uso básico es sencillo, existen algunas peculiaridades avanzadas que pueden llevarlo al siguiente nivel. En esta publicación, comenzaremos con los conceptos básicos sobre objetos y colecciones, luego profundizaremos en conceptos avanzados, como iteradores y clasificación.

Explorando objetos y colecciones

Acerca de los objetos y sus métodos

En Apex, todas las clases y primitivas heredan de la clase Object. Esta herencia está implícita en el sentido de que no es necesario especificarla al crear una clase personalizada, por ejemplo.

Gracias a la herencia de Object, todas las instancias de objetos pueden usar los equals , hashCode y toString como se demuestra aquí:

 Booleano myBoolean = falso;
Objeto myObject = (Objeto) myBoolean; // Boolean es un hijo de Object
System.debug (myObject.equals (true)); // falso
System.debug (myObject.hashCode ()); // 1237
System.debug (myObject.toString ()); // falso

equals permiten comparar una instancia de objeto en cuanto a igualdad con otra. Lo interesante de este método es que le permite comparar objetos de diferentes tipos. Por ejemplo, puede comparar una identificación con una cadena:

 Id accountId = '0010o00002svksw'; // ID de 15 caracteres
String accountIdString = '0010o00002svkswAAA'; // Misma ID en formato de 18 caracteres
accountId.equals (accountIdString); // cierto

Si bien equals es poderoso, tiene un costo de rendimiento cuando se ejecuta en objetos con una gran cantidad de propiedades. Aquí es donde entra en juego el método hashCode hashCode devuelve un número entero que identifica una instancia de objeto en función de algunos de sus valores de propiedad. Por ejemplo, el entero 123 tiene un código hash de 123 y una cadena "Hello World" tiene un código hash de -862545276.

Los valores del código hash son pseudo-únicos ya que algunas instancias de objetos con diferentes valores de propiedad pueden compartir el mismo código hash. Esto se denomina colisión de código hash y se considera aceptable. Cuando ocurre una colisión, equals se usa como alternativa para comparar objetos. En cualquier caso, comparar los códigos hash de dos objetos es estadísticamente más rápido que llamar a los equals .

Los equals y hashCode son esenciales cuando se trabaja con colecciones, y veremos por qué a medida que exploramos los diferentes tipos de colecciones.

Una descripción general de los tipos de colecciones

Las instancias de objetos se pueden almacenar en tres tipos de colecciones: Lista, Conjunto y Mapa. Estos tipos de colección tienen diferentes propósitos y propiedades:

  • Una lista contiene una colección ordenada de elementos no únicos
  • Un conjunto contiene una colección desordenada de elementos únicos
  • Un mapa contiene un diccionario de valores clave en el que las claves son únicas pero los valores no

Dato curioso: Set y Map tienen nombres de conceptos matemáticos (consulte Definiciones de Set y Map ).

List y Set tienen cierto grado de interoperabilidad ya que comparten algunos constructores y métodos que funcionan con ambos tipos. Por ejemplo, puede crear una lista a partir de un conjunto y viceversa, y puede llamar a métodos como addAll con ambos tipos. Esto permite casos de uso poderosos, como eliminar elementos duplicados de una lista al convertirlos en un conjunto:

 // Al convertir una lista en un conjunto se eliminan los elementos duplicados
// a expensas del orden de la lista
Lista <Intero> duplicados = nueva Lista <Intero> { 5 , 1 , 3 , 1 , 5 , 3 };
List <Integer> uniqueItems = new List <Integer> (new Set <Integer> (duplicados));
System.debug (artículos únicos); // (5, 1, 3)

La unicidad de los valores establecidos y las claves del mapa se aplica gracias al hashCode y una alternativa a los equals en caso de colisión del código hash. Estos dos métodos también son esenciales para algunas operaciones Set y Map, como Set.contains o Map.containsKey . Curiosamente, las operaciones de lista como List.contains basan únicamente en equals y nunca en hashCode .

Ahora que hemos visto el panorama general de los objetos y los tipos de colección, profundicemos en los detalles de la colección. Comenzaremos iterando en Listas y Conjuntos.

Iterando en listas y conjuntos

List y Set se pueden atravesar con for , pero hay una alternativa poderosa: los iteradores . List y Set implementan la Iterable , y esta interfaz proporciona acceso a un iterator que expone un objeto que implementa la interfaz Iterator

Gracias a los hasNext y next del Iterator, puede atravesar una colección en una sola dirección:

 List <Cuenta> myList = new List <Cuenta> {/ * algunas cuentas * /};
Iterador <Cuenta> it = myList.iterator ();
while (it.hasNext ()) { Cuenta acc = it.next (); // Hacer algo
}

Si bien el código anterior es más detallado que los for , el uso de iteradores tiene tres ventajas clave:

  • Los iteradores proporcionan acceso de solo lectura a las colecciones. Si pasa un iterador como parámetro de método, está seguro de que este método no puede modificar su colección.
  • Los iteradores bloquean la colección en modo de solo lectura, evitando cualquier modificación a la colección mientras la estás iterando:
 Set <Integer> mySet = new Set <Integer> {1, 2, 3};
Iterador <Intero> it = mySet.iterator (); it.next ();
it.next (); mySet.add (4); // Falla con System.FinalException porque el iterador está en uso it.next ();
  • Los iteradores proporcionan un mecanismo que le permite recuperar elementos dinámicamente sobre la marcha. Nuestro enfoque principal en este artículo son las colecciones, pero puede implementar sus propias clases iterables. Esto es extremadamente útil cuando se trabaja con datos paginados y cuando recupera elementos en lotes. Por ejemplo, podría crear un cliente REST que itera en un recurso y podría comenzar a iterar sin saber el número exacto de elementos que están disponibles.

Consulte las recetas de iteración en Apex Recipes para ver ejemplos de iteradores junto con su clase de prueba relacionada.

Listas de clasificación

La primera opción cuando se trata de ordenar registros es generalmente escribir una consulta SOQL con una cláusula ORDER BY . Sin embargo, a veces es necesario ordenar los registros sin obtenerlos de la base de datos o incluso ordenar los objetos que no son registros. En esos casos, puede usar el método List.sort como este:

 List <String> colores = new List <String> {'Amarillo', 'Rojo', 'Verde'};
colors.sort (); // Ordena la lista de cadenas alfabéticamente
System.debug (colores); // (verde, rojo, amarillo)

El List.sort es fácil de usar, pero echemos un vistazo más de cerca a cómo funciona y cómo puede personalizar el orden.

Trabajar con la interfaz comparable

List.sort trabaja con elementos List que implementan la interfaz Comparable . La interfaz especifica un método único: compareTo que es llamado por el algoritmo de ordenación de listas para ordenar elementos.

compareTo devuelve un número entero con los siguientes valores:

  • 0 si this instancia y objectToCompareTo son iguales
  • > 0 si this instancia es mayor que objectToCompareTo
  • <0 si this instancia es menor que objectToCompareTo

List.sort puede ordenar cualquier combinación de objetos de varios tipos siempre que sean primitivos o implementen Comparable . Por ejemplo, podrías escribir perfectamente algo como esto:

 Lista <Objeto> myList = nueva Lista <Objeto> { 4, 3.14, verdadero, nulo, 'Mundo', 'Hola', 1L, falso, Fecha.today ()
};
myList.sort (); // nulo, falso, 4, 3.14, verdadero, 1, 2021-09-03 00:00:00, Hola, mundo

Como advertencia, es seguro colocar objetos que no implementan Comparable en una Lista, pero si llama al sort en esa Lista, obtendrá una excepción System.ListException

La documentación del método de sort proporciona una implementación de ejemplo para clasificar una clase personalizada, por lo que no profundizaremos en los detalles de este tema. Pero, ¿qué pasa con la clasificación de SObject (lista de registros)?

Ordenar listas de sObjects

SObject implementa la Comparable y las instancias de esa clase tienen un orden de clasificación predecible. Sin embargo, es posible que deba implementar un orden de clasificación personalizado en algunos casos, y aquí es donde las cosas se vuelven más complejas. La clase SObject es final, por lo que no puede sobrescribir sus métodos internos, como compareTo .

Para compensar eso, debe trabajar con una clase contenedora alrededor del SObject que desea ordenar. Imagine que está importando algunas cuentas de una integración de terceros y que desea ordenarlas según el campo del país de envío antes de guardarlas. No puede ordenar los registros con SOQL porque aún no están en la base de datos. Debes implementar la siguiente clase:

 La clase pública SortableAccount implementa Comparable { cuenta de cuenta final privada; public SortableAccount (cuenta de cuenta) { this.account = cuenta; } public Integer compareTo (Object otherObject) { // Para mayor seguridad de tipos, verifique si otherObject es una SortableAccount // si no, lanza una SortException if (! (otherObject instanceof SortableAccount)) { lanzar una nueva SortException ('No se puede ordenar con un tipo incompatible'); } // Lanza otherObject a SortableAccount y compáralo SortableAccount otro = (SortableAccount) otroObjeto; if (this.account.ShippingCountry <other.account.ShippingCountry) { return -1; } if (this.account.ShippingCountry> other.account.ShippingCountry) { return 1; } return 0; } La clase pública SortException extiende la excepción {}
}

Puede ordenar su Lista con su lógica de pedido personalizada en tres pasos:

  1. Convierta la List<Account> en una List<SortableAccount>
  2. Llame al método de sort List<SortableAccount>
  3. Convierta la List<SortableAccount> lista de nuevo a la List<Account>

Sin embargo, implementar estos pasos no es práctico, ya que se necesitarían casi tantas líneas de código como la implementación de SortableAccount y esas líneas adicionales no serían reutilizables. Afortunadamente, hay algo que puede hacer para reducir el código repetitivo. Simplemente agregue el siguiente método estático a SortableAccount :

 clasificación vacía estática pública (Lista <Cuenta> cuentas) { // Convertir Lista <Cuenta> en Lista <Cuenta Clasificable> List <SortableAccount> sortableAccounts = new List <SortableAccount> (); para (Cuenta acc: cuentas) { sortableAccounts.add (nueva SortableAccount (acc)); } // Ordenar cuentas usando SortableAccount.compareTo sortableAccounts.sort (); // Sobrescribe la lista de cuentas proporcionada en el parámetro de entrada // con la lista ordenada. Hacer esto evita una declaración de devolución // y es menos detallado para el usuario del método. para (Entero i = 0; i <cuentas.tamaño (); i ++) { cuentas [i] = sortableAccounts [i] .account; }
}

Con este SortableAccount.sort , todo lo que se necesita para ordenar una lista de registros de cuenta por país de envío es una sola línea:

 SortableAccount.sort (cuentas);

Consulte Listar recetas en Apex Recipes para la implementación de SortableAccount junto con la clase de prueba relacionada.

Clasificación de listas con comparadores reutilizables

Si bien el List.sort predeterminado es conveniente, tiene dos limitaciones importantes:

  • La lógica de ordenación está directamente relacionada con el Comparable que se está ordenando.
  • El método de clasificación carece de la capacidad de clasificar con diferentes estrategias y parámetros.

El lenguaje Java (que está cerca de Apex) va más allá del método básico de clasificación de Apex y expone un método conveniente Arrays.sort(T[], Comparator) donde T es el tipo que se está ordenando y Comparator una interfaz que especifica un método de compare como Comparable.compareTo .

Este patrón se puede replicar fácilmente en Apex con una ListUtils personalizada y una interfaz Comparator

Con este enfoque, puede ordenar listas con diferentes comparadores e incluso pasar parámetros a comparadores. Se beneficia del hecho de que la lógica de ordenación está desacoplada de los objetos que clasifica.

 // Ordenar las cuentas alfabéticamente según el país de envío
ListUtils.sort (cuentas, nuevo SObjectStringFieldComparator ('ShippingCountry')); // Ordene las cuentas alfabéticamente según la industria
ListUtils.sort (cuentas, nuevo SObjectStringFieldComparator ('Industria')); // Ordene las cuentas según los valores de calificación
// como se define en el orden de la lista de selección de clasificación (clasificación no alfabética)
ListUtils.sort (cuentas, nuevo AccountRatingComparator ());

Consulte ListUtils en Apex Recipes para la implementación de ListUtils, algunos comparadores y clases de prueba relacionadas.

Palabras de cierre

Eso es un envoltorio. Le dimos un repaso sobre la clase Object y los diferentes tipos de colección. Cubrimos conceptos de colección avanzados: ha aprendido a usar iteradores y a ordenar Listas con el método de ordenación predeterminado y comparadores personalizados. Esperamos que este artículo le haya ayudado a comprender mejor las colecciones. Ahora te toca a ti poner en práctica estos conocimientos en tus proyectos.

Recursos

Sobre el Autor

Philippe Ozil es un promotor principal de desarrolladores en Salesforce, donde se centra en la plataforma Salesforce. Escribe contenido técnico y habla con frecuencia en conferencias. Es un desarrollador de pila completa y disfruta trabajar en proyectos de DevOps, robótica y realidad virtual. Síguelo en Twitter @PhilippeOzil o revisa sus proyectos de GitHub @pozil .

Esta es una traducción realizada por EGA Futura, y este es el link a la publicación original: https://developer.salesforce.com/blogs/2021/10/mastering-apex-collections.html

Últimas novedades 
de EGA Futura
1954
Desde hace más de 25 años potenciamos a las Empresas de Iberoamérica
🎬 Video de EGA Futura » Conceptos de Seguridad (EGA Futura ERP / Salesforce)

🎬 Video de EGA Futura » Conceptos de Seguridad (EGA Futura ERP / Salesforce)

🎬 Video de Juan Manuel Garrido » Claves para tu Productividad diaria 🙌✅

🎬 Video de EGA Futura » Facturación Electrónica en Uruguay » Conceptos básicos con EGA Futura Windows

🎬 Video de EGA Futura » Facturación Electrónica en Uruguay » Configuración de EGA Futura Windows

🎬 Video de EGA Futura » Facturación Electrónica en Uruguay » Funcionamiento con EGA Futura Windows

🎬 Video de EGA Futura » Configuración de la Plataforma EGA Futura

🎬 Video de EGA Futura » Configuración de usuario en EGA Futura

🎬 Video de EGA Futura » Como automatizar la publicación en Redes Sociales?

🎬 Video de Juan Manuel Garrido » Cómo restaurar la configuración de fábrica de EGA Futura Windows sin perder la información

🎬 Video de Juan Manuel Garrido » Factura electrónica: Prueba de Factura Electronica previa a la activacion

🎬 Video de EGA Futura » Como se registran los Beneficios de cada Empleado en la base de datos de EGA Futura

🎬 Video de EGA Futura » EGA Futura Time Clock » Reloj de Control horario y asistencia

🎬 Video de EGA Futura » Como registrar Observaciones en un Empleado dentro de EGA Futura People?

🎬 Video de EGA Futura » Cómo registrar la Educación de cada Empleado en EGA Futura People?

🎬 Video de EGA Futura » Como hacer la Desvinculación de un Empleado? (Offboarding)

🎬 Video de EGA Futura » Como registrar Habilidades o Skills de empleados dentro de EGA Futura

🎬 Video de EGA Futura » Como hacer el Onboarding o Proceso de Incorporación de un Empleado?

🎬 Video de EGA Futura » Cómo administrar Turno de trabajo dentro de EGA Futura

🎬 Video de EGA Futura » Que es un Ticket interno dentro de la Plataforma EGA Futura

🎬 Video de EGA Futura » Que son los Entrenamientos de Empleado en EGA Futura people?

🎬 Video de EGA Futura » Qué son los Epics dentro de EGA Futura

🎬 Video de EGA Futura » Qué es EGA Futura People?

🎬 Video de EGA Futura » EGA Futura People » Asistencias

🎬 Video de EGA Futura » Soporte EGA Futura » Software de Gestión Windows vs Software de Gestión Nube 🤩

🎬 Video de EGA Futura » ツ Comparando un Objeto con un Fichero

Dominando las colecciones de Apex ☁️
Dominando las colecciones de Apex ☁️