Tags: books
OOP (Object-Oriented Programming) is a paradigm where everything is treated as an object — encapsulating state (fields) and behavior (methods) together.
A stream is a sequence of data items that are conceptually produced one at a time.
Parallelism vs Concurrency. Parallelism is executing the code across multiple GPU cores. However Concurrency is running various code accross single core. You want to use paralleism for CPU bound work. Concurrency for I/O bound work or slow task.
Functional programming focuses on:
Method references are a shorthand for lambda expressions that simply call a method. They make your code cleaner and easier to read.
File[] hiddenFiles = new File(".").listFiles(file -> file.isHidden());
You can use a method reference:
File[] hiddenFiles = new File(".").listFiles(File::isHidden);
Double a list using stream
import java.util.*;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers
.stream()
.map(x -> x * x)
.collect(Collectors.toList())
.forEach(System.out::println);
}
}
Here collect is a terminal operation. It is eager—it triggers the processing of the stream and gathers the results. map is lazy, meaning it doesn’t process elements until a terminal operation (like collect) is called.
In programming language theory, the concept of first-class citizens (or first-class objects) refers to entities that can be used freely in all standard ways that other values can be used in a language.
Being passed as an argument to a function
Being returned from a function
Being assigned to a variable
Being stored in data structures
Functions Are Not First-Class Citizens (Before Java 8)
You couldn't pass a method directly as an argument to another method.
You couldn't assign a method to a variable.
You couldn't return a method from another method.
Functions are now first class citizens
Starting with Java 8 , functions became first-class citizens thanks to the introduction of:
Lambda expressions
Method references
Functional interfaces
The java.util.function
package
// Assigning a lambda to a variable
Function<Integer, Integer> square = x -> x * x;
// Invoke it
int result = square.apply(5);
// Passing a function as an argument
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
numbers.forEach(n -> System.out.println(n));
// Returning a function from a method
public Function<Integer, Integer> getMultiplier(int factor) {
return x -> x * factor;
}
Classes Are Also Not First-Class Citizens
Pass a class definition directly as a parameter
Return a class definition from a method (though you can return a Class<?> reference, which is metadata, not the class body itself)
public static void printClassName(Class<?> clazz) {
System.out.println("Class name: " + clazz.getName());
}
printClassName(String.class); // Passing metadata, not the class itself
A method reference allows you to refer to a method without executing it.
Before Java 8, if you wanted to list only the hidden files in a directory, you might write:
File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isHidden();
}
});
Using Method Reference
File[] hiddenFiles = new File(".").listFiles(File::isHidden);
Here, File::isHidden
is a method reference to the isHidden()
method of the File class. It’s equivalent to this lambda expression:
file -> file.isHidden()
Lets you add two filters like
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (GREEN.equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
public static List<Apple> filterHeavyApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getWeight() > 150) {
result.add(apple);
}
}
return result;
}
Refactor this like where a method is passes a predicate parameter named p.
public static boolean isGreenApple(Apple apple) {
return Green.equals(apple.getColor());
}
public static boolean isHeavyApple(Apple apple) {
return apple.getWeight() > 150;
}
import java.util.function.Predicate;
static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (p.test(apple)) {
result.add(apple);
}
}
return result;
}
To test this you can call
filterApples(inventory, Apple::isGreenApple);
// or
filterApples(inventory, Apple::isHeavyApple);
In Java, the Predicate<T>
interface is part of the java.util.function package and plays a central role in functional-style programming.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
It defines a single abstract method : test(T t)
This makes it a functional interface , which means you can assign lambda expressions or method references to it.
It represents a boolean-valued function (i.e., a condition) on one input.
import java.util.function.Predicate;
public class Main {
public static void main(String[] args) {
// Define a predicate using a lambda
Predicate<String> isLongerThan5 = s -> s.length() > 5;
// Use the test() method
System.out.println(isLongerThan5.test("hello")); // false
System.out.println(isLongerThan5.test("longstring")); // true
}
}
List<String> words = List.of("apple", "bat", "carrot", "dog", "elephant");
List<String> longWords = words.stream()
.filter(s -> s.length() > 5)
.toList();
Predicate
Predicate<String> startsWithA = s -> s.startsWith("a");
Predicate<String> endsWithZ = s -> s.endsWith("z");
// Combine with .and(), .or(), .negate()
Predicate<String> combined = startsWithA.and(endsWithZ);
System.out.println(combined.test("applez")); // true
System.out.println(combined.test("apple")); // false