Mudanças na Interface Java 8 – método estático, método padrão

Java 8 trouxe mudanças nas interfaces, incluindo métodos estáticos e métodos padrão. Antes do Java 8, só podíamos ter declarações de método nas interfaces. Mas a partir do Java 8, podemos ter métodos padrão e estáticos nas interfaces.

Interface Java 8

Projetar interfaces sempre foi um trabalho difícil porque se quisermos adicionar métodos adicionais nas interfaces, será necessário fazer alterações em todas as classes que as implementam. À medida que a interface envelhece, o número de classes que a implementam pode crescer a ponto de não ser possível estender as interfaces. Por isso, ao projetar uma aplicação, a maioria dos frameworks fornece uma classe de implementação base e então a estendemos e sobrescrevemos os métodos que são aplicáveis para nossa aplicação. Vamos analisar os métodos de interface padrão e os métodos de interface estática e a razão de sua introdução nas mudanças de interface do Java 8.

Método Padrão da Interface Java

Para criar um método padrão em uma interface Java, precisamos usar a palavra-chave “default” com a assinatura do método. Por exemplo,

package com.journaldev.java8.defaultmethod;

public interface Interface1 {

	void method1(String str);
	
	default void log(String str){
		System.out.println("I1 logging::"+str);
	}
}

Observe que log(String str) é o método padrão na Interface1. Agora, quando uma classe implementar Interface1, não é obrigatório fornecer uma implementação para os métodos padrão da interface. Essa característica nos ajudará a estender interfaces com métodos adicionais, tudo o que precisamos é fornecer uma implementação padrão. Digamos que temos outra interface com os seguintes métodos:

package com.journaldev.java8.defaultmethod;

public interface Interface2 {

	void method2();
	
	default void log(String str){
		System.out.println("I2 logging::"+str);
	}

}

Sabemos que o Java não nos permite estender múltiplas classes porque resultará no “Problema do Diamante”, onde o compilador não pode decidir qual método da superclasse usar. Com os métodos padrão, o problema do diamante também surgiria para interfaces. Porque se uma classe estiver implementando tanto Interface1 quanto Interface2 e não implementar o método padrão comum, o compilador não poderá decidir qual escolher. Estender múltiplas interfaces é uma parte integral do Java, você encontrará isso nas classes Java principais, bem como na maioria das aplicações empresariais e frameworks. Então, para garantir que esse problema não ocorra em interfaces, é obrigatório fornecer uma implementação para os métodos padrão comuns das interfaces. Portanto, se uma classe estiver implementando ambas as interfaces acima, ela terá que fornecer uma implementação para o método log() caso contrário, o compilador lançará um erro de tempo de compilação. Uma classe simples que está implementando tanto Interface1 quanto Interface2 será:

package com.journaldev.java8.defaultmethod;

public class MyClass implements Interface1, Interface2 {

	@Override
	public void method2() {
	}

	@Override
	public void method1(String str) {
	}

	@Override
	public void log(String str){
		System.out.println("MyClass logging::"+str);
		Interface1.print("abc");
	}
}

Pontos importantes sobre os métodos padrão de interface Java:

  1. Métodos padrão de interface Java nos ajudarão a estender interfaces sem o receio de quebrar as classes de implementação.
  2. Métodos padrão de interface Java têm reduzido as diferenças entre interfaces e classes abstratas.
  3. Os métodos padrão de interface do Java 8 nos ajudarão a evitar classes utilitárias, como todos os métodos da classe Collections podem ser fornecidos nas próprias interfaces.
  4. Os métodos padrão de interface Java nos ajudarão a remover classes de implementação base, podemos fornecer uma implementação padrão e as classes de implementação podem escolher qual delas substituir.
  5. Uma das principais razões para a introdução de métodos padrão em interfaces é aprimorar a API de coleções no Java 8 para suportar expressões lambda.
  6. Se alguma classe na hierarquia tiver um método com a mesma assinatura, então os métodos padrão se tornam irrelevantes. Um método padrão não pode substituir um método de java.lang.Object. A razão é muito simples, é porque Object é a classe base para todas as classes Java. Portanto, mesmo se tivermos métodos de classe Object definidos como métodos padrão nas interfaces, será inútil porque o método de classe Object sempre será utilizado. É por isso que, para evitar confusão, não podemos ter métodos padrão que substituam os métodos de classe Object.
  7. Métodos padrão de interface Java também são referidos como Métodos Defensores ou Métodos de Extensão Virtual.

