Introduction to Spring Cloud Stream Kafka

David Landup
Arpendu Kumar Garai

In this chapter, we are going to understand and use Spring Cloud Stream. It is a framework built on top of the core Spring Boot and Spring Integration. It helps us build an event-driven or message-driven microservice. We will take a deep look into its various concepts and usage.

But before we start with the Spring Cloud Stream concepts, we must first understand and review our core understanding of functional programming and its components. So let's explore some of the concepts we will use in this chapter.

Concept of Few Useful Functional Interfaces

Functional Programming is a programming paradigm where the basic unit of computation is a function. These functions are treated as mathematical functions, where we map inputs to outputs to produce a result. Java 8 introduced a new syntactic improvement as lambda functions. A lambda is an anonymous function that is used as a first-class citizen.

Any interface with a Single Abstract Method is considered a functional interface. The implementation of these functional interfaces is treated as lambda expressions. The java.util.function package introduced more than 40 functional interfaces. Here, we will discuss only Function, Consumer, Supplier, Predicate, BiFunction, and BiConsumer.

  • Function - It is one of the simplest and most generic forms of functional interfaces that accepts one argument and returns a result. This kind of interface is usually used to convert or transform from one form to another.

    @FunctionalInterface
    public interface Function<T, R> {
        R apply(T t);
    }
    

    Example Usage:

    Function<Long, String> longToString = Object::toString;
    Function<String, String> stringToUC = String::toUpperCase;
    
  • Consumer - This represents functional interfaces that accept a single input argument and return no result. The final outcome is the side effect that it produces.

    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T t);
    
    }
    

    Example Usage:

    User user = new User();
    Consumer<User> updateUser = u -> u.setName("John");
    
  • Supplier - This functional interface does the exact opposite of the Consumer. It takes no arguments but returns some result or value.

    @FunctionalInterface
    public interface Supplier<T> {
        void get(T t);
    }
    

    Example Usage:

    Supplier<Double> randomDouble = () -> Math.random();
    
  • Predicate - It is a statement that can return true or false based on the value of its variables. It essentially acts as a function that returns a Boolean value.

    @FunctionalInterface
    public interface Predicate<T> {
        boolean test(T t);
    }
    

    Example Usage:

    Predicate<String> predicateCheck = x -> x.length() > 5;
    
  • BiFunction - This accepts two arguments as input and returns a result. While declaring a BiFunction, we should define the type of argument that needs to be passed and its return type. We can then apply our business logic with those two values and return the result.

    @FunctionalInterface
    public interface Function<T, U, R> {
        R apply(T t, U u);
    }
    

    Example Usage:

    BiFunction<Integer, Integer, String> biFunctionExample = (n1, n2) -> String.valueOf(n1 + n2);
    
  • BiConsumer - It accepts two parameters as arguments but returns no result.

    @FunctionalInterface
    public interface BiConsumer<T, U> {
        void accept(T t, U u);
    }
    

    Example Usage:

    BiConsumer<Integer,String> biConsumer = (key, value) -> log.info("Key:{} Value:{}", key, value);
    
Start course to continue
Lessson 10/14
You must first start the course before tracking progress.
Mark completed

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms