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

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

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

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Designing a Java Connector for Software Integrations
  • How to Convert XLS to XLSX in Java
  • Recurrent Workflows With Cloud Native Dapr Jobs
  • Java Virtual Threads and Scaling

Trending

  • The Human Side of Logs: What Unstructured Data Is Trying to Tell You
  • Automating Data Pipelines: Generating PySpark and SQL Jobs With LLMs in Cloudera
  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • 5 Subtle Indicators Your Development Environment Is Under Siege
  1. DZone
  2. Coding
  3. Java
  4. Java Lambda Expressions: Functions as First-Class Citizens

Java Lambda Expressions: Functions as First-Class Citizens

Whether you're migrating to Java 8 or just want a refresher, here's an excellent primer of lambda expressions and how they help bridge OOP and FP in Java.

By 
Yogen Rai user avatar
Yogen Rai
·
Jun. 20, 18 · Tutorial
Likes (18)
Comment
Save
Tweet
Share
22.2K Views

Join the DZone community and get the full member experience.

Join For Free

Since Java 8, a lot of boilerplate code can be replaced with lambda expressions in our codebase. I really want to put out an article about Streams in Java, but since that carries real value only if we combine them with lambda expressions, I want to write about some ideas about playing around with lambda expressions first.

Functional Interfaces in Java

A functional interface is an interface with a single abstract method, also known as SAM (Single Abstract Method) types. The concept was introduced in JDK 8, but there were interfaces prior to JDK 8 that complied with that definition. For example, Comparator has only one method: compare().

We can create our own as:

@FunctionalInterface
interface Calculator<T,R> {
    R calculate(T a, T b);
}


Here, the @FunctionalInterface annotation is checked by the compiler. So, if the interface does not contain exactly one abstract method, there is a compiler error.

It is not necessary to use this annotation when providing a type for a lambda expression, but, like other annotations (@Override, for example), it is a best practice to use it because it tells the compiler to check that it would work — otherwise, it will be overlooked until runtime.

Now, What Is a Lambda Expression?

A lambda expression is an inline implementation of a functional interface, eliminating the need of an anonymous class.

A lambda expression has three parts:

parameters [zero or more]
    ->
code block [if more than one statement, enclosed in curly braces { . . . } ] 
           [may contain free variables; values for these supplied by local or instance vbles]


For example:

(a,b) -> a + b; // given two numbers a and b, return another number with their summation.

(String str) -> System.out.println(str); // prints the given string into console


The equivalent of the first lambda expression is:

new Calculator<Integer, Integer>() {    
    @Override    
    public Integer calculate(Integer a, Integer b) {        
        return a + b;    
    }
};


You can see how lambda expressions help to get rid of the boilerplate code.

Naming Lambda Expressions

Every object in Java has a type; the same is true of lambda expressions. The type of a lambda expression is any functional interface for which the lambda expression is an implementation.

Naming a lambda expression is done by using an appropriate functional interface as its type, like naming any other object. For example:

Calculator<Integer, Integer> adder = (a,b) -> a + b;


The name of this lambda expression is adder of type Calculator.

Note: I am omitting the parameter type because if parameter types can be inferred, they can be omitted. So, the above expression with the parameter type would be:

Calculator<Integer, Integer> adder = (Integer a,Integer b) -> a + b;


Using Lambda Expressions

You've seen how inner class approximations can be replaced by lambda expressions, which capture their essential functional nature: Arguments mapped to outputs. Hence, the functions are now first-class citizens. So:

1. A lambda expression can be used as a regular class object to call the method. For example, adder can be used to call the calculate method as:

Integer sum = adder.calculate(3,4); // sum = 7


2. Lambda expressions can be passed as an argument and used to evaluate expressions as:

// ...
printSum(adder);
// ...

static void printSum(Calculator cal) {
    System.out.println(cal.calculate(4,5));
}


3. Lambda expressions can be returned as a return object:

// ...
Calculator<Integer, Integer> multiplier = getCalculatorFunc();
Integer result = multiplier.calculate(6,9));  // 54
// ...
static Calculator getCalculatorFunc() {
    Calculator<Integer, Integer> multiplier = (a, b) -> a * b;
    return multiplier;
}


Conclusion

Now, you can see how it is possible to reap many of the benefits of Functional Programming while maintaining the OO essence of the Java language as a whole. Lambda expressions are the fundamentals for functional programming and writing code concisely with Streams, which I want to continue in the next post. Until then, happy coding!

The source code for the examples presented above is available on GitHub.

Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • Designing a Java Connector for Software Integrations
  • How to Convert XLS to XLSX in Java
  • Recurrent Workflows With Cloud Native Dapr Jobs
  • Java Virtual Threads and Scaling

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!