Método Estático de Interface Java

O método estático da interface Java é semelhante ao método padrão, exceto que não podemos substituí-los nas classes de implementação. Essa característica nos ajuda a evitar resultados indesejados em caso de implementação inadequada nas classes de implementação. Vamos analisar isso com um exemplo simples.

package com.journaldev.java8.staticmethod;

public interface MyData {

	default void print(String str) {
		if (!isNull(str))
			System.out.println("MyData Print::" + str);
	}

	static boolean isNull(String str) {
		System.out.println("Interface Null Check");

		return str == null ? true : "".equals(str) ? true : false;
	}
}

Agora vamos ver uma classe de implementação que possui o método isNull() com uma implementação inadequada.

package com.journaldev.java8.staticmethod;

public class MyDataImpl implements MyData {

	public boolean isNull(String str) {
		System.out.println("Impl Null Check");

		return str == null ? true : false;
	}
	
	public static void main(String args[]){
		MyDataImpl obj = new MyDataImpl();
		obj.print("");
		obj.isNull("abc");
	}
}

Observe que isNull(String str) é um método de classe simples, não está substituindo o método da interface. Por exemplo, se adicionarmos a anotação @Override ao método isNull(), resultará em erro de compilação. Agora, ao executarmos a aplicação, obtemos a seguinte saída.

Interface Null Check
Impl Null Check

Se tornarmos o método da interface de estático para padrão, obteremos a seguinte saída.

Impl Null Check
MyData Print::
Impl Null Check

O método estático da interface Java é visível apenas para métodos da interface, se removermos o método isNull() da classe MyDataImpl, não poderemos usá-lo para o objeto MyDataImpl. No entanto, como outros métodos estáticos, podemos usar métodos estáticos da interface usando o nome da classe. Por exemplo, uma declaração válida será:

boolean result = MyData.isNull("abc");

Pontos importantes sobre o método estático da interface Java:

  1. O método estático da interface Java faz parte da interface, não podemos usá-lo para objetos de classe de implementação.
  2. Os métodos estáticos da interface Java são bons para fornecer métodos utilitários, por exemplo, verificação de nulo, ordenação de coleções etc.
  3. O método estático de uma interface Java nos ajuda a fornecer segurança, não permitindo que as classes de implementação os substituam.
  4. Não podemos definir um método estático de interface para métodos da classe Object, receberemos um erro do compilador dizendo “Este método estático não pode ocultar o método de instância de Object”. Isso ocorre porque não é permitido em Java, uma vez que Object é a classe base para todas as classes e não podemos ter um método estático de nível de classe e outro método de instância com a mesma assinatura.
  5. Podemos usar métodos estáticos de interface Java para remover classes utilitárias como Collections e mover todos os seus métodos estáticos para a interface correspondente, o que seria fácil de encontrar e usar.

Interfaces Funcionais Java

Antes de concluir a postagem, gostaria de fornecer uma breve introdução às Interfaces Funcionais. Uma interface com exatamente um método abstrato é conhecida como Interface Funcional. Uma nova anotação @FunctionalInterface foi introduzida para marcar uma interface como Interface Funcional. A anotação @FunctionalInterface é uma facilidade para evitar a adição acidental de métodos abstratos nas interfaces funcionais. É opcional, mas é uma boa prática usá-la. As interfaces funcionais são uma característica muito aguardada do Java 8, pois nos permite usar expressões lambda para instanciá-las. Um novo pacote java.util.function com um conjunto de interfaces funcionais foi adicionado para fornecer tipos-alvo para expressões lambda e referências de método. Vamos explorar as interfaces funcionais e as expressões lambda nas postagens futuras.

Source:
https://www.digitalocean.com/community/tutorials/java-8-interface-changes-static-method-default-method