Saturday, May 11, 2024

Revolutionizing Stream Pipelines with Custom Intermediate Operations JEP 473: Stream Gatherers (Second Preview)

Introduction

In the ever-evolving scene of Java improvement, the Stream API has been a foundation of utilitarian programming paradigms since its presentation in Java 8. With each iteration, Java looks for to enhance its capabilities advance. In this post, we dig into JEP 473, which presents Stream Gatherers as a second preview feature, pointed at making stream pipelines more adaptable and expressive.

Understanding Stream Gatherers

Stream Gatherers point to amplify the capabilities of the Stream API by presenting custom intermediate operations. These operations permit designers to change information in ways not effectively achievable with built-in intermediate operations, hence upgrading the adaptability and expressiveness of stream pipelines.

Goals and Non-Goals

The essential objective of Stream Gatherers is to make stream pipelines more adaptable and expressive. It points to engage engineers to control streams of information in ways that were already challenging with standard intermediate operations.However, it is fundamental to note the non-goals of this feature. It is not aiming to alter the Java programming language itself to facilitate stream processing, nor is it pointed at special-casing the compilation of code utilizing the Stream API. Instep, Stream Gatherers center unequivocally on improving the capabilities inside the Stream API system.

Motivation

The inspiration behind Stream Gatherers stems from the widespread adoption of streams in Java development. Whereas streams offer an effective and expressive way to prepare information, the settled set of intermediate operations now and then limits the capacity to express complex tasks concisely.

For occasion, consider scenarios where custom peculiarity criteria based on particular properties of components are required, or when gathering components into fixed-size groups with specialized logic gets to be fundamental. These are challenges that Stream Gatherers point to address effectively.

Exploring Stream Gatherers in Action

To better understand Stream Gatherers, let us dig into a commonsense example showcasing their control and flexibility.

Java Stream Gatherers: Understanding the Map Gatherer

In the space of Java programming, especially when overseeing with data taking care of utilizing streams, the map operation stands out as a crucial transformation instrument. let us burrow into a brief yet capable execution of the map gatherer, which plays a significant part in stream operations.

The Map Gatherer Function

Firstly, let us dissect the code snippet that characterizes the map gatherer:
  
    public final static  Gatherer map(Function mapper) {
        return Gatherer.of(
            () -> (Void)null,
            (nothing, element, downstream) ->
                downstream.push(mapper.apply(element)),
            (l,r) -> l,
            (nothing, downstream) -> {}
        );
    }
  

Code Breakdown

  1. Generic Declaration:
  2. <T, R>: This denotes the generic types used in the map gatherer. T represents the input type, while R signifies the ouput or return type.
  3. Gatherer.of Method:
  4. The Gatherer.of method constructs the gatherer using several functional interfaces.
  5. Initializer:
  6. () -> (Void)null: The initializer function returns null, essentially indicating no initial state is needed for this gatherer.
  7. Integrator:
  8. (nothing, element, downstream) -> downstream.push(mapper.apply(element)): Here, each element from the stream is processed by applying the 'mapper' function, which transforms T into R. The downstream.push method then passes this transformed element downstream for further processing.
  9. Combiner:
  10. (l, r) -> l: The combiner function specifies how to combine results when operating in parallel. In the map gatherer, this function simply returns the left result, as there's no need for combining.
  11. Finisher:
  12. (nothing, downstream) -> {}: Finally, the finisher function does nothing as there's no post-processing or final actions required for this gatherer.

Understanding the Map Operation

The essence of the map gatherer lies in its capacity to apply a transformation function (mapper) to each component of the stream, making a new stream of changed components. This adjusts closely with the customary map operation in Java streams, and this allows us to see the tremendous power of the Gatherers API, which can create new intermediate operations and also allows us to create our own versions of the standard Stream API functions such us map.

Example Usage

Lets's layout the utilization of the map gatherer with a essential example:
  
    Stream numbers = Stream.of(1, 2, 3, 4, 5);
    Gatherer stringMapper = map(Object::toString);
    List stringNumbers = numbers.gather(stringMapper).toList();
    System.out.println("Is the first number a string? " + (stringNumbers.get(0) instanceof String));
    System.out.println(stringNumbers);
  
In this case, we alter over a stream of integers into a stream of strings utilizing the map gatherer with a mapper function that changes integers to strings.

The code from this post can be run in Java Playground

Friday, April 29, 2016

Java code guidelines

The following are the java code guidelines used by Google and Oracle,



What is your favorite code guidelines and why? 

Enjoy...

Tuesday, November 17, 2015

Monday, August 31, 2015

Java Lambdas with no effectively final variables

In Java the variables that are outside of the scope of the lambdas needs to be effectively final, effectively final is when a variable is declare without the final modifier, but has all the characteristics of a final variable, this means that the variable is declare and initialize, but is never change after the initialization, see the following example:

Final variable declaration into a method:

    public void processWithFinalVariable() {
        List<info> infos = new ArrayList<>();
        final int finalVariable = 0;
        infos.add(new Info("Leonardo"));
     
        // final variable
        infos.forEach( info -> System.out.println("Variable value: " + finalVariable));
    }
Effectively final variable declaration into a method

    public void processWithEffectivelyFinalVariable() {
        List<info> infos = new ArrayList<>();
        int effectivelyFinalVariable = 0;
        infos.add(new Info("Leonardo"));
     
        // effectively final variable
        infos.forEach( info -> System.out.println("Variable value: " + effectivelyFinalVariable));
    }
No effectively final variable declaration into a method

    public void processWithNoEffectivelyFinalVariableChange() {
        List<info> infos = new ArrayList<>();
        int noEffectivelyFinalVariable = 0;
        infos.add(new Info("Leonardo"));
     
        // Compiler error, no effectively final or final variable
        infos.forEach( info -> System.out.println("Variable value: " + noEffectivelyFinalVariable));
     
        noEffectivelyFinalVariable++;
    }
As you can see in the previous examples you are not able to have a variable that is not final or effectively final, the purpose of this post is to show you that we are able to use non final or non effectively final variables in java lambdas.

To have a variable that is not effectively final or final in a lambda expressions you need to declare this variable at the level of the class instance, as you can see in the following example:

public class ExampleObject {
 
    //Instance variable that is not final or effectively final
    private int noEffectivelyFinalVariable = 0;
 
    public void processWithNoEffectivelyFinalVariable() {
        List<info> infos = new ArrayList<>();
     
        infos.add(new Info("Leonardo"));
     
        // See here the variable is able to be modified, is not final or effectively final
        infos.forEach( info -> System.out.println("Variable value: " + noEffectivelyFinalVariable++) );
    }
 
    public void printValue() {
        System.out.println("No Effectively Final Variable: " + noEffectivelyFinalVariable);
    }
}
The previous happened because the compiler adds the "this" java variable to the code that we are using to make the variable reference, and as you know the "this" variable is final by definition, this tell the compiler that is using a final variable and that the lambda is safe, see the following example:  

    public void processWithNoEffectivelyFinalVariableWithExplictThis() {
        List<info> infos = new ArrayList<>();
     
        infos.add(new Info("Leonardo"));
     
        // See here the variable is able to be modified, is not final or effectively final
        infos.forEach( info -> System.out.println("Variable value: " + this.noEffectivelyFinalVariable++) );
    }

Why the previous is possible, the answer is very simple the java compiler just only look up for effectively final variable that are directly reference by the lambda, and not between the compound variables of the effectively or final variable, the "this" variable is final and is a direct reference from the lambda, so the only thing that the compiler does, is to follow the final and effectively final rules and not applying the rules to the compound variables that are in the "this" variable.

The previous is not recommended to be used in your code or in production, because this can create race conditions, and make this kind of errors hard to understand by the developer.

How you can fix the previous:

    Mark the instance variable as final and the compiler will be complaining when it sees this kind of variables and changed from a lambda.

Project source code: ProjectSourceCode

Friday, August 28, 2015

JDK 8 Lambdas MOOC Course Videos and Slides Available

The videos and slides of the JDK 8 Lambdas MOOC online course are available now

In this online course you can see topics as:
  • Lambdas
  • Stream
  • Optional


Enjoy!!!

Tuesday, August 4, 2015

JEP 260: Encapsulate Most Internal APIs

The JEP 260 is a candidate to be included in JDK 9, this JEP deals with the problem that the modularization effort will have with the current internal APIs.

This JEP define three types of internal APIs:

  1. Non critical internal APIs, this are not critical and will be encapsulated in JDK 9
  2. Critical internal APIs witch supported replacement exists, this APIs are critical, but they have a replacement that was made in JDK 8. 
  3. Non encapsulated critical internal APIs, as Unsafe, this APIs does not have a replacement and are critical, this APIs remain public in JDK 9, but as soon as they have a replacement they could be encapsulated. 
If you need more information read the official JEP 260 page.




Monday, July 13, 2015

JDK 9 Module System Jigsaw 2 from N - JEP 200

This post is about the JEP 200, I will be bringing to you an explanation about what is JEP  200 and what is the importance of this JEP 200 for the java community and the java platform.

JEP 200 or the Modular JDK,is a Java Enhancement Proposal, that define a modular structure for the JDK, Make minimal assumptions about the module system that will be used to implement the structure. This is the first JEP that we have to start the process of modularity of the JVM and the Java platform, with this JEP we have the goal to divide the JDK in a set of modules, that can be used in compile time, build time, install time and run-time.  


The Module Graph


The below image represent the module graph of the Java Platform, this image has a transitive reduction of all the modules relationship, this with the purpose to make easy to understand and see the relationship between modules. 



From the previous image you can define that:



  • Orange is for standard modules.
  • Blue is for non standard modules.
  • When a module re-export the context of another module, the edge is darker otherwise the edge is lighter. 
  • Base module does not depend of any other module. 
  • There are aggregators modules like the java.se, and the aggregator module is a module that re-export the content of other modules and does not contains any content. 
  • The Module Graph is considering a new kind of API and will be maintained and evolved by the Java standardization process.  


No Standard Module is implemented, and is not a goal of this JEP to implement it. 


As we know the goal of this JEP is to make the JDK ready for modularization and the Java platform, and this means that any error, or previous part of the JDK that was not coded or build with the modularity concept in mind has to be fixed, as example we have: the API changes to the locale data, that will be make in a separate module for each locale.

The modularization process will produce a new way to test, compile, deploy and run, because each part of the JVM will be affected and this means that is not a simple process. 

Moreover, as we know we do not have any implementation of the module system at this point, and someone can ask, how the developers of Oracle will start the process to moduralize the JDK? The answers is simple, they use a simple XML document to define the module structure of the modules. See the below xml for an example of how the modules will be made coded for modularization: 

  java.security.sasl
  java.base
  java.logging
  
    javax.security.sasl
  

  
  
    com.sun.security.sasl.util
    java.security.jgss
  

Important definitions from the previous XML:  


Export: define what are the packages that you can be exported, moreover you can define what are the modules that can see the public content of your module, for example the java.security.sasl module can only export the com.sun.security.sasl.util package to the java.security.jgss module
Depend: mark the dependencies that a module has to another module, for example every module depends upon java.base module.
Re-Exports: let you export the public content of an existing module is used with a depended module. 

As you can see right now we are able to export, and mark a depended module, but this is only a xml that will be replaced with a compiler and run-time support, so this means that in the final definition of the module system we will have more options, as options to mark what are the services that a module has, or the ability make OAT (Ahead of time compilation). 

Conclusions:

First we saw that the JEP 200 define the start of the modular JDK, and is related to the structure of the new JDK modules, Second, this define some important concepts like export, depend, re-exports, Third, all this will be used by the module implementation, and we saw that the new modular JDK will have a module graph that will be used like an API, and it will be standardized, finally if you join all of these things you can see the importance of this JEP from the standardization to the module structure definition and for what this JEP is very important.  

For more information, JEP 200, openjdk.java.net.

I hope that you like this post, In the near future I will be making a post related to JEP 220: Modular Run-Time Images, please let your comments and enjoy!!!

Previous Post: 

JDK 9 Module System Jigsaw 1 from N

The Images presented in this post are property of his respective owners.

Revolutionizing Stream Pipelines with Custom Intermediate Operations JEP 473: Stream Gatherers (Second Preview)

Introduction In the ever-evolving scene of Java improvement, the Stream API has been a foundation of utilitarian programming paradigms sin...