Texto de: Geraldo Daros
Introdução
Em Java, um método construtor é um bloco de código especial chamado quando uma instância de uma classe é criada usando a palavra-chave new. No geral, o método construtor tem a responsabilidade de iniciar os atributos de um objeto, permitindo, ao mesmo tempo, a adição de personalizações específicas por parâmetros durante sua invocação e lógicas dentro do próprio método construtor.
Tipos de construtores
Em Java, existem dois tipos principais de construtores, conforme explicado:
- Construtor Padrão:
- É o construtor que não recebe nenhum argumento.
- Ele é fornecido automaticamente pelo compilador se nenhum construtor for definido explicitamente na classe.
- Inicializa os atributos do objeto com valores padrão para cada tipo de dado.
- Se um construtor com parâmetros for definido explicitamente, o construtor padrão precisa ser explicitamente fornecido se desejado.
- Construtor com Parâmetros:
- É o construtor que recebe argumentos durante a criação do objeto.
- Os argumentos fornecidos durante a chamada do construtor são usados para inicializar os atributos do objeto com valores específicos.
- Ele permite uma personalização mais detalhada da inicialização do objeto com base nos valores passados como argumentos.
Declaração de construtores
A estrutura de declaração de um construtor assemelha-se à de um método, mas com o mesmo nome da classe à qual pertence. Além disso, é caracterizado por não possuir um tipo de retorno e deve ser declarado como público. Aqui está um exemplo de um construtor padrão dentro da classe Pessoa:
public class Pessoa {
String nome;
String endereco;
String cpf;
int idade;
// Construtor abaixo:
public Pessoa() {
}
}
O construtor padrão, conforme mencionado anteriormente, é gerado automaticamente, portanto, não é necessário criá-lo manualmente. Embora eu tenha optado por criá-lo manualmente neste exemplo para ficar claro como ele é por padrão, é recomendável evitar a criação manual do construtor padrão, a menos que seja estritamente necessário, especialmente quando se pretende utilizar apenas o construtor padrão em uma classe. Aqui está um exemplo de um construtor com parâmetros na mesma classe:
public class Pessoa {
String nome;
String endereco;
String cpf;
int idade;
// Construtor abaixo:
public Pessoa(String nome, String endereco, String cpf, int idade) {
this.nome = nome;
this.endereco = endereco;
this.cpf = cpf;
this.idade = idade;
}
}
Nesse construtor estamos recebendo parâmetros e então adicionando esses valores recebidos por parâmetro nos atributos da classe.
Chamando construtores
Para criar um objeto de uma classe, usamos a palavra-chave “new” e após chamamos o construtor. Aqui está um exemplo de como chamar um construtor padrão:
new Pessoa();
Agora um exemplo chamando o construtor com parâmetros:
new Pessoa("Fulano", "Rua ABC, "01234567-89", 32);
Para chamarmos o construtor, utilizamos a palavra “new”, e, em seguida, a chamada do método construtor “NomeDoMétodoConstrutor”, juntamente com os parênteses “()”, nesse momento, podemos passar ou não os parâmetros. É importante observar que os parâmetros são cruciais, pois determinam qual construtor o Java irá utilizar. Então, memorize: sempre que você ver um “new Classe();” você está chamando um construtor, seja com argumentos dentro de () ou sem argumentos, você está chamando um construtor! Aqui um exemplo:
Agora, é extremamente importante observar dois pontos: ao usar o construtor padrão, os valores serão os padrões correspondentes a cada tipo. Com isso, todos os atributos do tipo String serão nulos, enquanto a idade, do tipo int, será zero. É fundamental ter em mente que cada tipo possui seu próprio valor padrão, portanto, é crucial exercer cautela ao utilizar o construtor padrão e estar consciente de que os valores assumirão os padrões predefinidos para cada tipo.
Já no construtor com argumentos, você precisa estar ciente da ordem dos argumentos passados, já que eles devem seguir a ordem que você definiu no construtor e se você colocar em outra ordem na hora da chamada o construtor pode gerar erro ou então vai trocar a atribuição de valores, por exemplo:
Pessoa pessoaComParametros = new Pessoa("Rua ABC", "Fulano", "01234567-89", 32);
// Variável "pessoaComParametros" vai receber a instancia criada retornada pelo construtor.
Nesse exemplo, foi invertido o nome com o endereço. Então, ao criar o objeto o nome terá o valor esperado para o endereço e o endereço o valor esperado para o nome. Isso acontece devido à ordem dos parâmetros no construtor, onde recebemos: nome, endereço, CPF e idade, nesse caso os valores passados como parâmetros foram, endereço, nome, CPF e idade. Esse exemplo não irá gerar erro, pois os dois valores são do tipo String, porém se os tipos forssem diferentes o compilador já iria gerar erro e não rodaria o código. É extremamente importante ter atenção com os valores e a ordem em que os construtores recebem os parâmetros.
Personalizando construtores
Agora que nós já sabemos como modificar e como usar os construtores, podemos tornar eles algo extremamente útil no nosso dia a dia, com algumas personalizações. Validações não são responsabilidade dos construtores, mas nessa sessão veremos pequenas validações no construtor por questões didáticas, mesmo não sendo uma prática interessante de se usar. Vamos melhorar construtor que usamos anteriormente:
public Pessoa(String nome, String endereco, String cpf, int idade) {
verificarCpfValido();
verificarNomeValido();
verificarEnderecoValido();
verificarIdadeValido();
this.nome = nome;
this.endereco = endereco;
this.cpf = cpf;
this.idade = idade;
}
Nesse exemplo, a classe executa 4 métodos de verificação antes de atribuir os valores. A regra para validar cada atributo dependerá do seu negócio.
Vejamos outro exemplo, dessa vez recebendo um objeto de um determinado tipo no construtor:
public Pessoa(DocumentoIdentificacao documentoIdentificacao, String endereco) throws Exception {
if (endereco != null && !endereco.isEmpty()) {
this.endereco = endereco;
} else {
throw new Exception("Endereco inválido!");
}
this.nome = documentoIdentificacao.nome;
this.cpf = documentoIdentificacao.cpf;
this.idade = documentoIdentificacao.idade;
}
Nesse construtor fomos um pouco além. Nós recebemos um objeto do tipo DocumentoIdentificacao que contém informações sobre a pessoa e então adicionamos esse objeto ao nosso novo objeto que está sendo criado. Também recebemos o endereço de forma explícita e verificamos se ele não está nulo nem vazio. Se o endereço for válido, alteramos o endereço atual e inserimos o novo, mas se ele for nulo ou vazio irá gerar uma exceção.
Boas práticas ao usar construtores
Considere algumas boas práticas ao usar construtores em Java:
- Forneça construtores significativos: certifique-se de que os construtores tenham parâmetros significativos que indiquem claramente a finalidade de cada construtor.
- Use construtores para garantir estados válidos: projete os construtores para assegurar que os objetos criados possuam um estado válido e consistente.
- Evite a lógica complexa nos construtores: os construtores devem ser simples e rápidos. Evite incluir lógica de negócios complexa neles, mova essa lógica para outros métodos da classe.
- Use construtores padrão com cuidado: se você fornecer construtores personalizados, pode ser uma boa prática fornecer um construtor padrão sem parâmetros apenas se ele fizer sentido para a sua classe.
- Evite construtores muito longos: construtores com muitos parâmetros podem ser difíceis de usar e entender.
Conclusão
Os construtores são uma parte fundamental da programação em Java, permitindo a inicialização adequada de objetos. Compreender como criar e usar construtores é essencial para escrever código Java eficiente e robusto. Ao seguir as boas práticas e princípios discutidos neste artigo, você poderá criar classes e seus construtores de forma mais legível, modular e fácil de manter.