Tutorial Java 8
"Java ainda está vivo e as pessoas estão começando a entendê-lo."
Bem-vindo à minha introdução ao Java 8. Este artigo irá guiá-lo passo a passo por todos os novos recursos do Java 7 ao Java 8. Com exemplos de código rápidos e simples, podemos aprender como usar interfaces padrão, referências de
método e Anotações repetíveis . Ao final do artigo conheceremos a API Stream.
Sem conversas desnecessárias - apenas códigos e comentários! Avançar!
Métodos padrão para interfaces
Java 8 nos permite adicionar métodos não abstratos (que são implementados) às interfaces adicionando o
default
. Esse recurso também é conhecido como
Métodos de Extensão . Abaixo está o primeiro exemplo:
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
Além do método abstrato
calculate
, a interface
Formula
também define um método padrão
sqrt
. As classes que implementam essa interface só precisam implementar o
calculate
. O método padrão
sqrt
pode ser usado imediatamente.
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100);
formula.sqrt(16);
A interface
Formula
é implementada como uma classe anônima. O código é redundante: 6 linhas para implementação
sqrt(a * 100)
. Como veremos na próxima seção, existe uma maneira mais bonita de implementar um único método em Java 8.
Expressões lambda
Vamos começar com um exemplo simples de classificação de uma lista de strings em versões anteriores do Java:
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
O método estático
Collections.sort
aceita uma lista e um comparador na ordem em que a lista deve ser classificada. Você sempre pode criar uma classe comparadora anônima e repassá-la. Em vez de criar uma classe anônima, no Java 8 você pode criar uma notação mais curta, uma expressão lambda.
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
Como você pode ver, o código é muito mais curto e fácil de ler. Mas isso pode ser ainda mais curto:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
Para um corpo com uma linha, você pode pular
{}
a palavra
return
. Mas você pode torná-lo ainda mais curto:
Collections.sort(names, (a, b) -> b.compareTo(a));
O compilador Java conhece os tipos de argumentos, portanto você também pode ignorá-los. Vamos nos aprofundar nas expressões lambda e entender como elas podem ser usadas.
Interfaces Funcionais
Como as expressões lambda se encaixam no sistema de tipos Java? Cada lambda corresponde a um tipo descrito na interface. Portanto, uma interface funcional deve conter apenas um método abstrato. Cada expressão lambda deste tipo corresponderá a este método abstrato. Como os métodos padrão não são abstratos, você pode criar métodos padrão em interfaces funcionais conforme necessário. Também podemos usar interfaces arbitrárias como expressões lambda se houver apenas um método abstrato nesta interface. Para atender a esses requisitos, você precisa adicionar
@FucntionalInterface
uma anotação. O compilador sabe disso e lançará uma exceção se você quiser fornecer mais de um método abstrato. Exemplo:
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);
Lembre-se de que o código também será compilado se
@FunctionalInterface
a anotação for omitida.
Referências de métodos e construtores
O exemplo acima também pode ser ainda menor usando referências de método:
Converter<String, Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);
Java 8 permite passar referências para um método ou construtor adicionando
::
. O exemplo acima mostra como podemos fazer referência a um método estático, embora também possamos fazer referência a métodos não estáticos:
class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);
Vamos ver como
::
funciona com construtores. Para começar, definiremos uma classe de exemplo com diferentes construtores:
class Person {
String firstName;
String lastName;
Person() {}
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
A seguir, definiremos uma interface para criação de novos objetos:
interface PersonFactory<P extends Person> {
P create(String firstName, String lastName);
}
Em vez de implementar uma fábrica de criação, uniremos tudo com
::
a ajuda do construtor:
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");
Criamos um link para o construtor via
Person::new
. O compilador Java selecionará automaticamente o construtor correto que corresponda à assinatura do método
PersonFactory.create
. ... Continua. Infelizmente, não encontrei uma maneira de salvar um rascunho do artigo, e isso é muito estranho, e o tempo de tradução acabou - então terminarei mais tarde. Para todos que conhecem e entendem inglês -
Artigo Original . Se você tiver sugestões para corrigir a tradução, escreva da forma que estiver disponível.
Minha conta Github
GO TO FULL VERSION