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:
Set the
counter
to0
, run a loop of the first100
values, and add each number to thecounter
.Set
data
equal to0
, add the first number in the array todata
and repeat this for the rest of the numbers in the array and dividedata
by thelength
of thearray
.
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.
Code
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 +
'}';
}
}
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)
);
}
}
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);
}
}
Explanation
We have a list of books data.
We then used a for-loop to iterate through all the book objects.
Inside for-loop, we are constantly changing the
book
variable data and further checking theif
check to add the filtered data into another list.So we are mutating, which means we are changing the
book
variable that’s holding a value from one state to another.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.
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);
}
}
Explanation
We have a list of integer values.
We then used a for-loop to iterate through all the list values.
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.So we are mutating, which means we are changing the
integer
variable that’s holding a value from one state to another.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:
Set the counter as the sum of all numbers from 0 to 100.
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.
Code
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 +
'}';
}
}
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)
);
}
}
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);
}
}
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
We are first filtering the
books
whose cost is greater than or equal to5
using a lambda expression.filter(book -> book.getCostInEuros() >= 5)
.We now have a
list
of books whose close is above5
euros. We chain this to another method.collect(...)
which converts the stream data into a list usingCollections.toList()
and return the list and store it indeclarativeApproach
reference variable.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.
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);
}
}
Explanation
We have a list of integer values.
We then added
.stream()
, so the collections of integer values get converted into streams of integer values.we chained it with another function called
distinct()
that removes the duplicate elements from thelist
.Once we go through all the filtered data, we need to terminate the stream and we are doing it with
.collect(...)
.The
.collect(...)
hasCollections.toList()
which converts the stream data into a list and the results are loaded intointegerList1
variable.