Explore 1.5M+ audiobooks & ebooks free for days

Only $12.99 CAD/month after trial. Cancel anytime.

Functional Programming with Java: An In-Depth Exploration and Implementation Guide
Functional Programming with Java: An In-Depth Exploration and Implementation Guide
Functional Programming with Java: An In-Depth Exploration and Implementation Guide
Ebook1,258 pages3 hours

Functional Programming with Java: An In-Depth Exploration and Implementation Guide

Rating: 0 out of 5 stars

()

Read preview

About this ebook

"Functional Programming with Java: An In-Depth Exploration and Implementation Guide" is the essential resource for Java developers aiming to elevate their programming acumen and bring their code into the forefront of modern software practices. This meticulously crafted guide provides a comprehensive examination of functional programming principles as they apply to Java, covering foundational elements like lambda expressions and the Stream API, as well as delving into complex topics such as concurrency management and modular design using Java Modules.

Each carefully structured chapter combines theoretical insights with practical examples and exercises, ensuring a robust understanding of concepts. Whether you are new to functional programming or a seasoned Java developer seeking to integrate contemporary methodologies, this book equips you with the knowledge and tools necessary to create more efficient, concise, and resilient Java applications. Through a thorough exploration of functional interfaces, Optional, and collectors, among others, readers will learn to harness the full potential of functional programming within the Java ecosystem.

Embark on a transformative journey with this indispensable guide, and revolutionize your software development approach by mastering functional programming with Java.

LanguageEnglish
PublisherWalzone Press
Release dateJan 5, 2025
ISBN9798230284673
Functional Programming with Java: An In-Depth Exploration and Implementation Guide

Read more from Adam Jones

Related to Functional Programming with Java

Related ebooks

Computers For You

View More

Reviews for Functional Programming with Java

Rating: 0 out of 5 stars
0 ratings

0 ratings0 reviews

What did you think?

Tap to rate

Review must be at least 10 words

    Book preview

    Functional Programming with Java - Adam Jones

    Functional Programming with Java

    An In-Depth Exploration and Implementation Guide

    Copyright © 2024 by NOB TREX L.L.C.

    All rights reserved. No part of this publication may be reproduced, distributed, or transmitted in any form or by any means, including photocopying, recording, or other electronic or mechanical methods, without the prior written permission of the publisher, except in the case of brief quotations embodied in critical reviews and certain other noncommercial uses permitted by copyright law.

    Contents

    1 Introduction to Functional Programming in Java

    1.1 The Evolution of Java: From OOP to Functional Programming

    1.2 Core Concepts of Functional Programming

    1.3 The Impact of Lambdas and Streams: A Paradigm Shift

    1.4 Functional vs. Imperative Programming: A Comparative Analysis

    1.5 Immutable Data Structures and Their Importance

    1.6 First-Class and Higher-Order Functions Explained

    1.7 Pure Functions and Side Effects: Understanding the Basics

    1.8 Recursion in Functional Programming

    1.9 Advantages of Functional Programming in Java

    1.10 Challenges and Considerations in Adopting Functional Programming

    1.11 Functional Programming Terminology: A Glossary

    2 Understanding Lambda Expressions

    2.1 Introduction to Lambda Expressions: A New Era in Java

    2.2 Syntax of Lambda Expressions: Breaking it Down

    2.3 Functional Interfaces: The Foundation of Lambda Expressions

    2.4 Using Lambda Expressions: Practical Examples

    2.5 Variables in Lambda Expressions: Capture and Shadowing

    2.6 Method References: A Shortcut for Lambda Expressions

    2.7 Built-In Functional Interfaces in Java.util.function

    2.8 Chaining Lambda Expressions: Higher Complexity Operations

    2.9 Lambda Expressions and Collections: A Harmonious Union

    2.10 Performance Considerations with Lambda Expressions

    2.11 Debugging Lambda Expressions: Tips and Tricks

    3 Stream API: Your Gateway to Functional Programming

    3.1 Stream API Overview: The Basics

    3.2 Creating Streams from Various Data Sources

    3.3 Intermediate Operations: Transforming Streams

    3.4 Terminal Operations: Consuming Streams

    3.5 Stream Specializations: IntStream, LongStream, and DoubleStream

    3.6 Using Collectors for Data Aggregation

    3.7 Short-circuiting Operations: Efficiency in Computation

    3.8 Parallel Streams: Leveraging Multicore Processors

    3.9 Optional Class and Stream API: A Perfect Match

    3.10 Common Pitfalls and Best Practices in Using Stream API

    3.11 Stream API vs. Traditional Iteration: A Performance Analysis

    3.12 Advanced Stream API Techniques

    4 Functional Interfaces in Depth

    4.1 Understanding Functional Interfaces: An Overview

    4.2 The @FunctionalInterface Annotation: Significance and Usage

    4.3 The Predicate Interface: Filtering with Logic

    4.4 The Function Interface: Applying Functions to Data

    4.5 The Consumer Interface: The Side-Effects Producer

    4.6 The Supplier Interface: Data Generation on Demand

    4.7 Specialized Variants of Functional Interfaces

    4.8 Bi-Functional Interfaces: Operating on Two Variables

    4.9 Creating Custom Functional Interfaces

    4.10 Common Use Cases for Functional Interfaces

    4.11 Combining and Composing with Functional Interfaces

    4.12 Best Practices and Pitfalls in Using Functional Interfaces

    5 Optional: Embracing Null Safety

    5.1 Introduction to the Optional Class: Null Safety in Java

    5.2 Creating Optional Objects: Empty, Of, and OfNullable

    5.3 Retrieving and Checking Values within Optional Objects

    5.4 Optional Methods: ifPresent, orElse, and orElseGet

    5.5 Mapping and Filtering with Optional

    5.6 Optional in Stream Operations

    5.7 The flatMap Method in Optional: For Nested Optionals

    5.8 Optional Best Practices: When and How to Use

    5.9 Common Pitfalls in Using Optional

    5.10 Optional and Patterns: Design Considerations

    5.11 Comparing Optional to Traditional Null Checks

    5.12 Optional in APIs: Dos and Don’ts

    6 Collectors: Beyond Basic Data Aggregation

    6.1 Introduction to Collectors and Data Aggregation

    6.2 Predefined Collectors: toList, toSet, toMap

    6.3 Grouping and Partitioning Data with Collectors

    6.4 Custom Collector Implementation: A Step-by-Step Guide

    6.5 Collectors for Joining Strings: Making Text Processing Easier

    6.6 Statistics with Collectors: Summarizing Data

    6.7 Combining Collectors: Nested Grouping and Mapping

    6.8 Collectors in Parallel Streams

    6.9 Performance Considerations when Using Collectors

    6.10 Best Practices for Effective Data Aggregation

    6.11 Use Cases and Patterns for Advanced Data Aggregation

    6.12 Beyond Collectors: Extending Capabilities with Reduction

    7 Patterns and Practices in Functional Programming

    7.1 Introduction to Functional Programming Patterns

    7.2 The Singleton Pattern in a Functional Style

    7.3 Functional Factory: Modular and Reusable Code

    7.4 The Strategy Pattern: Behavior Parameterization

    7.5 The Observer Pattern with Lambdas and Functional Interfaces

    7.6 The Command Pattern: Actions as First-Class Citizens

    7.7 Builder Pattern: Fluent Interfaces in Functional Java

    7.8 The Decorator Pattern: Enhancing Objects Functionally

    7.9 Using Memoization for Efficiency in Functional Programming

    7.10 Functional Programming and Immutable Data Patterns

    7.11 Concurrency Patterns: Safe and Scalable Solutions

    7.12 Refactoring for Functional Programming: Best Practices

    8 Concurrency in Java with Functional Programming

    8.1 Concurrency in Java: An Introduction

    8.2 Functional Programming and Thread Safety

    8.3 Creating Asynchronous Applications with CompletableFuture

    8.4 Leveraging Parallel Streams for Data Processing

    8.5 Functional Interfaces in Concurrent Environments

    8.6 Synchronization and Coordination Techniques

    8.7 Reactive Programming with Java: A Functional Approach

    8.8 Handling Errors in Asynchronous and Parallel Streams

    8.9 Testing Concurrency: Strategies and Best Practices

    8.10 Optimizing Performance for Concurrent Functional Programs

    8.11 Design Patterns for Concurrency: Applying Functional Principles

    8.12 Challenges and Pitfalls in Concurrency with Functional Java

    9 Functional Programming with Java Modules

    9.1 Overview of Java Modules

    9.2 Setting Up a Modular Project in Java

    9.3 Defining Modules for Functional Programming

    9.4 Exporting and Requiring Functional Interfaces

    9.5 Sharing Functional Libraries Across Modules

    9.6 Best Practices for Organizing Modules in Large Projects

    9.7 Modularization Strategies for Legacy Projects

    9.8 Access Control and Encapsulation in Java Modules

    9.9 Interoperability Between Modules: Challenges and Solutions

    9.10 Dynamic Module Loading and Unloading

    9.11 Performance Considerations in Modular Java Applications

    9.12 Case Studies: Real-World Applications of Modular Functional Programming

    10 Testing Functional Java Code

    10.1 Introduction to Testing Functional Java Code

    10.2 The Importance of Testing in Functional Programming

    10.3 Unit Testing Functional Interfaces and Lambda Expressions

    10.4 Mocking and Stubbing in Functional Tests

    10.5 Testing Stream Operations and Data Transformations

    10.6 Integration Testing with Functional Java Code

    10.7 Property-based Testing for Functional Java

    10.8 Testing Asynchronous and Parallel Streams

    10.9 Leveraging Test Frameworks for Functional Java

    10.10 Best Practices for Test Coverage and Test Design

    10.11 Debugging Functional Java Code

    10.12 Performance Testing in Functional Java Applications

    Preface

    With the groundbreaking introduction of functional programming features in Java 8, particularly the advent of lambda expressions and the Stream API, the landscape for Java developers has evolved dramatically. This shift from the traditional imperative style to a more functional paradigm presents a profound opportunity for developers to enhance the readability, maintainability, and scalability of their applications. Recognizing the significance of this transformation, Functional Programming with Java: An In-Depth Exploration and Implementation Guide is crafted to be the definitive resource for mastering functional programming in Java.

    The essence of this book lies in its ability to deconstruct complex functional programming concepts and reconstruct them in the context of Java, offering a detailed exploration into how these modern practices can be seamlessly integrated into your existing Java skill set. Starting with foundational elements such as lambda expressions and functional interfaces, the book comprehensively navigates through the subtleties of the Stream API, culminating in advanced topics like reactive programming and functional design patterns that illustrate the power and elegance of functional constructs.

    Designed for a diverse audience, this book is an invaluable asset for novice programmers and seasoned professionals alike. It endeavors to bridge the knowledge gap for beginners, familiarizing them with functional programming’s core principles and their direct applications in Java. For the experienced Java developers, the book delves into more sophisticated territories such as parallel stream processing, higher-order functions, and lazy evaluation, arming them with advanced strategies and techniques to optimize their code.

    Each chapter presents a blend of theory and practice — offering conceptual explanations that are immediately followed by practical examples and well-thought-out exercises. This approach not only solidifies the reader’s comprehension but also ensures they gain hands-on experience in applying what they learn. Additionally, the book anticipates the evolving nature of the Java platform, providing insights into how forthcoming updates may further support functional paradigms, and preparing developers for future advancements.

    In essence, this book aspires to serve as both an educational compendium and a practical reference guide. It empowers Java developers to innovate in their programming endeavors, embracing functional programming’s richness to achieve new levels of code efficiency, clarity, and sophistication. By engaging thoroughly with this book, readers will unlock a new dimension of Java programming, harnessing the full potential of functional programming to craft sophisticated, high-performance Java applications.

    Chapter 1

    Introduction to Functional Programming in Java

    Functional programming has emerged as a powerful paradigm in Java, offering a different approach to solving problems compared to traditional object-oriented programming. With the introduction of lambda expressions in Java 8, the language opened the door to more concise code, immutability, and higher-order functions, embodying the principles of functional programming. This chapter lays the foundation for understanding how functional programming influences Java development, discussing its core concepts, benefits, and the shift it represents from imperative coding styles. Through this exploration, developers will gain insight into the significance of functional programming within the Java ecosystem and how it can be leveraged to create more efficient, readable, and scalable applications.

    1.1

    The Evolution of Java: From OOP to Functional Programming

    Java, since its inception, has been quintessentially tied to the paradigm of Object-Oriented Programming (OOP). This model, focusing on encapsulating state and behavior inside objects and leveraging inheritance and polymorphism, has dominated software development for decades. The evolution of Java, however, illustrates the language’s gradual embrace of Functional Programming (FP), a paradigm shift that reflects broader industry trends towards more concise, flexible, and expressive codebases.

    The journey towards functional programming in Java began earnestly with the introduction of anonymous inner classes. While not purely functional in nature, these constructs allowed developers to encapsulate behavior in a manner that hinted at the expressiveness and conciseness functional programming is known for. However, anonymous inner classes were verbose and often cumbersome to use, limiting their appeal.

    The transformative moment for Java came with the release of Java 8 in 2014, which introduced lambda expressions and the Stream API. Lambda expressions, or lambdas, allow for the clear and concise creation of anonymous functions, providing a syntax that is more readable and less verbose than anonymous inner classes. These functions can be passed around as objects, enabling Java to support higher-order functions – a core concept in functional programming.

    Consider the following example that illustrates the use of a lambda expression to create a simple function that adds two numbers:

    1

    BinaryOperator

    <

    Integer

    >

     

    add

     

    =

     

    (

    a

    ,

     

    b

    )

     

    ->

     

    a

     

    +

     

    b

    ;

     

    2

    System

    .

    out

    .

    println

    (

    add

    .

    apply

    (10,

     

    20)

    )

    ;

     

    //

     

    Output

    :

     

    30

    This introduction of lambdas provided a foundation for functional programming in Java, but it was the introduction of the Stream API that fully unlocked the paradigm’s potential. The Stream API allows for operations on a sequence of elements in a declarative manner, closely aligning with functional programming principles. For example, one could easily filter and map a collection of numbers as follows:

    1

    List

    <

    Integer

    >

     

    numbers

     

    =

     

    Arrays

    .

    asList

    (1,

     

    2,

     

    3,

     

    4,

     

    5)

    ;

     

    2

    List

    <

    Integer

    >

     

    squaredNumbers

     

    =

     

    numbers

    .

    stream

    ()

     

    3

       

    .

    map

    (

    n

     

    ->

     

    n

     

    *

     

    n

    )

     

    4

       

    .

    collect

    (

    Collectors

    .

    toList

    ()

    )

    ;

     

    5

    squaredNumbers

    .

    forEach

    (

    System

    .

    out

    ::

    println

    )

    ;

    Through the Stream API, Java developers can leverage a more functional style of programming, making code more concise, more readable, and often more expressive.

    Furthermore, the release of Java 8 also heralded the introduction of Optional, a container type that represents the presence or absence of a value, reducing the likelihood of null pointer exceptions and encouraging developers to think in terms of explicit value presence checks. This feature, while not functional in the traditional sense, encourages a more functional approach to error handling and value manipulation.

    The evolution of Java demonstrates the language’s significant strides towards embracing functional programming, driven by the need for more concise, readable, and expressive code. The introduction of lambda expressions and the Stream API in Java 8 was a landmark step, marking Java’s transition from a purely object-oriented language to one that supports functional programming principles. As developers seek to write more efficient and scalable applications, the functional programming capabilities of Java continue to expand, solidifying its role in modern software development.

    1.2

    Core Concepts of Functional Programming

    Functional programming is an approach to software development that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It is a declarative programming paradigm, contrasting with imperative programming, which focuses on how to perform tasks. This section delves into the essential concepts that underpin functional programming, setting the foundation for its application in Java.

    First-Class Functions

    One of the core principles of functional programming is the concept of first-class functions. This means that functions are treated as first-class citizens; they can be assigned to variables, passed as arguments to other functions, and returned from functions. This flexibility enables the creation of higher-order functions, which either take one or more functions as arguments or return a function.

    1

    //

     

    Example

     

    of

     

    a

     

    higher

    -

    order

     

    function

     

    in

     

    Java

     

    2

    import

     

    java

    .

    util

    .

    function

    .

    Function

    ;

     

    3

     

    4

    public

     

    class

     

    HigherOrderFunctionExample

     

    {

     

    5

       

    //

     

    Takes

     

    a

     

    function

     

    as

     

    an

     

    argument

     

    and

     

    returns

     

    a

     

    function

     

    6

       

    public

     

    static

     

    Function

    <

    Integer

    ,

     

    Integer

    >

     

    createMultiplier

    (

    int

     

    x

    )

     

    {

     

    7

          

    return

     

    (

    Integer

     

    y

    )

     

    ->

     

    x

     

    *

     

    y

    ;

     

    8

       

    }

     

    9

     

    10

       

    public

     

    static

     

    void

     

    main

    (

    String

    []

     

    args

    )

     

    {

     

    11

          

    Function

    <

    Integer

    ,

     

    Integer

    >

     

    timesTwo

     

    =

     

    createMultiplier

    (2)

    ;

     

    12

          

    System

    .

    out

    .

    println

    (

    timesTwo

    .

    apply

    (5)

    )

    ;

     

    //

     

    Output

    :

     

    10

     

    13

       

    }

     

    14

    }

    Immutable Data Structures

    Another fundamental concept in functional programming is the use of immutable data structures. Immutability means that once a data structure is created, it cannot be altered. Any modification produces a new data structure without changing the original. This characteristic is crucial for avoiding side effects and ensuring thread safety.

    Pure Functions

    Pure functions are at the heart of functional programming. A function is considered pure if it meets two criteria: first, its output depends solely on its input values, without observable side effects; second, it does not alter anything outside its local environment. Consequently, pure functions are predictable and can be easily reasoned about.

    1

    //

     

    Example

     

    of

     

    a

     

    pure

     

    function

     

    in

     

    Java

     

    2

    public

     

    class

     

    PureFunctionExample

     

    {

     

    3

       

    public

     

    static

     

    int

     

    add

    (

    int

     

    a

    ,

     

    int

     

    b

    )

     

    {

     

    4

          

    return

     

    a

     

    +

     

    b

    ;

     

    5

       

    }

     

    6

     

    7

       

    public

     

    static

     

    void

     

    main

    (

    String

    []

     

    args

    )

     

    {

     

    8

          

    System

    .

    out

    .

    println

    (

    add

    (2,3)

    )

    ;

     

    //

     

    Output

    :

     

    5

     

    9

       

    }

     

    10

    }

    Recursion

    Recursion is a common practice in functional programming, where a function calls itself to solve smaller instances of the same problem. Recursion is often used as a substitute for looping constructs, fitting the functional programming paradigm’s preference for immutability and statelessness.

    1

    //

     

    Recursive

     

    function

     

    to

     

    find

     

    the

     

    factorial

     

    of

     

    a

     

    number

     

    in

     

    Java

     

    2

    public

     

    class

     

    RecursiveExample

     

    {

     

    3

       

    public

     

    static

     

    long

     

    factorial

    (

    int

     

    n

    )

     

    {

     

    4

          

    if

     

    (

    n

     

    <=

     

    1)

     

    return

     

    1;

     

    5

          

    else

     

    return

     

    n

     

    *

     

    factorial

    (

    n

    -1)

    ;

     

    6

       

    }

     

    7

     

    8

       

    public

     

    static

     

    void

     

    main

    (

    String

    []

     

    args

    )

     

    {

     

    9

          

    System

    .

    out

    .

    println

    (

    factorial

    (5)

    )

    ;

     

    //

     

    Output

    :

     

    120

     

    10

       

    }

     

    11

    }

    Higher-Order Functions

    As mentioned, higher-order functions can take functions as parameters or return them as results. This capability is instrumental in creating adaptable and composable software, where small, simple functions are built up into more complex functions. These are extensively used in conjunction with Java’s streams and lambda expressions to enable functional-style operations on collections.

    This section has introduced the central principles underlying functional programming. By embracing these concepts, Java developers can leverage the power of functional programming to write clearer, more robust, and more concise code. As we explore further, we’ll see how these principles have been integrated into Java and how they can be applied in real-world programming tasks.

    1.3

    The Impact of Lambdas and Streams: A Paradigm Shift

    With the introduction of Java 8, significant features such as lambda expressions and the Stream API have revolutionized the way developers write code in Java, marking a paradigm shift from an imperative programming style toward a more functional approach. This shift has not only made code more concise but has also enhanced its readability and efficiency.

    Lambda Expressions

    Lambda expressions, essentially anonymous functions, allow for a clear and concise way to represent one-method interfaces using an expression. They are a cornerstone of functional programming in Java, enabling developers to write more flexible and succinct code.

    Consider the syntax of a lambda expression:

    1

    (

    parameter1

    ,

     

    parameter2

    )

     

    ->

     

    {

     

    body

     

    }

    This syntax eliminates the need for the boilerplate code that is common in anonymous class implementations. For instance, to compare two String objects by their length in a list, traditionally, one would implement a Comparator anonymously. With lambda expressions, this can be simplified as:

    1

    Collections

    .

    sort

    (

    list

    ,

     

    (

    String

     

    s1

    ,

     

    String

     

    s2

    )

     

    ->

     

    s1

    .

    length

    ()

     

    -

     

    s2

    .

    length

    ()

    )

    ;

    This example illustrates how lambda expressions make the code not only more compact but also clearer in intent.

    Stream API

    The introduction of the Stream API complements lambda expressions by providing a high-level abstraction for sequences of elements, supporting various operations to perform computations. Streams can be serial or parallel, allowing for significant flexibility and efficiency in processing large data sets.

    Key characteristics of streams include:

    No storage. A stream is not a data structure but a conduit for data.

    Functional in nature. Operations on a stream produce a result, but do not modify its source.

    Laziness-seeking. Many operations on streams are deferred until necessary.

    Consider an example where one needs to filter all even numbers from a list and compute their sum. Using the Stream API, this can be achieved succinctly as follows:

    1

    int

     

    sum

     

    =

     

    list

    .

    stream

    ()

     

    2

              

    .

    filter

    (

    n

     

    ->

     

    n

     

    %

     

    2

     

    ==

     

    0)

     

    3

              

    .

    reduce

    (0,

     

    Integer

    ::

    sum

    )

    ;

    Here, filter and reduce are stream operations. The filter operation selects even numbers, and reduce computes their sum. This code snippet is not only succinct but also easy to read and understand, showcasing the power of streams in simplifying operations on collections.

    Combining Lambdas and Streams

    The real power of functional programming in Java comes through the integration of lambda expressions with the Stream API. This combination allows for highly efficient, expressive, and concise code that can easily be parallelized.

    For example, to find the minimum element in a list of integers, one could write:

    1

    OptionalInt

     

    minElement

     

    =

     

    list

    .

    stream

    ()

     

    2

                           

    .

    mapToInt

    (

    Integer

    ::

    intValue

    )

     

    3

                           

    .

    min

    ()

    ;

    This snippet highlights how lambdas and streams can be woven together to express complex operations compactly.

    The introduction of lambda expressions and the Stream API has indeed marked a paradigm shift in Java, enabling a functional programming approach. This shift has not only made Java more expressive but has also increased its capabilities to handle modern computing tasks efficiently. Through these features, Java developers can write less boilerplate code, improve application performance, and increase code readability and maintainability.

    1.4

    Functional vs. Imperative Programming: A Comparative Analysis

    In this section, we will discuss the fundamental differences between functional and imperative programming paradigms, particularly in the context of Java development. While imperative programming has been the backbone of software development for decades, functional programming offers a distinct approach that emphasizes immutability, function purity, and the use of higher-order functions.

    Definition and Core Principles

    Imperative programming is a programming paradigm that uses statements to change a program’s state. It is characterized by the explicit sequencing of commands that modify mutable data. On the other hand, functional programming is built around the concept of mathematical functions that avoid changing state and mutable data. One of the most significant distinctions between these paradigms is how they approach the execution flow and data management.

    In imperative programming, code is executed in a sequential manner, where the state is changed through assignments and loops.

    In functional programming, computation is expressed as the evaluation of mathematical functions without side effects. This means functions are treated as first-class citizens and can be passed around and manipulated just like any other data.

    Example of Imperative vs. Functional Style

    To illustrate the contrast, consider the problem of calculating the sum of all even numbers in a list. An imperative approach in Java would typically involve initializing a sum variable, iterating over the list, checking if a number is even, and if so, adding it to the sum.

    1

    int

     

    sumEvenNumbers

    (

    List

    <

    Integer

    >

     

    numbers

    )

     

    {

     

    2

       

    int

     

    sum

     

    =

     

    0;

     

    3

       

    for

    (

    int

     

    number

     

    :

     

    numbers

    )

     

    {

     

    4

          

    if

    (

    number

     

    %

     

    2

     

    ==

     

    0)

     

    {

     

    5

             

    sum

     

    +=

     

    number

    ;

     

    6

          

    }

     

    7

       

    }

     

    8

       

    return

     

    sum

    ;

     

    9

    }

    Conversely, the functional approach leverages Java’s Stream API to describe what should be done in a declarative manner without explicitly specifying how the iteration is handled.

    1

    int

     

    sumEvenNumbers

    (

    List

    <

    Integer

    >

     

    numbers

    )

     

    {

     

    2

       

    return

     

    numbers

    .

    stream

    ()

     

    3

                 

    .

    filter

    (

    number

     

    ->

     

    number

     

    %

     

    2

     

    ==

     

    0)

     

    4

                 

    .

    reduce

    (0,

     

    Integer

    ::

    sum

    )

    ;

     

    5

    }

    Enjoying the preview?
    Page 1 of 1