DEV Community

Cover image for A arte das coleções em .NET - List
Thaise Medeiros for Unhacked

Posted on

A arte das coleções em .NET - List

Com certeza você já precisou lidar com dados e optou por usar List, seja por toda a praticidade que esta classe proporciona ou por ser uma das mais difundidas. Uma das perguntas que eu mais gosto de me fazer quando estou programando é: por que vou usar isto aqui? Essa é uma das perguntas que vamos responder agora no segundo artigo da série sobre coleções.

Definindo a List

Como vimos no artigo anterior, a recomendação é usar coleções genéricas, então encontramos a classe List<T> no namespace System.Collections.Generic. A List<T> representa uma lista fortemente tipada de objetos que podem ser acessados por índice e possui métodos para pesquisar, classificar e manipular as listas. Por baixo dos panos, a List<T> é um array unidimensional que começa em índice zero.

Utilizando a List<T>

Para inicializar uma lista do tipo Aluno, escrevemos assim:

List<Aluno> alunos = new List<Aluno>();
Enter fullscreen mode Exit fullscreen mode

Ao utilizarmos o construtor sem parâmetros, iremos criar uma lista com a capacidade padrão, que é 4. Após a inicialização, podemos adicionar itens à lista usando o método Add() passando o objeto aluno como parâmetro, assim:

alunos.Add(new Aluno { Id = 1, Nome = "Thaise" });
Enter fullscreen mode Exit fullscreen mode

Agora aqui é a dica de ouro para otimizar seu código usando List<T> com uma grande quantidade de itens! Se não definirmos a capacidade, o .NET vai criar uma com capacidade para até 4 itens, que é o padrão. Toda vez que um item é adicionado, é verificado se a capacidade da lista comporta mais um item. Caso a capacidade seja menor que a quantidade de itens mais 1, que estamos tentando adicionar, será criada uma nova lista com a capacidade duplicada e os itens da lista atual serão copiados para a nova.

Por exemplo: no nosso código acima, criamos uma lista de alunos usando o construtor sem parâmetros e adicionamos um aluno nela. Neste momento, temos uma lista de alunos com capacidade para até 4 itens e um item adicionado. Agora vamos inserir mais 3 itens:

alunos.Add(new Aluno { Id = 2, Nome = "Ana" });
alunos.Add(new Aluno { Id = 3, Nome = "Cristiano" });
alunos.Add(new Aluno { Id = 4, Nome = "Maggie" });
Enter fullscreen mode Exit fullscreen mode

Neste momento ainda temos uma lista com capacidade para até 4 itens e agora com 4 itens. Isso significa que estamos utilizando a capacidade máxima. Quando adicionarmos mais um item, a verificação para saber se a lista comporta mais um item vai retornar negativa. Para comportar mais itens, será criada uma nova lista com a capacidade duplicada da atual, que será 8. Os itens da lista atual serão copiados para a nova e aí sim será adicionado o quinto item, fazendo com que ainda sobre 3 posições. Essa lógica é repetida quantas vezes forem necessárias para comportar os itens que estamos adicionando e assim vamos criando listas com capacidade de 4, 8, 16, 32, 64, 128... E as listas antigas simplesmente são deixados para trás e ficam a cargo do Garbage Collector fazer a limpeza delas. Dependendo da quantidade, isso gera pressão desnecessária no GC afetando a performance da sua aplicação. Entenderam a importância de definirmos a capacidade? Para isso, basta usar o construtor com o parâmetro int:

List<Aluno> alunos = new List<Aluno>(500);
Enter fullscreen mode Exit fullscreen mode

Conclusão

Usar a capacidade na inicialização da lista é uma abordagem extremamente simples mas muito útil ao lidar com grande quantidade dados. "Ah, mas e quando eu não sei quantos itens serão adicionados?" Aqui entra a importância de entendermos a volumetria da aplicação que estamos trabalhando. A ideia não é acertarmos a quantidade exata, mas termos uma noção para evitarmos pressão desnecessária no Garbage Collector. Quer entender com mais detalhes como isso funciona no GC? Confira aqui

Referências

List<T> Class
Github - dotnet runtime

Top comments (0)