JavaRush /Blogue Java /Random-PT /Livrando-se de loops em Java 8
KapChook
Nível 19
Volga

Livrando-se de loops em Java 8

Publicado no grupo Random-PT
O estilo funcional introduzido no Java 8 é um ótimo complemento para a linguagem. Agora Java não é OOP puro, agora é um híbrido de OOP e programação funcional. Isso é uma virada de jogo e precisamos mudar nossos cérebros OOP para absorver essas mudanças. Livrando-se de loops em Java 8-1Mas por que deveríamos aceitar essas mudanças? Por que deveríamos perder tempo tentando nos dar bem com um estilo funcional quando podemos resolver o problema usando OOP pura?
  • O estilo funcional introduzido no Java 8 nos ajuda a reduzir a lacuna entre a lógica de negócios e o código. Isso nos permite contar a história em um fluxo natural em um nível superior. Em vez de dizer como deseja fazer, você pode dizer o que deseja fazer.

  • O código fica mais limpo e conciso.

  • Funções de alta ordem nos permitem:

    • Enviar funções para outras funções
    • Crie funções dentro de outras funções
    • Retornar funções de outras funções

    Esta é uma grande vitória para Java, onde precisamos enviar, criar e retornar objetos para fazer isso. Seremos capazes de escrever código mais confiável, focado e mais fácil de reutilizar.

  • Graças aos lambdas, podemos fazer cálculos preguiçosos. Quando uma expressão lambda é enviada como argumento de método, o compilador a avaliará quando for chamada no método. Isso é diferente dos argumentos normais do método, que são avaliados imediatamente.

  • Lambdas tornam a escrita de testes unitários divertida. Eles nos permitem criar testes leves, limpos, de tamanho pequeno e rápidos de escrever. Podemos erradicar o código em teste usando lambdas. Isso nos permite testar como todos os tipos de cenários afetarão o código.

  • Novos padrões para aprender.

  • E muito mais!

Mas chega de água, neste artigo daremos uma olhada em soluções alternativas aos ciclos tradicionais. É claro que os ciclos são flexíveis, mas isso tem um preço. break, mudam drasticamente o comportamento do loop, forçando-nos a entender não apenas o que o código está tentando alcançar, continuemas returntambém a entender como o loop funciona. Agora veremos como podemos transformar loops em códigos mais concisos e legíveis.

Deixe a codificação começar!

Trabalharemos com artigos. Um artigo possui título, autor e diversas tags.

private class Article {
 
    private final String title;
    private final String author;
    private final List<String> tags;
 
    private Article(String title, String author, List<String> tags) {
        this.title = title;
        this.author = author;
        this.tags = tags;
    }
 
    public String getTitle() {
        return title;
    }
 
    public String getAuthor() {
        return author;
    }
 
    public List<String> getTags() {
        return tags;
    }
}
Cada exemplo conterá uma solução tradicional usando loops e uma solução usando os novos recursos do Java 8. No primeiro exemplo, queremos encontrar o primeiro artigo da coleção com a tag “Java”. Vamos dar uma olhada em uma solução usando um loop.

public Article getFirstJavaArticle() {
 
    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            return article;
        }
    }
    return null;
}
Agora vamos resolver o problema usando operações da API Stream.

public Optional<Article> getFirstJavaArticle() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .findFirst();
    }
Muito legal, não é? Primeiro usamos a operação filterpara encontrar todos os artigos com a tag “Java” e depois usamos findFirst()para obter a primeira ocorrência. Como os fluxos são preguiçosos e o filtro retorna um fluxo, essa abordagem processará apenas os elementos até encontrar a primeira correspondência. Agora vamos colocar todos os artigos marcados como “Java” em vez de apenas o primeiro. Primeiro a solução usando loops.

public List<Article> getAllJavaArticles() {
 
    List<Article> result = new ArrayList<>();
 
    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            result.add(article);
        }
    }
    return result;
}
Solução usando operações de fluxo.

public List<Article> getAllJavaArticles() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .collect(Collectors.toList());
    }
Neste exemplo, usamos uma operação collectpara encurtar o fluxo resultante, em vez de declarar uma coleção e adicionar explicitamente as entradas correspondentes. Até agora tudo bem. É hora de exemplos que farão a API Stream realmente brilhar. Vamos agrupar todos os artigos por autor. Como de costume, começamos resolvendo-o usando loops:

public Map<String, List<Article>> groupByAuthor() {
 
    Map<String, List<Article>> result = new HashMap<>();
 
    for (Article article : articles) {
        if (result.containsKey(article.getAuthor())) {
            result.get(article.getAuthor()).add(article);
        } else {
            ArrayList<Article> articles = new ArrayList<>();
            articles.add(article);
            result.put(article.getAuthor(), articles);
        }
    }
    return result;
}
Podemos encontrar uma solução limpa para este problema usando operações de fluxo?

public Map<String, List<Article>> groupByAuthor() {
    return articles.stream()
        .collect(Collectors.groupingBy(Article::getAuthor));
}
Incrível! Ao usar uma operação groupingBye uma referência de método getAuthor(), obtemos um código limpo e legível. Agora vamos encontrar o restante das tags usadas na coleção. Vamos começar com um exemplo de loop:

public Set<String> getDistinctTags() {
 
    Set<String> result = new HashSet<>();
 
    for (Article article : articles) {
        result.addAll(article.getTags());
    } 
    return result;
}
Ok, vamos dar uma olhada em como podemos resolver isso usando operações de stream:

public Set<String> getDistinctTags() {
    return articles.stream()
        .flatMap(article -> article.getTags().stream())
        .collect(Collectors.toSet());
}
Legal! flatmapnos ajuda a nivelar a lista de tags em um único fluxo de resultados, que então usamos collectpara criar o conjunto de retorno.

Infinitas possibilidades

Estes foram 4 exemplos de como os loops podem ser substituídos por código mais legível. Não deixe de conferir a API Stream, pois este artigo apenas arranhou a superfície. Dominar o novo estilo funcional do Java será um desafio para os desenvolvedores de OOP, mas é um desafio que deve ser bem recebido. Vou ainda mais longe e digo que você deve aprender uma linguagem de programação funcional pura. Dessa forma, você pode compreender totalmente os recursos e o poder que ele oferece. Acho que isso ajudará você a entender a programação funcional em um nível diferente. Portanto, aprenda programação funcional junto com o bom e velho OOP e use ambos para escrever códigos ainda melhores! Uma mistura gratuita de traduções de dois artigos - Por que você deve adotar a programação funcional no Java 8 e Afastando-se dos Loops no Java 8
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION