O que são interfaces Java 8 e como usá-las?
Em Java, uma interface funciona da mesma maneira que uma classe abstrata, o que significa que um objeto nunca pode ser criado a partir de uma interface. Como resultado disso, uma interface não possui construtores, mas possui métodos.
Antes do Java 8, uma interface podia delinear as operações que sua classe de implementação executa, mas não como a classe de implementação deveria executar essa operação (mais sobre isso posteriormente). Agora, com o Java 8, um desenvolvedor pode fazer as duas coisas com uma interface.
Isso ocorre porque o Java 8 introduziu métodos de interface padrão. Portanto, os desenvolvedores agora têm a opção de usar métodos abstratos tradicionais, bem como os novos métodos concretos em uma interface. Vamos olhar mais de perto.
O que é uma interface?
Antes que você possa realmente entender o propósito de uma interface e como usá-la com eficácia, você precisa entender o polimorfismo. O polimorfismo é um conceito central da programação orientada a objetos, que permite a um desenvolvedor criar um comportamento generalizado e especializado com classes (que, em alguns casos, não estão diretamente relacionados).
O principal benefício do polimorfismo é que ele facilita a reutilização de código, o que é vital na indústria de desenvolvimento de software atual.
Então, como o polimorfismo se relaciona com uma interface Java? Em Java, uma interface permite que classes que não seriam convencionalmente relacionadas tenham acesso a operações semelhantes. Em sua forma mais simples, uma interface Java é um modelo que pode ser facilmente utilizado pelas diferentes classes que o implementam. Essas classes de implementação podem então transformar o método de uma interface de seu estado generalizado para um estado mais especializado para realizar uma tarefa específica.
Quais são os benefícios do uso de interfaces Java 8?
O benefício mais óbvio de usar uma interface Java 8 é seu novo recurso de método concreto.
Outro benefício bem-vindo das interfaces Java 8 é a capacidade de adicionar novos métodos concretos a uma interface existente, que já foi implementada, sem quebrar o programa. Antes do Java 8, se você tivesse uma classe implementando uma interface, mas não usando todos os seus métodos, essa classe teria que ser rotulada como abstrata. Caso contrário, o programa seria interrompido.
Quando você deve usar uma interface?
Muitos programas existentes podem potencialmente utilizar interfaces Java 8. A função de uma interface é facilitar a vida do programador. Embora a mesma funcionalidade possa ser alcançada sem interfaces, usá-los tornará seus programas mais organizados e seu processo de desenvolvimento menos demorado.
Se você está familiarizado com herança, deve saber que também é um conceito central da programação orientada a objetos que facilita a generalização. Com a herança, classes semelhantes são agrupadas em relacionamentos pai-filho.
Com o polimorfismo (que é o comportamento de programação que uma interface exibe), as classes que geralmente não teriam acesso aos mesmos métodos (devido à falta de relacionamentos pai-filho), agora podem ser processadas polimorficamente.
Um exemplo prático de uso de interface está no departamento de contas de uma organização de software. Este departamento provavelmente conduzirá um conjunto dos mesmos métodos (ou operações) ao criar o recibo de pagamento de um funcionário e a fatura de um cliente.
Essas são duas classes que não seriam convencionalmente relacionadas, mas agora podem usar algumas das mesmas operações graças às interfaces Java 8.
Criação de uma interface em Java
Usando o cenário do departamento de contas acima, você pode criar uma interface que lida com as operações de pagamento. O objetivo dessa interface é auxiliar na geração de relatórios de pagamento (na forma de faturas, holerites e outras despesas).
Criação de um exemplo de interface Java
//Java interface
public interface Payable {
//abstract method public void paymentAmount();
}
O código acima gera uma interface Java simples. A palavra-chave interface indica que Payable é uma interface e o método paymentAmount () é um método abstrato porque não foi implementado.
Implementando o Exemplo de Interface a Pagar
public class Employee implements Payable {
//attributes
private String name; private String position;
//primary constructor
public Employee (String name, String position) {
this.name = name; this.position = position;
}
//payLevel method - takes an employee's position and returns their pay
public double payLevel(String position) {
position.toLowerCase();
if (position == "junior" ) {
return 10.00;
}
if(position == "mid-level") {
return 20.0;
}
if(position == "senior") {
return 30.00;
}
return 0 ;
}
@Override public void paymentAmount() {
//passes the position attribute provided by the user to the payLevel() method above
// store the return from the function call to a double variable called pay
//and print the relevant data to the console
double pay = payLevel(position);
System.out.println(name + " pay for this month is: " + pay);
}
}
Para usar uma interface em uma classe, você primeiro precisa implementar essa interface usando a palavra-chave implementar , como você pode ver no código acima. Depois de implementar uma nova interface, você deve criar métodos concretos para todos os métodos abstratos na interface, usando a palavra-chave @Override .
Executando o Exemplo de Programa
public class Main {
public static void main(String[] args) {
//Create a new employee pay report
Payable JanesPay = new Employee ("Jane Doe", "mid-level");
//calculate the employee's pay
JanesPay.paymentAmount();
}
}
O programa acima usa a classe Employee para gerar um novo contracheque que utiliza a interface Payable . Um objeto não pode ser criado a partir de uma interface, mas um objeto pode ser declarado usando uma interface, como você pode ver no código acima.
O objeto de pagamento de Jane é criado usando dois atributos – o nome de um funcionário e a posição do funcionário na empresa. Há apenas um construtor primário na classe de funcionário , portanto, cada novo objeto de funcionário criado deve ter dois atributos de string.
Usando o objeto de pagamento de Jane , o programa chama o método paymentAmount () na classe do funcionário , que produz a seguinte saída no console:
Jane Doe pay for this month is: 20.0
Implementando a Interface a Pagar com Exemplo de Cliente
public class Customer implements Payable{
private String customerName;
private String projectType;
public Customer(String customerName, String projectType) {
this.customerName = customerName;
this.projectType = projectType;
}
public double customerInvoice(String projectType) {
projectType.toLowerCase();
if (projectType == "small" ) {
return 10.00;
}
if(projectType == "medium") {
return 20.0;
}
if(projectType == "large") {
return 30.00;
}
return 0 ;
}
@Override public void paymentAmount() {
double total = customerInvoice(projectType);
System.out.println(customerName + " total charge for services provided is: " + total);
}
}
As classes de funcionários e clientes não estão relacionadas entre si, mas como cada uma implementa a mesma interface, agora eles têm acesso a operações semelhantes. Como a classe de funcionário , a classe de cliente deve implementar a interface e substituir o método abstrato paymentAmount () para funcionar corretamente.
Agora, as mesmas operações que foram conduzidas em um objeto da classe do funcionário , também podem ser conduzidas em um objeto da classe do cliente .
Criação de um exemplo de objeto do cliente
public class Main {
public static void main(String[] args) {
//Create a new customer invoice report
Payable PaulsInvoice = new Customer("Paul Smith", "large");
//calculate the customer's pay
PaulsInvoice.paymentAmount();
}
}
O código acima gera a seguinte saída no console:
Paul Smith total charge for services provided is: 30.0
Como a interface é Java 8, você pode adicionar métodos padrão a ela sem quebrar o código, como você pode ver no exemplo abaixo.
Exemplo de atualização de uma interface Java 8
//Java interface
public interface Payable {
//abstract method
public abstract void paymentAmount();
//concrete method
public default void companyName() {
System.out.println("Software Company");
}
}
Antes do Java 8, adicionar o método concreto no código acima à sua interface quebraria a interface. Isso ocorre porque as interfaces anteriores ao Java 8 não podiam ter métodos concretos. No entanto, se o método fosse abstrato, a interface não seria afetada. Mas as classes que o implementassem antes de o novo método ser adicionado seriam interrompidas.
Agora, por causa do Java 8, adicionar métodos concretos a uma interface não interromperá as classes que já foram implementadas. Portanto, os objetos criados a partir de qualquer uma das duas classes de implementação neste exemplo de gerenciamento de conta podem usar o método companyName () sem alterar seu código existente.
Usando Java 8 Interface Exemplo de Método Padrão
public class Main {
public static void main(String[] args) {
//Create a new employee pay report
Payable JanesPay = new Employee("Jane Doe", "mid-level");
//call the default method from the interface
JanesPay.companyName();
//calculate the employee's pay
JanesPay.paymentAmount();
}
}
O código acima produzirá o seguinte no console:
Software Company
Jane Doe pay for this month is: 20.0
Usando generalização para criar código reutilizável
Agora você pode usar operações semelhantes para classes que não são convencionalmente relacionadas com a ajuda de interfaces Java 8. Você também tem a opção e o conhecimento de usar métodos concretos e abstratos em suas interfaces.
Mas para classes que são convencionalmente relacionadas, você pode aprender como reutilizar código com herança.