A arte das coleções em .NET - List
Thaise Medeiros
Posted on April 13, 2023
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>();
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" });
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" });
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);
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
Posted on April 13, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.