Imperative And Declarative Styles Of Programming

ggorantala

Gopi Gorantala

Posted on March 1, 2022

Imperative And Declarative Styles Of Programming

Imperative Programming

Here are some facts about the imperative style of programming.

Object-Oriented programming is an imperative style of programming.

It focuses on how to do things. For example, in imperative programming, we sort of do the following steps to run a use-case. For example:

  1. Set the counter to 0, run a loop of the first 100 values and add each number to the counter.

  2. Set data equal to 0, add the first number in the array to data and repeat this for the rest of the numbers in the array and divide data by the length of the array.

Here, we treat values as buckets. So the value can be modified in the application at any time. Embraces object mutability.

Variables declared hold some value and change at some point in the program. Think of POJO class variables with setters.
Modification of variable value is allowed.

Think of loops where we iterate through each value and before processing each item, we update the garbage variable we initialized in the loop.

Step-by-step instructions on how to achieve an objective.

Example 01: List of objects

In the imperative approach, we make use of the loops. The following example contains an algorithm that makes this happen.

Book POJO with constructor, getters, and setters.

class Book {
  String title;
  String author;
  Integer year;
  Integer copiesSoldInMillions;
  Double rating;
  Double costInEuros;

  public Book(String title, String author, Integer year, Integer copiesSoldInMillions, Double rating, Double costInEuros) {
    this.title = title;
    this.author = author;
    this.year = year;
    this.copiesSoldInMillions = copiesSoldInMillions;
    this.rating = rating;
    this.costInEuros = costInEuros;
  }

  public Double getCostInEuros() {
    return costInEuros;
  }

  @Override
  public String toString() {
    return "Book{" +
      "title='" + title + '\'' +
      ", author='" + author + '\'' +
      ", year=" + year +
      ", copiesSoldInMillions=" + copiesSoldInMillions +
      ", rating=" + rating +
      ", costInEuros=" + costInEuros +
      '}';
  }
}
Enter fullscreen mode Exit fullscreen mode

BookDatabase for dummy data injection.

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

public class BookDatabase {
  public static List<Book> getAllBooks() {
    return 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)
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Here is our BookApplication class that does the imperative programming or mutations on book variable inside for-loop.

import java.util.ArrayList;
import java.util.List;

public class BookApplication {
  public static void main(String[] args) {
    List<Book> books = BookDatabase.getAllBooks();
    List<Book> imperativeWay = new ArrayList<>();

    for (Book book : books) {
      if (book.getCostInEuros() >= 5) {
        imperativeWay.add(book);
      }
    }

    imperativeWay.forEach(System.out::println);
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  1. We have a list of books data.

  2. We then used a for-loop to iterate through all the book objects.

  3. Inside for-loop, we are constantly changing the book variable data and further checking the if check to add the filtered data into another list.

  4. So we are mutating, which means we are changing the book variable that’s holding a value from one state to another.

  5. We are printing the filtered data using a loop.

Example 02: Unique Integers

Another simple example is that removes duplicates from the list of input integers. This example is to make you understand how imperative programming is actually done.

Example 01, is how we do in real-time on production grade applications.

Sample code

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

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

    List<Integer> uniqueList = new ArrayList<>();

    // "integer" variable is changed/updated for each iteration.
    for (Integer integer : integerList) {
      if (!uniqueList.contains(integer)) {
        uniqueList.add(integer);
      }
    }
    System.out.println("Unique list : " + uniqueList);
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  1. We have a list of integer values.

  2. We then used a for-loop to iterate through all the list values.

  3. Inside for-loop, we are constantly changing the integer variable data and further checking the if check to add the unique data into another list.

  4. So we are mutating, which means we are changing the integer variable that’s holding a value from one state to another.

  5. We are loading all the unique values into another list, and printing them at the last.


Declarative Programming

Here are some facts about the declarative style of programming.

Functional programming is a declarative style of programming. It puts more focus on what things are, for example:

  1. Set the counter as the sum of all numbers from 0 to 100.

  2. data is the sum of all the numbers in the array. divided by the length of the array.

In functional programming, we don’t assign values as we do in imperative. Embraces object immutability. Think of variables as constants declared with final, just so you can get an idea of what we are discussing here. Modifying a value is not allowed.

This is analogous to SQL(Structured Query language). Use of functions that are already part of the library to achieve an objective.

With Streams API, we move from imperative to declarative programming.

Example 01: List of objects

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

The following example contains an algorithm that makes this happen.

Book POJO with constructor, getters, and setters.

class Book {
  String title;
  String author;
  Integer year;
  Integer copiesSoldInMillions;
  Double rating;
  Double costInEuros;

  public Book(String title, String author, Integer year, Integer copiesSoldInMillions, Double rating, Double costInEuros) {
    this.title = title;
    this.author = author;
    this.year = year;
    this.copiesSoldInMillions = copiesSoldInMillions;
    this.rating = rating;
    this.costInEuros = costInEuros;
  }

  public Double getCostInEuros() {
    return costInEuros;
  }

  @Override
  public String toString() {
    return "Book{" +
      "title='" + title + '\'' +
      ", author='" + author + '\'' +
      ", year=" + year +
      ", copiesSoldInMillions=" + copiesSoldInMillions +
      ", rating=" + rating +
      ", costInEuros=" + costInEuros +
      '}';
  }
}
Enter fullscreen mode Exit fullscreen mode

BookDatabase for dummy data injection.

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

public class BookDatabase {
  public static List<Book> getAllBooks() {
    return 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)
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Here is our BookApplication class that does the declarative programming or immutability on each book object.

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

public class BookApplication {
  public static void main(String[] args) {
    List<Book> books = BookDatabase.getAllBooks();

    List<Book> declarativeWay =
      books.stream()
        .filter(book -> book.getCostInEuros() >= 5)
        .collect(Collectors.toList());

    declarativeWay.forEach(System.out::println);
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

In the above, we have a list of the books and we are running some chain of methods on it like a filter, map, etc. This chain of method calls is called a Stream Pipeline.

This is called functional programming as we are passing functions to the operations in the form of lambda expressions and method references.

Let us see what’s happening in each line

  1. We are first filtering the books whose cost is greater than or equal to 5 using a lambda expression .filter(book -> book.getCostInEuros() >= 5).

  2. We now have a list of books whose close is above 5 euros. We chain this to another method .collect(...) which converts the stream data into a list using Collections.toList() and return the list and store it in declarativeApproach reference variable.

  3. We print it by calling .forEach(...) on the reference variable.

Example 02: Unique Integers

Another simple example is that removes duplicates from the list of input integers. This example is to make you understand how imperative programming is actually done.

Example 01, is how we do in real-time on production grade applications.

Sample Code

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

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

    List<Integer> uniqueList =
      integerList.stream()
        .distinct()
        .collect(Collectors.toList());

    System.out.println("Unique list1 : " + uniqueList);
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  1. We have a list of integer values.

  2. We then added .stream(), so the collections of integer values get converted into streams of integer values.

  3. we chained it with another function called distinct() that removes the duplicate elements from the list.

  4. Once we go through all the filtered data, we need to terminate the stream and we are doing it with .collect(...).

  5. The .collect(...) has Collections.toList() which converts the stream data into a list and the results are loaded into integerList1 variable.

Read More

  1. Introduction To Java Streams API

  2. How Does Streams API Work? A Deep Dive on Stream Operation Flow

  3. What Are Java Method References And Kinds Of Method References Available?

  4. Functional Programming And Programming Paradigms in Java

💖 💪 🙅 🚩
ggorantala
Gopi Gorantala

Posted on March 1, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related