DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
View Events Video Library
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Integrating PostgreSQL Databases with ANF: Join this workshop to learn how to create a PostgreSQL server using Instaclustr’s managed service

Mobile Database Essentials: Assess data needs, storage requirements, and more when leveraging databases for cloud and edge applications.

Monitoring and Observability for LLMs: Datadog and Google Cloud discuss how to achieve optimal AI model performance.

Automated Testing: The latest on architecture, TDD, and the benefits of AI and low-code tools.

Related

  • What Is Applicative? Basic Theory for Java Developers
  • What Is a Functor? Basic Theory for Java Developers
  • What Is a Monad? Basic Theory for a Java Developer
  • Leveraging Weka Library for Facebook Data Analysis

Trending

  • Securing Your Applications With Spring Security
  • Performance Optimization Strategies in Highly Scalable Systems
  • Implementing Stronger RBAC and Multitenancy in Kubernetes Using Istio
  • Build Quicker With Zipper: Building a Ping Pong Ranking App Using TypeScript Functions
  1. DZone
  2. Coding
  3. Java
  4. Lifting Functions to Work With Java Monads

Lifting Functions to Work With Java Monads

Want to take a more functional approach to Java? The language doesn't offer a lot of options, but here is some custom code you can use for method lifting.

Paweł Szeliga user avatar by
Paweł Szeliga
·
Jul. 24, 17 · Tutorial
Like (27)
Save
Tweet
Share
13.95K Views

Join the DZone community and get the full member experience.

Join For Free

Stream and Optional classes, added to Java 8, allow you to have some fun with functional programming. The problem is that Java is still missing quite a lot to be taken seriously as a functional programming language. Lambda notation and two monads (Optional and Stream) are just the tip of the iceberg. This leads to libraries like vavr or functionaljava — both deriving from the purely functional language Haskell.

One of the first things you need to get rid of when trying to be more functional is the attempt to unwrap monads too early. It usually involves using methods like Optional.get() or Stream.collect() where there is no need yet. Sometimes, though, Java doesn't help with that, so let me give you some custom code. This article will bring you closer to the concept of method lifting.

Calculations on Optionals

Suppose we have a nice API we would like to use to calculate numbers:

public interface Math {
    int multiply(int a, int b);
    double divide(int a, int b);
    ..
}


We would like to use it to do some calculations on numbers wrapped with Optional:

public interface NumberProvider {
    Optional<Integer> getNumber();
}


Let's say we want to write a method, which returns the result of the division of two numbers wrapped with Optional, or empty Optional if any one of them is empty (we skip the zero divisor case here). It may look something like this:

public Optional<Double> divideFirstTwo(NumberProvider numberProvider, Math math) {
    Optional<Integer> first = numberProvider.getNumber();
    Optional<Integer> second = numberProvider.getNumber();
    if(first.isPresent() && second.isPresent()) {
        double result = math.divide(first.get(), second.get());
        return Optional.of(result);
    } else {
        return Optional.empty();
    }
}


That's rather nasty. It involves a lot of code, the only purpose of which is to wrap/unwrap the Optional. Let's try to make it more functional:

public Optional<Double> divideFirstTwo(NumberProvider numberProvider, Math math) {
    return numberProvider.getNumber()
           .flatMap(first -> numberProvider.getNumber()
                                     .map(second -> math.divide(first, second)));
}


That's much better. It turns out that invoking flatMap on the first monad and map on the second one inside the lambda can be extracted even further to the method-called lift:

public interface Optionals {

    static <R, T, Z> BiFunction<Optional<T>, Optional<R>, Optional<Z>> lift(BiFunction<? super T, ? super R, ? extends Z> function) {
        return (left, right) -> left.flatMap(leftVal -> right.map(rightVal -> function.apply(leftVal, rightVal)));
    }
}


The lift is able to promote any function, which takes two arguments, to the function with the arguments and the result type wrapped with Optional. It actually adds Optional behavior to the function in such a way that if one of the arguments is empty, then the result will also be empty. If the JDK extracted flatMap and map methods to some common interface, for example, Monad, then we could write one lift function for every instance of a Java monad (Stream, Optional, custom classes). Unfortunately, we need to do this copy-pasting for every instance. The final code for divideFirstTwo becomes:

import static com.ps.functional.monad.optional.Optionals.lift;
...

    public Optional<Double> divideFirstTwo(NumberProvider numberProvider, Math math) {
        return lift(math::divide).apply(numberProvider.getNumber(), numberProvider.getNumber());
    }


Summary

I hope this article encouraged you to play with functional style in Java. The JDK needs to be greatly improved for the language to be called functional in the future. Unfortunately, Java 9 doesn't promise any major improvements besides a few additional methods. The source code can be found here.

Java (programming language) Monad (functional programming)

Published at DZone with permission of Paweł Szeliga. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • What Is Applicative? Basic Theory for Java Developers
  • What Is a Functor? Basic Theory for Java Developers
  • What Is a Monad? Basic Theory for a Java Developer
  • Leveraging Weka Library for Facebook Data Analysis

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: