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
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
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

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

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
  • How to Merge HTML Documents in Java

Trending

  • How to Submit a Post to DZone
  • Using Python Libraries in Java
  • Tired of Spring Overhead? Try Dropwizard for Your Next Java Microservice
  • Enforcing Architecture With ArchUnit in Java
  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.

By 
Paweł Szeliga user avatar
Paweł Szeliga
·
Jul. 24, 17 · Tutorial
Likes (27)
Comment
Save
Tweet
Share
14.9K 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
  • How to Merge HTML Documents in Java

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • 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:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!