Skip to content

What is Declarative Programming? With Examples

In this lesson, you will learn declarative programming and the steps to achieve it. You will also be introduced to some real-world use cases for easy understanding.

Gopi Gorantala
Gopi Gorantala
3 min read

Introduction

Declarative programming is a software paradigm that doesn’t change the program state at any given instance and uses the streams and some chain of methods to achieve functional programming, otherwise called the declarative style.

In functional programming, we don’t assign values as we do in imperative. Consider variables as constants declared with final , so you can understand what we are discussing here. Changing a value is not allowed.

This style of programming is analogous to SQL(Structured Query language). With streams, we move from imperative to declarative programming.

From the above understanding, we can say declarative programming embraces object immutability.

Declarative programming is how we write code by making use of Streams API

Declarative programming focuses on what things are.

For example, in declarative programming, we do the following to run a use case.

  1. Simple counter: Set the counter , which stores the sum of all numbers from 0 to 100.
  2. An array of integers: Consider another example. Imagine a variable data that stores the sum of all the numbers in the array divided by the length of the array.

Examples

In the declarative approach, we use the streams and a chain of methods called intermediate and terminal operations.

Remove Duplicates

Removing duplicate entries from a collection is a perfect example of a declarative approach, as it deals with Streams API.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Duplicates {
  public static void main(String[] args) {
    List<Integer> values = Arrays.asList(1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8);

    List<Integer> uniqueValues =
        values // collections data
            .stream() // converting into Stream of integers
            .distinct()
            .collect(Collectors.toList()); // or you can use `.toList();`

    System.out.println("Unique list : " + uniqueValues);
  }
}

What are we doing above? let's see each of the lines we've written above in action.

List<Integer> values = Arrays.asList(1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8);

We have a list of integer values stored in List<Integer>.

List<Integer> uniqueValues =
    values // collections data
        .stream() // converting into Stream of integers
        .distinct()
        .collect(Collectors.toList());

Line 3 is chained with .stream() to convert the collection of integer values into a stream of integers.

In line 4, we chained the stream of integers with .distinct that removes duplicate elements.

Finally, on line 5, with the help of a terminal operation .collect to collect the data into to List using Collections.toList().

Are we mutating? 🤔 No, we are not mutating the data. Each value in the stream is separate and never gets changed/updated until the stream operations are finished.

List Of Objects

We dealt with variables that are holding data. The following example re-iterates the same concept but for Java objects.

This is yet another simple example containing:

  1. Book POJO class.
  2. We inflate it with hard-coded data using BookRepositiryImpl class.
  3. An execution class that contains the main method, runs the application to perform the imperative approach.

Code:

import java.util.Arrays;
import java.util.List;

public record Book(
    String title,
    String author,
    Integer year,
    Integer copiesSold,
    Double rating,
    Double costInEuros) {
  // statements
  public static List<Book> BOOKS =
      Arrays.asList(
          new Book("Don Quixote", "Miguel de Cervantes", 1605, 500, 3.9, 9.99),
          new Book("A Tale of Two Cities", "Charles Dickens", 1859, 200, 3.9, 10.0),
          new Book("The Lord of the Rings", "J.R.R. Tolkien", 2001, 150, 4.0, 12.50),
          new Book("The Little Prince", "Antoine de Saint-Exupery", 2016, 142, 4.4, 5.0),
          new Book("The Dream of the Red Chamber", "Cao Xueqin", 1791, 100, 4.2, 10.0));
}
import java.util.List;
import src.dev.ggorantala.model.Book;

public class ListObjects {
  public static void main(String[] args) {
    List<Book> declarativeApproach =
        Book.BOOKS.stream()
            .filter(book -> book.costInEuros() >= 5)
            // .collect(Collectors.toList());
            .toList();

    declarativeApproach.forEach(System.out::println);
  }
}

/*
Outputs:
Book[title=Don Quixote, author=Miguel de Cervantes, year=1605, copiesSold=500, rating=3.9, costInEuros=9.99]
Book[title=A Tale of Two Cities, author=Charles Dickens, year=1859, copiesSold=200, rating=3.9, costInEuros=10.0]
Book[title=The Lord of the Rings, author=J.R.R. Tolkien, year=2001, copiesSold=150, rating=4.0, costInEuros=12.5]
Book[title=The Little Prince, author=Antoine de Saint-Exupery, year=2016, copiesSold=142, rating=4.4, costInEuros=5.0]
Book[title=The Dream of the Red Chamber, author=Cao Xueqin, year=1791, copiesSold=100, rating=4.2, costInEuros=10.0]
*/

In the above execution class, we have a list of Book objects stored in List<Book>.

List<Book> declarativeApproach =
    books // collection of books
        .stream() // stream of Book objects
        .filter(book -> book.getCostInEuros() >= 5)
        .collect(Collectors.toList());

We have a collection of Book objects in line 2.

Line 3, we converted the collections of books into a stream of book objects by chaining with .stream().

Line 4, we chained the stream of books with .filter() that takes a Predicate, a condition to filter books book -> book.getCostInEuros() >= 5.

Finally, on line 5, with the help of a terminal operation .collect to collect the data into to List using Collections.toList().

The same problem as above, We are not mutating Book objects, instead each Book in the stream is separate and never gets changed/updated.

Java Streams APIJava

Gopi Gorantala Twitter

Gopi is an engineering leader with 12+ of experience in full-stack development—a specialist in Java technology stack. He worked for multiple startups, the European govt, and FAANG in India and Europe.

Comments


Related Posts

Members Public

Differences Between JDK, JRE, and JVM?

Short answer JDK, JRE, and JVM are essential components of the Java platform, each serving a distinct purpose. Here are the key differences between them: 1. JDK (Java Development Kit): The JDK is used by developers to write, compile, and debug Java code. 2. JRE (Java Runtime Environment): End-users use

Members Public

Difference Between String and char[] in Java

Short answer Strings String is an object with many helpful methods. String class in Java's standard library is designed to handle text as a sequence of characters. A string of characters (string object) is non-modifiable or immutable in Java. Once you've created it, you cannot modify

Members Public

What is an Object class in Java?

Short answer Object class is the super class of every class you can create. In Java, a class extends another class using the keyword extends. If you don't have any other class to extend, that's fine. The compiler will make your class extend the Object class.