Mudanças na Interface do 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 em interfaces. 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, exigirá 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 que, ao projetar uma aplicação, a maioria dos frameworks fornece uma classe de implementação base e então a estendemos e substituímos os métodos 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 da interface Java 8.

Método Padrão de 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 implementação para os métodos padrão da interface. Essa funcionalidade 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 várias classes porque resultaria no “Problema do Diamante”, onde o compilador não consegue 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 conseguirá decidir qual escolher. Estender várias interfaces é uma parte integral do Java, você encontrará isso nas classes principais do Java, bem como na maioria das aplicações e estruturas empresariais. 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, será necessário 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 métodos padrão de interface Java:

  1. As métodos padrão da interface Java nos ajudarão a estender interfaces sem o receio de quebrar as classes de implementação.
  2. Os métodos padrão da interface Java têm diminuído as diferenças entre interfaces e classes abstratas.
  3. Os métodos padrão da interface Java 8 nos ajudarão a evitar classes utilitárias, pois todos os métodos da classe Collections podem ser fornecidos diretamente nas próprias interfaces.
  4. Os métodos padrão da interface Java nos ajudarão a remover classes de implementação base, podendo fornecer implementações padrão e as classes de implementação podem escolher qual delas substituir.
  5. Uma das principais razões para introduzir métodos padrão nas 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, 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 que tenhamos métodos de classe Object definidos como métodos padrão nas interfaces, será inútil, pois 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. Os métodos padrão da interface Java também são chamados de Métodos Defensores ou Métodos de Extensão Virtual.

Método Estático da Interface Java

interface Java método estático é semelhante ao método padrão, exceto que não podemos sobrescrevê-los nas classes de implementação. Essa característica ajuda a evitar resultados indesejados em caso de implementações inadequadas 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, vejamos 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 simples da classe, não está sobrescrevendo o método da interface. Por exemplo, se adicionarmos @Override anotação 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 os 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 os métodos estáticos da interface usando o nome da classe. Por exemplo, uma declaração válida seria:

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 da classe de implementação.
  2. Os métodos estáticos da interface Java são úteis para fornecer métodos de utilidade, como verificação nula, ordenação de coleções, etc.
  3. A interface estática do Java ajuda-nos a fornecer segurança ao não permitir que as classes de implementação as substituam.
  4. Não podemos definir métodos estáticos de interface para métodos da classe Object; obteremos um erro do compilador como “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 de utilitários, como Collections, e mover todos os seus métodos estáticos para a interface correspondente, o que facilitaria encontrar e usar.

Interfaces Funcionais em 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 há muito aguardada e muito procurada no Java 8, pois nos permite usar expressões lambda para instanciá-las. Um novo pacote java.util.function com uma variedade de interfaces funcionais foi adicionado para fornecer tipos-alvo para expressões lambda e referências a métodos. Vamos explorar interfaces funcionais e expressões lambda em postagens futuras.

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