Logo

dev-resources.site

for different kinds of informations.

Execução preguiçosa com Lambdas

Published at
7/21/2024
Categories
java
lambda
streams
Author
hugaomarques
Categories
3 categories in total
java
open
lambda
open
streams
open
Author
12 person written this
hugaomarques
open
Execução preguiçosa com Lambdas

Outro post curtinho! Esta semana eu peguei um bug interessante que achei bacana compartilhar com vocês. O bug em questão me fez lembrar como lambdas são executados de forma "lazy" no Java.

Vamos para o exemplo?

Execução preguiçosa da forma errada
Vamos analisar o seguinte exemplo. Imagine que você tem um stream em Java que você só quer executar dentro de um bloco com lock.

public class LazyStreamExample {
   private static final Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // Execução do Stream fora do Supplier
        System.out.println("Execução do Stream fora do Supplier");
        List<Integer> doubledNumbers = 
            numbers.stream()
                   .map(n -> {
                      System.out.println("Dobro de: " + n);
                      return n * 2;
                   })
                   .collect(Collectors.toList());

        writeToFileWithLock("output.txt", () -> doubledNumbers);
        System.out.println("Doubled Numbers: " + doubledNumbers);
    }

    private static void writeToFileWithLock(String filePath, Supplier<List<Integer>> supplier) {
        lock.lock();
        System.out.println("Lock adquirido!");
        try {
            List<Integer> result = supplier.get();
            String content = result.stream()
                                   .map(String::valueOf)
                                   .collect(Collectors.joining(", "));
            Files.write(Paths.get(filePath), content.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
            System.out.println("Resultado escrito no arquivo: " + content);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("Lock released!");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Se execurtamos o código acima veja o resultado:

Execução do Stream fora do Supplier
Dobro de: 1
Dobro de: 2
Dobro de: 3
Dobro de: 4
Dobro de: 5
Lock adquirido!
Resultado escrito no arquivo: 2, 4, 6, 8, 10
Lock released!
Doubled Numbers: [2, 4, 6, 8, 10]
Enter fullscreen mode Exit fullscreen mode

O nosso código executou fora do nosso lock 😱

Execução preguiçosa do jeito certo!

A correção do problema acima é trivial; basta entendermos que, para usarmos o poder "lazy" dos lambdas, precisamos executar o stream inteiro como parte do Supplier e não em uma variável separada.

Podemos fazer isso encapsulando o código em um método e chamando o método a partir do Supplier OU passando o bloco de código diretamente no Supplier. Vou utilizar a segunda opção aqui:

public class LazyLambdaExampleCorreto {
    private static final Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // Execução do Stream fora do Supplier
        System.out.println("Execução do Stream fora do Supplier");

        writeToFileWithLock("output.txt", () ->
                numbers.stream()
                        .map(n -> {
                            System.out.println("Dobro de: " + n);
                            return n * 2;
                        })
                        .collect(Collectors.toList()));
    }

    ...
}
Enter fullscreen mode Exit fullscreen mode

O código de escrita em arquivo continua o mesmo. A única coisa que mudamos foi passarmos o stream dentro do próprio supplier. Isso garante que só vamos executar o stream quando o supplier.get() for invocado.

O nosso novo resultado será:

Execução do Stream fora do Supplier
Lock adquirido!
Dobro de: 1
Dobro de: 2
Dobro de: 3
Dobro de: 4
Dobro de: 5
Resultado escrito no arquivo: 2, 4, 6, 8, 10
Lock released!
Enter fullscreen mode Exit fullscreen mode

Conclusão

Esse é um "erro bobo" que me pegou desprevenido. Naquele momento, tentando manter o código mais legível, eu isolei o meu stream em uma variável. Isso fez com que meu código rodasse fora do lock 😅.

Espero que este texto sirva de lembrete para vocês evitarem o mesmo problema.

streams Article's
30 articles in total
Favicon
How does Optional.ifPresent() differ from Optional.orElse()?
Favicon
Beyond the Basics: Mastering Streams in Node.JS
Favicon
The streaming bridges — A Kafka, RabbitMQ, MQTT and CoAP example
Favicon
Java Streams | What is the difference between sorted() and distinct() in streams?
Favicon
How to handle large file uploads in SvelteKit using streams
Favicon
Execução preguiçosa com Lambdas
Favicon
Руководство по Java 8 Stream API
Favicon
In Java how to create a custom ArrayList that doesn't allow duplicate? #Interview Question
Favicon
Why Set Doesn't Allow Duplicates in Java
Favicon
Optional Class in Java and its methods
Favicon
A Few About: Streams NodeJs (PT-BR)
Favicon
File reading in python
Favicon
Asynchronous Streams in C#: Effortless Async Data Processing
Favicon
Working with streams in Node.js
Favicon
Migrating to Phoenix Liveview Streams
Favicon
What is Java Stream and why does it exist?
Favicon
-
Favicon
Streams em Node.js para iniciantes (guia básico)
Favicon
From a data stream to the data warehouse
Favicon
Gentle Intro to Node Streams
Favicon
The Java `.boxed()` Method
Favicon
Request and Response Stream - Observations
Favicon
Getting a near-real-time view of a DynamoDB stream with Python
Favicon
Exploring Java Streams
Favicon
Service Worker Side Rendering (SWSR)
Favicon
Listening to payments (real-time) on your Stellar wallet
Favicon
Supporting Cross Node Interactive Queries In Kafka Streams
Favicon
Summing Java Streams Api
Favicon
Handling Slow Servers in NodeJS
Favicon
Java 8 Non ce n’est pas que les streams

Featured ones: