Java: Parallel Functional Programming
Modern Java is a hybrid of combining object oriented and functional paradigms together. Hence Java isn’t OOP anymore. This paradigm shift allows developers to tell what they want rather how it is done!
Object-oriented programming makes code understandable by encapsulating moving parts while Functional programming makes code understandable by minimizing moving parts.
Programming paradigms supported by Java:
• Object-oriented programming
• Functional programming
Another two Programming paradigms supported by Java:
• imperative
• declarative
Object-oriented programming is an “imperative” paradigm, focuses on describing how a program operates via statements that change its state. Functional programming is a “declarative” paradigm, focuses on “what” computations should be performed, instead of on “how” to compute them.
Let’s try to remove “James” from below array.
String[] nameArray = {"Barbara","James","Mary"};
String omit = "James";
Imperative way
for(String line: nameArray){
if(!omit.equals(line))
System.out.println(line);
}
This approach forces us to manually handle traversing through the list and then do the filtration and then print.
Declarative method:
Stream.of(nameArray)
.filter(Predicate.not(omit::equals))
.forEach(System.out::println);
In this approach we aren’t traversing the list is handled by the system, we just say we need to filter by “James” and rest is taken care by the system.
Key Functional Programming Concepts & Features
Pure Functions
Functional programming has its roots in lambda calculus, e.g, Computations are treated as evaluation of math functions. Ideally, each function is “pure,” i.e., it has no side- effects on memory or I/O.
First-class citizens
In functional programming, functions are treated as first-class citizens, meaning that they can be bound to names (including local identifiers), passed as arguments, and returned from other functions, just as any other data type can.
Collection pipelines
Collection pipelines are a programming pattern where you organize some computation as a sequence of operations which compose by taking a collection as output of one operation and feeding it into the next. (Common operations are filter, map, and reduce.) This pattern is common in functional programming, and also in object-oriented languages which have lambdas.
No Side Effects
Changing state & mutable shared data are discouraged to avoid various hazards. Instead, focus is on “immutable” objects.
One difficulty in implementing parallelism in applications that use collections is that collections are not thread-safe, which means that multiple threads cannot manipulate a collection without introducing thread interference or memory consistency errors. The Collections Framework provides synchronization wrappers, which add automatic synchronization to an arbitrary collection, making it thread-safe. However, synchronization introduces thread contention. You want to avoid thread contention because it prevents threads from running in parallel. Aggregate operations and parallel streams enable you to implement parallelism with non-thread-safe collections provided that you do not modify the collection(No side effects) while you are operating on it.
A method or an expression has a side effect if, in addition to returning or producing a value, it also modifies the state of the computer. It could be invoking the System.out.println method for debugging.
Immutable object
An object is considered immutable if its state cannot change after it is constructed. Maximum reliance on immutable objects is widely accepted as a sound strategy for creating simple, reliable code. Immutable object state cannot return value.length; change after it is constructed
Race condition
A race condition is the condition of an electronics, software, or other system where the system’s substantive behavior is dependent on the sequence or timing of other uncontrollable events. It becomes a bug when one or more of the possible behaviors is undesirable.
Fundamental to correct concurrent programming.
Atomicity, Visibility and Ordering are fundamental to correct concurrent programming. If an action is atomic, its result must be seen to happen ``all at once’’, or indivisibly. Visibility determines when the effects of one thread can be seen by another. Ordering determines when actions in one thread can be seen to occur out of order with respect to another.Require code synchronization.
Functional vs. Object-Oriented Programming
In contrast to functional programming, OO programming employs “hierarchical data abstraction”
Combining Object-Oriented & Functional Programming
Arguably the most successful declarative programming tool is the relational database (RDB). Before RDBs, most database systems were accessed through imperative code, which is heavily dependent on low-level details such as the order of records, indexes and the physical paths to the data itself.
Since Java is a hybrid language, there are situations in which mutable
changes to shared state are allowed/encouraged. e.g., Java collections
framework classes
If you do share mutable state in your programs then make sure you add the
necessary synchronizers and/or use concurrent/synchronized collections.
Atomic: operations An action that effectively happens all at once
or not at all
Mutual exclusion: Allows concurrent access & updates to shared mutable data without race conditions
Coordination: Ensures computations run properly, e.g., in
the right order, at the right time, under the right conditions, etc.
Barrier synchronization: Ensures that any thread(s) must stop at a
certain point & cannot proceed until all other thread(s) reach this barrier