Java 8: Guia de Referência Rápida Completo
Java 8 - Visão Geral
O Java 8 é um lançamento de recursos majeurs da linguagem Java. Sua versão inicial saiu em 18 de março de 2014. Com ele, o Java passou a suportar programação funcional, novo motor JavaScript, novas APIs de manipulação de data/hora, nova API de Streams, entre outros.
Novos Recursos
Expressões Lambda — Adicionam capacidade de processamento funcional.
Referências de Método — Referenciam funções pelo nome em vez de invocá-las diretamente.
Métodos Default — Interfaces podem ter implementação padrão.
Novas Ferramentas — Ferramentas de compilação e utilitários como
jdepspara análise de dependências.Stream API — Nova API para processamento em pipeline.
Date Time API — API de data/hora aprimorada.
Optional — Ênfase em boas práticas para lidar com valores nulos.
Nashorn, JavaScript Engine — Motor baseado em Java para executar código JavaScript.
Exemplo: Ordenação com Java 7 vs Java 8
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Comparator;
public class Java8Tester {
public static void main(String args[]) {
List<String> names1 = new ArrayList<>();
names1.add("Mahesh ");
names1.add("Suresh ");
names1.add("Ramesh ");
names1.add("Naresh ");
names1.add("Kalpesh ");
List<String> names2 = new ArrayList<>();
names2.add("Mahesh ");
names2.add("Suresh ");
names2.add("Ramesh ");
names2.add("Naresh ");
names2.add("Kalpesh ");
Java8Tester tester = new Java8Tester();
System.out.println("Ordenação com sintaxe Java 7: ");
tester.sortUsingJava7(names1);
System.out.println(names1);
System.out.println("Ordenação com sintaxe Java 8: ");
tester.sortUsingJava8(names2);
System.out.println(names2);
}
// Ordenação Java 7
private void sortUsingJava7(List<String> names) {
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
}
// Ordenação Java 8 com lambda
private void sortUsingJava8(List<String> names) {
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
}
}
Resultado:
Ordenação com sintaxe Java 7: [ Kalpesh Mahesh Naresh Ramesh Suresh ] Ordenação com sintaxe Java 8: [ Kalpesh Mahesh Naresh Ramesh Suresh ]
O método sortUsingJava8() usa expressão lambda como parâmetro para definir o critério de ordenação.
Java 8 - Configuração do Ambiente
Configuração Local
Para configurar seu ambiente Java, siga os passos:
Baixe o Java SE gratuitamente em: site da Oracle. Escolha a versão para seu sistema operacional, execute o instalador .exe e configure as variáveis de ambiente.
Windows 2000/XP
- Clique com botão direito em 'Meu Computador' → 'Propriedades'.
- Aba 'Avançado' → botão 'Variáveis de Ambiente'.
- Altere a variável 'Path' adicionando o caminho do
bindo JDK, ex:C:\WINDOWS\SYSTEM32;c:\Program Files\java\jdk\bin.
Windows 95/98/ME
- Edite
C:\autoexec.batadicionando:SET PATH=%PATH%;C:\Program Files\java\jdk\bin.
Linux, UNIX, Solaris, FreeBSD
Defina a variável PATH para o diretório dos binários Java. Exemplo para bash: export PATH=/path/to/java:$PATH no .bashrc.
Editores Java Populares
Notepad — Editor simples no Windows (recomendado para este tutorial) ou TextPad.
Netbeans — IDE open-source e gratuito. Download.
Eclipse — IDE da comunidade open-source. Download.
Java 8 - Expressões Lambda
Lambdas são o maior recurso do Java 8. Facilitam programação funcional e simplificam o desenvolvimento.
Sintaxe
parâmetro -> corpo da expressão
Características importantes:
Declaração de tipo opcional — O compilador infere o tipo pelo valor do parâmetro.
Parênteses opcionais — Para um único parâmetro, parênteses são opcionais; para múltiplos, obrigatórios.
Chaves opcionais — Não necessárias se o corpo tiver uma única instrução.
Palavra-chave return opcional — O compilador retorna automaticamente se o corpo for uma única expressão.
Exemplo de Expressões Lambda
Java8Tester.java
public class Java8Tester {
public static void main(String args[]) {
Java8Tester tester = new Java8Tester();
// Com declaração de tipo
MathOperation addition = (int a, int b) -> a + b;
// Sem declaração de tipo
MathOperation subtraction = (a, b) -> a - b;
// Com return e chaves
MathOperation multiplication = (int a, int b) -> { return a * b; };
// Sem return e sem chaves
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
// Sem parênteses
GreetingService greetService1 = message -> System.out.println("Hello " + message);
// Com parênteses
GreetingService greetService2 = (message) -> System.out.println("Hello " + message);
greetService1.sayMessage("Mahesh");
greetService2.sayMessage("Suresh");
}
interface MathOperation { int operation(int a, int b); }
interface GreetingService { void sayMessage(String message); }
private int operate(int a, int b, MathOperation mathOperation) {
return mathOperation.operation(a, b);
}
}
Verificando o Resultado
C:\JAVA>javac Java8Tester.java C:\JAVA>java Java8Tester
Saída:
10 + 5 = 15 10 - 5 = 5 10 x 5 = 50 10 / 5 = 2 Hello Mahesh Hello Suresh
Pontos-chave:
- Lambdas definem implementação inline de interfaces funcionais (interface com um único método).
- Eliminam a necessidade de classes anônimas, dando poder de programação funcional simples.
Escopo
Lambdas podem referenciar variáveis final ou effectively final (atribuídas uma única vez). Erro de compilação se a variável for reatribuída.
Exemplo de Escopo
public class Java8Tester {
final static String salutation = "Hello! ";
public static void main(String args[]) {
GreetingService greetService1 = message -> System.out.println(salutation + message);
greetService1.sayMessage("Mahesh");
}
interface GreetingService { void sayMessage(String message); }
}
Resultado
Hello! Mahesh
Java 8 - Referências de Método
Referências de método apontam para métodos pelo nome usando o símbolo ::. Podem referenciar:
- Métodos estáticos
- Métodos de instância
- Construtores com operador
new(ex:TreeSet::new)
Exemplo de Referência de Método
Java8Tester.java
import java.util.List;
import java.util.ArrayList;
public class Java8Tester {
public static void main(String args[]) {
List names = new ArrayList();
names.add("Mahesh");
names.add("Suresh");
names.add("Ramesh");
names.add("Naresh");
names.add("Kalpesh");
names.forEach(System.out::println);
}
}
Aqui passamos System.out::println como referência a método estático.
Verificando o Resultado
C:\JAVA>javac Java8Tester.java C:\JAVA>java Java8Tester
Saída:
Mahesh Suresh Ramesh Naresh Kalpesh
Java 8 - Interfaces Funcionais
Interfaces funcionais têm uma única funcionalidade. Exemplo: Comparable com compareTo. O Java 8 define muitas no pacote java.util.function.
| Nº | Interface e Descrição |
|---|---|
| 1 | BiConsumer<T,U> Operação que aceita dois argumentos e não retorna resultado. |
| 2 | BiFunction<T,U,R> Função que aceita dois argumentos e produz resultado. |
| 3 | BinaryOperator<T> Operação sobre dois operandos do mesmo tipo, resultando no mesmo tipo. |
| 4 | BiPredicate<T,U> Predicado (função booleana) de dois argumentos. |
| 5 | BooleanSupplier Fornecedor de resultados booleanos. |
| 6 | Consumer<T> Operação que aceita um argumento e não retorna resultado. |
| 7 | DoubleBinaryOperator Operação sobre dois operandos double, resultando double. |
| 8 | DoubleConsumer Operação que aceita um double e não retorna resultado. |
| 9 | DoubleFunction<R> Função que aceita double e produz resultado. |
| 10 | DoublePredicate Predicado de um argumento double. |
| 11 | DoubleSupplier Fornecedor de resultados double. |
| 12 | DoubleToIntFunction Função que aceita double e produz int. |
| 13 | DoubleToLongFunction Função que aceita double e produz long. |
| 14 | DoubleUnaryOperator Operação sobre um operando double resultando double. |
| 15 | Function<T,R> Função que aceita um argumento e produz resultado. |
| 16 | IntBinaryOperator Operação sobre dois ints resultando int. |
| 17 | IntConsumer Operação que aceita um int e não retorna resultado. |
| 18 | IntFunction<R> Função que aceita int e produz resultado. |
| 19 | IntPredicate Predicado de um argumento int. |
| 20 | IntSupplier Fornecedor de resultados int. |
| 21 | IntToDoubleFunction Função que aceita int e produz double. |
| 22 | IntToLongFunction Função que aceita int e produz long. |
| 23 | IntUnaryOperator Operação sobre um operando int resultando int. |
| 24 | LongBinaryOperator Operação sobre dois longs resultando long. |
| 25 | LongConsumer Operação que aceita um long e não retorna resultado. |
| 26 | LongFunction<R> Função que aceita long e produz resultado. |
| 27 | LongPredicate Predicado de um argumento long. |
| 28 | LongSupplier Fornecedor de resultados long. |
| 29 | LongToDoubleFunction Função que aceita long e produz double. |
| 30 | LongToIntFunction Função que aceita long e produz int. |
| 31 | LongUnaryOperator Operação sobre um operando long resultando long. |
| 32 | ObjDoubleConsumer<T> Operação que aceita objeto e double, sem resultado. |
| 33 | ObjIntConsumer<T> Operação que aceita objeto e int, sem resultado. |
| 34 | ObjLongConsumer<T> Operação que aceita objeto e long, sem resultado. |
| 35 | Predicate<T> Predicado de um argumento. |
| 36 | Supplier<T> Fornecedor de resultados. |
| 37 | ToDoubleBiFunction<T,U> Função que aceita dois argumentos e produz double. |
| 38 | ToDoubleFunction<T> Função que produz double. |
| 39 | ToIntBiFunction<T,U> Função que aceita dois argumentos e produz int. |
| 40 | ToIntFunction<T> Função que produz int. |
| 41 | ToLongBiFunction<T,U> Função que aceita dois argumentos e produz long. |
| 42 | ToLongFunction<T> Função que produz long. |
| 43 | UnaryOperator<T> Operação sobre um operando resultando no mesmo tipo. |
Exemplo de Interface Funcional
Predicate<T> é interface funcional com método test(Object) retornando boolean.
Java8Tester.java
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Java8Tester {
public static void main(String args[]) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println("Imprimir todos os números:");
eval(list, n -> true);
System.out.println("Imprimir números pares:");
eval(list, n -> n % 2 == 0);
System.out.println("Imprimir números maiores que 3:");
eval(list, n -> n > 3);
}
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for (Integer n : list) {
if (predicate.test(n)) {
System.out.println(n + " ");
}
}
}
}
Verificando o Resultado
C:\JAVA>javac Java8Tester.java C:\JAVA>java Java8Tester
Saída:
Imprimir todos os números: 1 2 3 4 5 6 7 8 9 Imprimir números pares: 2 4 6 8 Imprimir números maiores que 3: 4 5 6 7 8 9
Java 8 - Métodos Default
O Java 8 introduz implementação padrão em interfaces para compatibilidade reversa, permitindo que interfaces antigas aproveitem lambdas.
Exemplo: List ou Collection não tinham forEach. Adicionar esse método quebraria implementações. Com método default, a interface fornece implementação padrão e classes não precisam implementá-lo.
Sintaxe
public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
Múltiplos Defaults
Se uma classe implementa duas interfaces com mesmo método default, a ambiguidade deve ser resolvida.
public interface Vehicle {
default void print() { System.out.println("I am a vehicle!"); }
}
public interface FourWheeler {
default void print() { System.out.println("I am a four wheeler!"); }
}
Solução 1: Sobrescrever o método.
public class Car implements Vehicle, FourWheeler {
public void print() {
System.out.println("I am a four wheeler car vehicle!");
}
}
Solução 2: Chamar o default da interface específica via super.
public class Car implements Vehicle, FourWheeler {
public void print() {
Vehicle.super.print();
}
}
Métodos Default Estáticos
Interfaces também podem ter métodos estáticos auxiliares.
public interface Vehicle {
default void print() { System.out.println("I am a vehicle!"); }
static void blowHorn() { System.out.println("Blowing horn!!!"); }
}
Exemplo de Método Default
Java8Tester.java
public class Java8Tester {
public static void main(String args[]) {
Vehicle vehicle = new Car();
vehicle.print();
}
}
interface Vehicle {
default void print() { System.out.println("I am a vehicle!"); }
static void blowHorn() { System.out.println("Blowing horn!!!"); }
}
interface FourWheeler {
default void print() { System.out.println("I am a four wheeler!"); }
}
class Car implements Vehicle, FourWheeler {
public void print() {
Vehicle.super.print();
FourWheeler.super.print();
Vehicle.blowHorn();
System.out.println("I am a car!");
}
}
Verificando o Resultado
C:\JAVA>javac Java8Tester.java C:\JAVA>java Java8Tester
Saída:
I am a vehicle! I am a four wheeler! Blowing horn!!! I am a car!
Java 8 - Streams
Stream é uma camada abstrata para processar dados de forma declarativa, similar a SQL. Permite aproveitar arquitetura multicore sem código paralelo explícito.
O que é Stream?
Sequência de elementos — Conjunto de elementos de tipo específico, computados sob demanda, não armazenados.
Fonte — Collections, Arrays ou recursos I/O.
Operações agregadas — filter, map, limit, reduce, find, match, etc.
Pipelining — Operações retornam stream para encadeamento.
collect()é operação terminal.Iteração automática — Itera internamente sobre a fonte, ao contrário de Collections que exigem iteração explícita.
Gerando Streams
Interface Collection tem dois métodos:
stream()— Stream sequencial.parallelStream()— Stream paralelo.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
forEach
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
map
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); List<Integer> squaresList = numbers.stream().map(i -> i*i).distinct().collect(Collectors.toList());
filter
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
int count = strings.stream().filter(s -> s.isEmpty()).count();
limit
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
sorted
Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println);
Processamento Paralelo
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
long count = strings.parallelStream().filter(s -> s.isEmpty()).count();
Collectors
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
String mergedString = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.joining(", "));
Estatísticas
List numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt(x -> x).summaryStatistics();
System.out.println("Maior: " + stats.getMax());
System.out.println("Menor: " + stats.getMin());
System.out.println("Soma: " + stats.getSum());
System.out.println("Média: " + stats.getAverage());
Exemplo Completo de Stream
Java8Tester.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;
public class Java8Tester {
public static void main(String args[]) {
System.out.println("Usando Java 7: ");
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
System.out.println("Lista: " + strings);
long count = getCountEmptyStringUsingJava7(strings);
System.out.println("Strings vazias: " + count);
count = getCountLength3UsingJava7(strings);
System.out.println("Strings de tamanho 3: " + count);
List<String> filtered = deleteEmptyStringsUsingJava7(strings);
System.out.println("Lista filtrada: " + filtered);
String mergedString = getMergedStringUsingJava7(strings, ", ");
System.out.println("String mesclada: " + mergedString);
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = getSquares(numbers);
System.out.println("Lista de quadrados: " + squaresList);
List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
System.out.println("Lista: " + integers);
System.out.println("Máximo: " + getMax(integers));
System.out.println("Mínimo: " + getMin(integers));
System.out.println("Soma: " + getSum(integers));
System.out.println("Média: " + getAverage(integers));
System.out.println("Números aleatórios: ");
Random random = new Random();
for (int i = 0; i < 10; i++) {
System.out.println(random.nextInt());
}
System.out.println("Usando Java 8: ");
System.out.println("Lista: " + strings);
count = strings.stream().filter(s -> s.isEmpty()).count();
System.out.println("Strings vazias: " + count);
count = strings.stream().filter(s -> s.length() == 3).count();
System.out.println("Strings de tamanho 3: " + count);
filtered = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
System.out.println("Lista filtrada: " + filtered);
mergedString = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.joining(", "));
System.out.println("String mesclada: " + mergedString);
squaresList = numbers.stream().map(i -> i*i).distinct().collect(Collectors.toList());
System.out.println("Lista de quadrados: " + squaresList);
System.out.println("Lista: " + integers);
IntSummaryStatistics stats = integers.stream().mapToInt(x -> x).summaryStatistics();
System.out.println("Máximo: " + stats.getMax());
System.out.println("Mínimo: " + stats.getMin());
System.out.println("Soma: " + stats.getSum());
System.out.println("Média: " + stats.getAverage());
System.out.println("Números aleatórios: ");
random.ints().limit(10).sorted().forEach(System.out::println);
count = strings.parallelStream().filter(s -> s.isEmpty()).count();
System.out.println("Strings vazias (paralelo): " + count);
}
// Métodos auxiliares Java 7 omitidos por brevidade
}
Verificando o Resultado
C:\JAVA>javac Java8Tester.java C:\JAVA>java Java8Tester
Saída resumida mostra equivalência entre Java 7 e 8, com média mais precisa no Java 8.
Java 8 - Classe Optional
(Conteúdo idêntico ao artigo 1004016161, omitido para brevidade.)
Java 8 - Nashorn JavaScript
(Conteúdo idêntico ao artigo 1004016162, omitido para brevidade.)
Java 8 - Nova API Date/Time
(Conteúdo idêntico ao artigo 1004016163, omitido para brevidade.)
Java 8 - Base64
(Conteúdo idêntico ao artigo 1004016164, omitido para brevidade.)
Java
- Entendendo o Java Vector: Uso, Recursos e Comparação com ArrayList
- Fundamentos de Fresamento CNC: Guia de Referência Rápida para Operadores Profissionais
- Dominando Manutenção Preventiva e Baseada em Condição: Guia Prático de Desenvolvimento de MP
- Proteja sua Cadeia de Suprimentos: Estratégias Completas de Seguro
- Guia Especializado de Máquinas de Curvar Tubos Quadrados
- Prensas a Frio: Guia Completo para Conformação Metálica Eficiente
- Caixa Planetária Explicada: Redução de Velocidade Compacta e Alto Torque
- Fresadora-Furadeira Jet: O Guia Profissional Definitivo
- Prensas Servo: Como Funcionam e Vantagens Sobre Prensas Mecânicas
- Guia Profissional de Cilindros Pneumáticos: Rápidos e Confiáveis