Transform your Java coding style through functional paradigms, stream processing mastery, and lambda-powered elegant solutions
By the end of this lesson, you will:
<aside> ā”
Functional Programming Philosophy
Functional programming treats computation as the evaluation of functions - avoiding changing state and mutable data. In Java, this means writing more declarative code that says WHAT you want rather than HOW to do it.
</aside>
Java Functional Evolution - From Verbose to Elegant
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
š JAVA 7 & EARLIER šÆ JAVA 8+ LAMBDA ERA
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā // Anonymous Inner Classes ā ā // Lambda Expressions ā
ā Comparator<String> comp = new ā ā Comparator<String> comp = ā
ā Comparator<String>() { ā ā (s1, s2) -> s1.length() - ā
ā @Override ā ā s2.length(); ā
ā public int compare(String s1, ā ā ā
ā String s2) { ā ā // Method References ā
ā return s1.length() - ā ā list.forEach(System.out::println); ā
ā s2.length(); ā ā ā
ā } ā ā // Stream API ā
ā }; ā ā [list.stream](<http://list.stream>)() ā
ā ā ā .filter(s -> s.length() > 3) ā
ā // Imperative Loops ā ā .map(String::toUpperCase) ā
ā List<String> result = new ā ā .collect(Collectors.toList()); ā
ā ArrayList<>(); ā ā ā
ā for (String s : list) { ā ā ā
ā if (s.length() > 3) { ā ā ā
ā result.add(s.toUpperCase()); ā ā ā
ā } ā ā ā
ā } ā ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
š° PROBLEMS: ⨠BENEFITS:
⢠Verbose boilerplate ⢠Concise & readable
⢠Mutable state ⢠Immutable operations
⢠Error-prone loops ⢠Declarative intent
⢠Hard to parallelize ⢠Easy parallelization
<aside> ā”ļø
Lambda Syntax Formula
(parameters) -> expression or (parameters) -> { statements; }
Lambda = Parameters + Arrow Token + Body = Functional Interface Implementation
</aside>
public class MovieStreamingPlatform {
// š¬ Movie data model
public static class Movie {
private String title;
private String genre;
private int year;
private double rating;
private int duration; // minutes
private List<String> actors;
public Movie(String title, String genre, int year, double rating,
int duration, List<String> actors) {
this.title = title;
this.genre = genre;
this.year = year;
this.rating = rating;
this.duration = duration;
this.actors = actors;
}
// Getters
public String getTitle() { return title; }
public String getGenre() { return genre; }
public int getYear() { return year; }
public double getRating() { return rating; }
public int getDuration() { return duration; }
public List<String> getActors() { return actors; }
@Override
public String toString() {
return String.format("%s (%d) - %s [%.1f/10, %dmin]",
title, year, genre, rating, duration);
}
}
private List<Movie> movies;
public MovieStreamingPlatform() {
initializeMovies();
}
private void initializeMovies() {
movies = Arrays.asList(
new Movie("Inception", "Sci-Fi", 2010, 8.8, 148,
Arrays.asList("Leonardo DiCaprio", "Marion Cotillard", "Tom Hardy")),
new Movie("The Matrix", "Sci-Fi", 1999, 8.7, 136,
Arrays.asList("Keanu Reeves", "Laurence Fishburne", "Carrie-Anne Moss")),
new Movie("Pulp Fiction", "Crime", 1994, 8.9, 154,
Arrays.asList("John Travolta", "Uma Thurman", "Samuel L. Jackson")),
new Movie("The Dark Knight", "Action", 2008, 9.0, 152,
Arrays.asList("Christian Bale", "Heath Ledger", "Aaron Eckhart")),
new Movie("Forrest Gump", "Drama", 1994, 8.8, 142,
Arrays.asList("Tom Hanks", "Robin Wright", "Gary Sinise")),
new Movie("The Godfather", "Crime", 1972, 9.2, 175,
Arrays.asList("Marlon Brando", "Al Pacino", "James Caan")),
new Movie("Parasite", "Thriller", 2019, 8.6, 132,
Arrays.asList("Song Kang-ho", "Lee Sun-kyun", "Cho Yeo-jeong")),
new Movie("Spirited Away", "Animation", 2001, 9.3, 125,
Arrays.asList("Rumi Hiiragi", "Miyu Irino", "Mari Natsuki"))
);
}
// šÆ Lambda Expression Syntax Demonstrations
public void demonstrateLambdaSyntax() {
System.out.println("šÆ Lambda Expression Syntax Variations");
System.out.println("=====================================");
// 1ļøā£ No parameters - Supplier<T>
Supplier<String> greeting = () -> "Welcome to our movie platform!";
System.out.println("No parameters: " + greeting.get());
// 2ļøā£ Single parameter (parentheses optional)
Consumer<String> printer1 = message -> System.out.println("š¢ " + message);
Consumer<String> printer2 = (message) -> System.out.println("š¢ " + message);
printer1.accept("Single parameter without parentheses");
printer2.accept("Single parameter with parentheses");
// 3ļøā£ Multiple parameters
BiFunction<String, String, String> combiner = (a, b) -> a + " & " + b;
System.out.println("Multiple parameters: " + combiner.apply("Action", "Adventure"));
// 4ļøā£ Block body with return
Function<Movie, String> movieSummary = (movie) -> {
StringBuilder summary = new StringBuilder();
summary.append("š¬ ").append(movie.getTitle());
summary.append(" (").append(movie.getYear()).append(")");
if (movie.getRating() > 8.5) {
summary.append(" ā HIGHLY RATED!");
}
return summary.toString();
};
System.out.println("Block body example:");
[movies.stream](<http://movies.stream>)()
.limit(3)
.map(movieSummary)
.forEach(System.out::println);
// 5ļøā£ Explicit type parameters (usually inferred)
Comparator<Movie> ratingComparator = (Movie m1, Movie m2) ->
[Double.compare](<http://Double.compare>)(m2.getRating(), m1.getRating());
System.out.println("\\nTop 3 rated movies:");
[movies.stream](<http://movies.stream>)()
.sorted(ratingComparator)
.limit(3)
.forEach(System.out::println);
}
// š Functional Interface Usage Examples
public void demonstrateFunctionalInterfaces() {
System.out.println("\\nš Functional Interface Patterns");
System.out.println("================================");
// Predicate<T> - boolean test
Predicate<Movie> isRecentMovie = movie -> movie.getYear() >= 2010;
Predicate<Movie> isHighRated = movie -> movie.getRating() >= 8.0;
Predicate<Movie> isActionMovie = movie -> "Action".equals(movie.getGenre());
// Combine predicates
Predicate<Movie> recentHighRatedAction = isRecentMovie
.and(isHighRated)
.and(isActionMovie);
System.out.println("Recent high-rated action movies:");
[movies.stream](<http://movies.stream>)()
.filter(recentHighRatedAction)
.forEach(movie -> System.out.println(" š¬ " + movie));
// Function<T, R> - transformation
Function<Movie, String> genreExtractor = Movie::getGenre;
Function<String, String> genreFormatter = genre -> "šŗ " + genre.toUpperCase();
Function<Movie, String> genreDisplay = genreExtractor.andThen(genreFormatter);
System.out.println("\\nGenre transformation:");
[movies.stream](<http://movies.stream>)()
.map(genreDisplay)
.distinct()
.forEach(System.out::println);
// Consumer<T> - side effects
Consumer<Movie> movieLogger = movie ->
System.out.println("š Viewed: " + movie.getTitle());
Consumer<Movie> ratingLogger = movie ->
System.out.println("ā Rating: " + movie.getRating());
Consumer<Movie> fullLogger = movieLogger.andThen(ratingLogger);
System.out.println("\\nMovie logging:");
[movies.stream](<http://movies.stream>)()
.filter(movie -> movie.getYear() == 1994)
.forEach(fullLogger);
// BiFunction<T, U, R> - two inputs, one output
BiFunction<Double, Integer, String> movieScore = (rating, year) -> {
double ageBonus = (2024 - year) * 0.01; // Bonus for classics
double totalScore = rating + ageBonus;
return String.format("%.2f", totalScore);
};
System.out.println("\\nMovies with age-adjusted scores:");
movies.forEach(movie -> {
String score = movieScore.apply(movie.getRating(), movie.getYear());
System.out.println(" " + movie.getTitle() + ": " + score);
});
}
// šÆ Advanced Lambda Patterns
public void demonstrateAdvancedPatterns() {
System.out.println("\\nš Advanced Lambda Patterns");
System.out.println("===========================");
// Higher-order functions - functions that return functions
Function<String, Predicate<Movie>> genreFilter = genre ->
movie -> genre.equals(movie.getGenre());
Function<Double, Predicate<Movie>> ratingFilter = minRating ->
movie -> movie.getRating() >= minRating;
// Use the factory functions
Predicate<Movie> sciFiFilter = genreFilter.apply("Sci-Fi");
Predicate<Movie> highRatingFilter = ratingFilter.apply(8.5);
System.out.println("High-rated Sci-Fi movies:");
[movies.stream](<http://movies.stream>)()
.filter(sciFiFilter.and(highRatingFilter))
.forEach(movie -> System.out.println(" š " + movie));
// Currying - transforming multi-argument function into chain of single-argument functions
Function<String, Function<Integer, Function<Double, Movie>>> movieCreator =
title -> year -> rating ->
new Movie(title, "Unknown", year, rating, 0, Arrays.asList());
Movie newMovie = movieCreator
.apply("Test Movie")
.apply(2024)
.apply(7.5);
System.out.println("\\nCurried movie creation: " + newMovie);
// Lambda with exception handling
Function<String, Optional<Integer>> safeParser = input -> {
try {
return Optional.of(Integer.parseInt(input));
} catch (NumberFormatException e) {
return Optional.empty();
}
};
List<String> inputs = Arrays.asList("2010", "invalid", "1999", "not-a-year");
System.out.println("\\nSafe parsing results:");
[inputs.stream](<http://inputs.stream>)()
.map(safeParser)
.forEach(result ->
System.out.println(" " + [result.map](<http://result.map>)(String::valueOf).orElse("Invalid")));
}
}