Functional Programming
Functional Interfaces
Single Abstract Method
What makes an interface work with lambdas? It must have exactly one abstract
method - a functional interface. Java provides Function, Predicate, Consumer,
and more. You can create your own too.
Define a functional interface
Interface with exactly one abstract method.
public class Definition {
@FunctionalInterface
interface Formatter {
String format(String input);
default String formatOrEmpty(String input) {
if (input == null) return "";
return format(input);
}
static Formatter identity() {
return s -> s;
}
}
public static void main(String[] args) {
Formatter upper = s -> s.toUpperCase();
String sample = "hello";
System.out.println("upper: " + upper.format(sample));
System.out.println("default: '" + upper.formatOrEmpty(null) + "'");
Formatter id = Formatter.identity();
System.out.println("identity: " + id.format("same"));
}
}
public class Definition {
@FunctionalInterface
interface Formatter {
String format(String input);
default String formatOrEmpty(String input) {
if (input == null) return "";
return format(input);
}
static Formatter identity() {
return s -> s;
}
}
public static void main(String[] args) {
Formatter upper = s -> s.toUpperCase();
String sample = "lambda";
System.out.println("upper: " + upper.format(sample));
System.out.println("default: '" + upper.formatOrEmpty(null) + "'");
Formatter id = Formatter.identity();
System.out.println("identity: " + id.format("same"));
}
}
public class Definition {
@FunctionalInterface
interface Formatter {
String format(String input);
default String formatOrEmpty(String input) {
if (input == null) return "";
return format(input);
}
static Formatter identity() {
return s -> s;
}
}
public static void main(String[] args) {
Formatter upper = s -> s.toUpperCase();
String sample = "Java";
System.out.println("upper: " + upper.format(sample));
System.out.println("default: '" + upper.formatOrEmpty(null) + "'");
Formatter id = Formatter.identity();
System.out.println("identity: " + id.format("same"));
}
}
upper ← ⟨Definition lambda A⟩, sample ← hello
17public static void main(String[] args) {18 Formatter upper→ ⟨Definition lambda A⟩ = s -> s.toUpperCase();19 String sample→ hello = "hello"; //@sample="hello", "lambda", "Java"20 System.out.println("upper: " + upper.format(samplehello));2122 System.out.println("default: '" + upper.formatOrEmpty(null) + "'");outputupper: HELLOdefault String formatOrEmpty(String input)
7default String formatOrEmpty(String inputnull) {8 if (input == null) return "";if (input == null)
7default String formatOrEmpty(String input) {8 if (inputnull == null) return "";9 return format(input);System.out.println("default: '" + upper.formatOrEmpty(null) + "'");
22System.out.println("default: '" + upper.formatOrEmpty(null) + "'");2324Formatter id = Formatter.identity();25System.out.println("identity: " + id.format("same"));outputdefault: ''id ← ⟨Definition$Formatter lambda B⟩
24Formatter id→ ⟨Definition$Formatter lambda B⟩ = Formatter.identity();25System.out.println("identity: " + id.format("same"));outputidentity: same
upper ← ⟨Definition lambda A⟩, sample ← lambda
17public static void main(String[] args) {18 Formatter upper→ ⟨Definition lambda A⟩ = s -> s.toUpperCase();19 String sample→ lambda = "lambda";20 System.out.println("upper: " + upper.format(samplelambda));2122 System.out.println("default: '" + upper.formatOrEmpty(null) + "'");outputupper: LAMBDAdefault String formatOrEmpty(String input)
7default String formatOrEmpty(String inputnull) {8 if (input == null) return "";if (input == null)
7default String formatOrEmpty(String input) {8 if (inputnull == null) return "";9 return format(input);System.out.println("default: '" + upper.formatOrEmpty(null) + "'");
22System.out.println("default: '" + upper.formatOrEmpty(null) + "'");2324Formatter id = Formatter.identity();25System.out.println("identity: " + id.format("same"));outputdefault: ''id ← ⟨Definition$Formatter lambda B⟩
24Formatter id→ ⟨Definition$Formatter lambda B⟩ = Formatter.identity();25System.out.println("identity: " + id.format("same"));outputidentity: same
upper ← ⟨Definition lambda A⟩, sample ← Java
17public static void main(String[] args) {18 Formatter upper→ ⟨Definition lambda A⟩ = s -> s.toUpperCase();19 String sample→ Java = "Java";20 System.out.println("upper: " + upper.format(sampleJava));2122 System.out.println("default: '" + upper.formatOrEmpty(null) + "'");outputupper: JAVAdefault String formatOrEmpty(String input)
7default String formatOrEmpty(String inputnull) {8 if (input == null) return "";if (input == null)
7default String formatOrEmpty(String input) {8 if (inputnull == null) return "";9 return format(input);System.out.println("default: '" + upper.formatOrEmpty(null) + "'");
22System.out.println("default: '" + upper.formatOrEmpty(null) + "'");2324Formatter id = Formatter.identity();25System.out.println("identity: " + id.format("same"));outputdefault: ''id ← ⟨Definition$Formatter lambda B⟩
24Formatter id→ ⟨Definition$Formatter lambda B⟩ = Formatter.identity();25System.out.println("identity: " + id.format("same"));outputidentity: same
@FunctionalInterface annotation ensures single abstract method.
Built-in functional interfaces
Java's standard functional interfaces.
import java.util.function.*;
public class Builtin {
public static void main(String[] args) {
Predicate<String> isLong = s -> s.length() >= 5;
System.out.println("isLong('cat') = " + isLong.test("cat"));
System.out.println("isLong('tiger') = " + isLong.test("tiger"));
Function<String, Integer> length = s -> s.length();
System.out.println("length('hello') = " + length.apply("hello"));
Consumer<String> printer = s -> System.out.println("print: " + s);
printer.accept("message");
long fixedMillis = 1700000000000L;
Supplier<Long> nowMillis = () -> fixedMillis;
System.out.println("nowMillis() = " + nowMillis.get());
UnaryOperator<String> trim = s -> s.trim();
System.out.println("trim(' hi ') = '" + trim.apply(" hi ") + "'");
BiFunction<Integer, Integer, Integer> max = (a, b) -> a > b ? a : b;
System.out.println("max(3, 7) = " + max.apply(3, 7));
}
}
isLong ← ⟨Builtin lambda A⟩, length ← ⟨Builtin lambda B⟩, printer ← ⟨Builtin lambda C⟩
3public class Builtin {4 public static void main(String[] args) {5 Predicate<String> isLong→ ⟨Builtin lambda A⟩ = s -> s.length() >= 5;6 System.out.println("isLong('cat') = " + isLong.test("cat"));7 System.out.println("isLong('tiger') = " + isLong.test("tiger"));89 Function<String, Integer> length→ ⟨Builtin lambda B⟩ = s -> s.length();10 System.out.println("length('hello') = " + length.apply("hello"));1112 Consumer<String> printer→ ⟨Builtin lambda C⟩ = s -> System.out.println("print: " + s);13 printer.accept("message");1415 long fixedMillis→ 1700000000000 = 1700000000000L;16 Supplier<Long> nowMillis→ ⟨Builtin lambda D⟩ = () -> fixedMillis;17 System.out.println("nowMillis() = " + nowMillis.get());1819 UnaryOperator<String> trim→ ⟨Builtin lambda E⟩ = s -> s.trim();20 System.out.println("trim(' hi ') = '" + trim.apply(" hi ") + "'");2122 BiFunction<Integer, Integer, Integer> max→ ⟨Builtin lambda F⟩ = (a, b) -> a > b ? a : b;23 System.out.println("max(3, 7) = " + max.apply(3, 7));outputisLong('cat') = false isLong('tiger') = true length('hello') = 5 nowMillis() = 1700000000000 trim(' hi ') = 'hi' max(3, 7) = 7
Function<T,R>, Predicate<T>, Consumer<T>, Supplier<T> - learn these.
Function composition
Chain functions together.
import java.util.function.*;
public class Composition {
public static void main(String[] args) {
Function<String, String> trim = s -> s.trim();
Function<String, String> upper = s -> s.toUpperCase();
Function<String, Integer> length = s -> s.length();
String text = " hi ";
Function<String, String> upperAfterTrim = upper.compose(trim);
System.out.println("upperAfterTrim('" + text + "') = " + upperAfterTrim.apply(text));
Function<String, Integer> lenAfterUpperTrim = upperAfterTrim.andThen(length);
System.out.println("lenAfterUpperTrim('" + text + "') = " + lenAfterUpperTrim.apply(text));
Predicate<String> nonEmpty = s -> !s.isEmpty();
Predicate<String> startsWithA = s -> s.startsWith("A");
Predicate<String> ok = nonEmpty.and(startsWithA);
System.out.println("ok('') = " + ok.test(""));
System.out.println("ok('Bob') = " + ok.test("Bob"));
System.out.println("ok('Alice') = " + ok.test("Alice"));
System.out.println("not startsWithA('Bob') = " + startsWithA.negate().test("Bob"));
Consumer<String> a = s -> System.out.print("[" + s + "]");
Consumer<String> b = s -> System.out.println(" (len=" + s.length() + ")");
Consumer<String> both = a.andThen(b);
both.accept("hello");
}
}
import java.util.function.*;
public class Composition {
public static void main(String[] args) {
Function<String, String> trim = s -> s.trim();
Function<String, String> upper = s -> s.toUpperCase();
Function<String, Integer> length = s -> s.length();
String text = " Alice ";
Function<String, String> upperAfterTrim = upper.compose(trim);
System.out.println("upperAfterTrim('" + text + "') = " + upperAfterTrim.apply(text));
Function<String, Integer> lenAfterUpperTrim = upperAfterTrim.andThen(length);
System.out.println("lenAfterUpperTrim('" + text + "') = " + lenAfterUpperTrim.apply(text));
Predicate<String> nonEmpty = s -> !s.isEmpty();
Predicate<String> startsWithA = s -> s.startsWith("A");
Predicate<String> ok = nonEmpty.and(startsWithA);
System.out.println("ok('') = " + ok.test(""));
System.out.println("ok('Bob') = " + ok.test("Bob"));
System.out.println("ok('Alice') = " + ok.test("Alice"));
System.out.println("not startsWithA('Bob') = " + startsWithA.negate().test("Bob"));
Consumer<String> a = s -> System.out.print("[" + s + "]");
Consumer<String> b = s -> System.out.println(" (len=" + s.length() + ")");
Consumer<String> both = a.andThen(b);
both.accept("hello");
}
}
import java.util.function.*;
public class Composition {
public static void main(String[] args) {
Function<String, String> trim = s -> s.trim();
Function<String, String> upper = s -> s.toUpperCase();
Function<String, Integer> length = s -> s.length();
String text = "Bob";
Function<String, String> upperAfterTrim = upper.compose(trim);
System.out.println("upperAfterTrim('" + text + "') = " + upperAfterTrim.apply(text));
Function<String, Integer> lenAfterUpperTrim = upperAfterTrim.andThen(length);
System.out.println("lenAfterUpperTrim('" + text + "') = " + lenAfterUpperTrim.apply(text));
Predicate<String> nonEmpty = s -> !s.isEmpty();
Predicate<String> startsWithA = s -> s.startsWith("A");
Predicate<String> ok = nonEmpty.and(startsWithA);
System.out.println("ok('') = " + ok.test(""));
System.out.println("ok('Bob') = " + ok.test("Bob"));
System.out.println("ok('Alice') = " + ok.test("Alice"));
System.out.println("not startsWithA('Bob') = " + startsWithA.negate().test("Bob"));
Consumer<String> a = s -> System.out.print("[" + s + "]");
Consumer<String> b = s -> System.out.println(" (len=" + s.length() + ")");
Consumer<String> both = a.andThen(b);
both.accept("hello");
}
}
trim ← ⟨Composition lambda A⟩, upper ← ⟨Composition lambda B⟩
3public class Composition {4 public static void main(String[] args) {5 Function<String, String> trim→ ⟨Composition lambda A⟩ = s -> s.trim();6 Function<String, String> upper→ ⟨Composition lambda B⟩ = s -> s.toUpperCase();7 Function<String, Integer> length→ ⟨Composition lambda C⟩ = s -> s.length();89 String text→ hi = " hi "; //@text=" hi ", " Alice ", "Bob"10 Function<String, String> upperAfterTrim→ ⟨Function lambda D⟩ = upper.compose(trim⟨Composition lambda A⟩);11 System.out.println("upperAfterTrim('" + text hi + "') = " + upperAfterTrim.apply(text));1213 Function<String, Integer> lenAfterUpperTrim→ ⟨Function lambda E⟩ = upperAfterTrim.andThen(length⟨Composition lambda C⟩);14 System.out.println("lenAfterUpperTrim('" + text hi + "') = " + lenAfterUpperTrim.apply(text));1516 Predicate<String> nonEmpty→ ⟨Composition lambda F⟩ = s -> !s.isEmpty();17 Predicate<String> startsWithA→ ⟨Composition lambda G⟩ = s -> s.startsWith("A");1819 Predicate<String> ok→ ⟨Predicate lambda H⟩ = nonEmpty.and(startsWithA⟨Composition lambda G⟩);20 System.out.println("ok('') = " + ok.test(""));21 System.out.println("ok('Bob') = " + ok.test("Bob"));22 System.out.println("ok('Alice') = " + ok.test("Alice"));2324 System.out.println("not startsWithA('Bob') = " + startsWithA.negate().test("Bob"));2526 Consumer<String> a→ ⟨Composition lambda I⟩ = s -> System.out.print("[" + s + "]");27 Consumer<String> b→ ⟨Composition lambda J⟩ = s -> System.out.println(" (len=" + s.length() + ")");28 Consumer<String> both→ ⟨Consumer lambda K⟩ = a.andThen(b⟨Composition lambda J⟩);29 both.accept("hello");outputupperAfterTrim(' hi ') = HI lenAfterUpperTrim(' hi ') = 2 ok('') = false ok('Bob') = false ok('Alice') = true not startsWithA('Bob') = true
trim ← ⟨Composition lambda A⟩, upper ← ⟨Composition lambda B⟩
3public class Composition {4 public static void main(String[] args) {5 Function<String, String> trim→ ⟨Composition lambda A⟩ = s -> s.trim();6 Function<String, String> upper→ ⟨Composition lambda B⟩ = s -> s.toUpperCase();7 Function<String, Integer> length→ ⟨Composition lambda C⟩ = s -> s.length();89 String text→ Alice = " Alice ";10 Function<String, String> upperAfterTrim→ ⟨Function lambda D⟩ = upper.compose(trim⟨Composition lambda A⟩);11 System.out.println("upperAfterTrim('" + text Alice + "') = " + upperAfterTrim.apply(text));1213 Function<String, Integer> lenAfterUpperTrim→ ⟨Function lambda E⟩ = upperAfterTrim.andThen(length⟨Composition lambda C⟩);14 System.out.println("lenAfterUpperTrim('" + text Alice + "') = " + lenAfterUpperTrim.apply(text));1516 Predicate<String> nonEmpty→ ⟨Composition lambda F⟩ = s -> !s.isEmpty();17 Predicate<String> startsWithA→ ⟨Composition lambda G⟩ = s -> s.startsWith("A");1819 Predicate<String> ok→ ⟨Predicate lambda H⟩ = nonEmpty.and(startsWithA⟨Composition lambda G⟩);20 System.out.println("ok('') = " + ok.test(""));21 System.out.println("ok('Bob') = " + ok.test("Bob"));22 System.out.println("ok('Alice') = " + ok.test("Alice"));2324 System.out.println("not startsWithA('Bob') = " + startsWithA.negate().test("Bob"));2526 Consumer<String> a→ ⟨Composition lambda I⟩ = s -> System.out.print("[" + s + "]");27 Consumer<String> b→ ⟨Composition lambda J⟩ = s -> System.out.println(" (len=" + s.length() + ")");28 Consumer<String> both→ ⟨Consumer lambda K⟩ = a.andThen(b⟨Composition lambda J⟩);29 both.accept("hello");outputupperAfterTrim(' Alice ') = ALICE lenAfterUpperTrim(' Alice ') = 5 ok('') = false ok('Bob') = false ok('Alice') = true not startsWithA('Bob') = true
trim ← ⟨Composition lambda A⟩, upper ← ⟨Composition lambda B⟩
3public class Composition {4 public static void main(String[] args) {5 Function<String, String> trim→ ⟨Composition lambda A⟩ = s -> s.trim();6 Function<String, String> upper→ ⟨Composition lambda B⟩ = s -> s.toUpperCase();7 Function<String, Integer> length→ ⟨Composition lambda C⟩ = s -> s.length();89 String text→ Bob = "Bob";10 Function<String, String> upperAfterTrim→ ⟨Function lambda D⟩ = upper.compose(trim⟨Composition lambda A⟩);11 System.out.println("upperAfterTrim('" + textBob + "') = " + upperAfterTrim.apply(text));1213 Function<String, Integer> lenAfterUpperTrim→ ⟨Function lambda E⟩ = upperAfterTrim.andThen(length⟨Composition lambda C⟩);14 System.out.println("lenAfterUpperTrim('" + textBob + "') = " + lenAfterUpperTrim.apply(text));1516 Predicate<String> nonEmpty→ ⟨Composition lambda F⟩ = s -> !s.isEmpty();17 Predicate<String> startsWithA→ ⟨Composition lambda G⟩ = s -> s.startsWith("A");1819 Predicate<String> ok→ ⟨Predicate lambda H⟩ = nonEmpty.and(startsWithA⟨Composition lambda G⟩);20 System.out.println("ok('') = " + ok.test(""));21 System.out.println("ok('Bob') = " + ok.test("Bob"));22 System.out.println("ok('Alice') = " + ok.test("Alice"));2324 System.out.println("not startsWithA('Bob') = " + startsWithA.negate().test("Bob"));2526 Consumer<String> a→ ⟨Composition lambda I⟩ = s -> System.out.print("[" + s + "]");27 Consumer<String> b→ ⟨Composition lambda J⟩ = s -> System.out.println(" (len=" + s.length() + ")");28 Consumer<String> both→ ⟨Consumer lambda K⟩ = a.andThen(b⟨Composition lambda J⟩);29 both.accept("hello");outputupperAfterTrim('Bob') = BOB lenAfterUpperTrim('Bob') = 3 ok('') = false ok('Bob') = false ok('Alice') = true not startsWithA('Bob') = true
f.andThen(g) - apply f, then g. f.compose(g) - apply g, then f.
Custom generic functional interface
Create your own functional interfaces.
import java.util.*;
public class CustomGeneric {
@FunctionalInterface
interface Validator<T> {
boolean isValid(T value);
default Validator<T> and(Validator<T> other) {
return v -> this.isValid(v) && other.isValid(v);
}
default Validator<T> or(Validator<T> other) {
return v -> this.isValid(v) || other.isValid(v);
}
}
private static <T> List<T> filter(List<T> items, Validator<T> validator) {
List<T> out = new ArrayList<>();
for (T item : items) {
if (validator.isValid(item)) {
out.add(item);
}
}
return out;
}
public static void main(String[] args) {
Validator<String> nonEmpty = s -> s != null && !s.isEmpty();
Validator<String> hasAt = s -> s.contains("@");
Validator<String> emailLike = nonEmpty.and(hasAt);
List<String> inputs = Arrays.asList("", "alice", "alice@example.com", "@", "bob@x");
System.out.println("inputs: " + inputs);
System.out.println("emailLike: " + filter(inputs, emailLike));
Validator<String> empty = s -> s.isEmpty();
Validator<String> emptyOrEmail = empty.or(emailLike);
System.out.println("emptyOrEmail: " + filter(inputs, emptyOrEmail));
}
}
nonEmpty ← ⟨CustomGeneric lambda A⟩, hasAt ← ⟨CustomGeneric lambda B⟩
28public static void main(String[] args) {29 Validator<String> nonEmpty→ ⟨CustomGeneric lambda A⟩ = s -> s != null && !s.isEmpty();30 Validator<String> hasAt→ ⟨CustomGeneric lambda B⟩ = s -> s.contains("@");3132 Validator<String> emailLike = nonEmpty.and(hasAt⟨CustomGeneric lambda B⟩);default Validator<T> and(Validator<T> other)
9default Validator<T> and(Validator<T> other⟨CustomGeneric lambda B⟩) {10 return v -> this.isValid(v) && other.isValid(v);11}emailLike ← ⟨CustomGeneric$Validator lambda C⟩, inputs ← [, alice, alice@example.com, @, bob@x]
32Validator<String> emailLike→ ⟨CustomGeneric$Validator lambda C⟩ = nonEmpty.and(hasAt⟨CustomGeneric lambda B⟩);3334List<String> inputs→ [, alice, alice@example.com, @, bob@x] = Arrays.asList("", "alice", "alice@example.com", "@", "bob@x");35System.out.println("inputs: " + inputs[, alice, alice@example.com, @, bob@x]);36System.out.println("emailLike: " + filter(inputs[, alice, alice@example.com, @, bob@x], emailLike⟨CustomGeneric$Validator lambda C⟩));outputinputs: [, alice, alice@example.com, @, bob@x]out ← []
pass 1 of 218private static <T> List<T> filter(List<T> items[, alice, alice@example.com, @, bob@x], Validator<T> validator⟨CustomGeneric$Validator lambda C⟩) {19 List<T> out→ [] = new ArrayList<>();20 for (T item : items) {for (T item : items)
pass 1 of 1019List<T> out = new ArrayList<>();20for (T item(empty) : items[, alice, alice@example.com, @, bob@x]) {21 if (validator.isValid(item)) {All 10 passes — pass 1 is the card above pass item1 (empty) 2 alice 3 alice@example.com 4 @ 5 bob@x 6 (empty) 7 alice 8 alice@example.com 9 @ 10 bob@x if (validator.isValid(item))
pass 1 of 720for (T item : items) {21 if (validator.isValid(itemalice@example.com)) {22 out.add(itemalice@example.com);23 }All 7 passes — pass 1 is the card above pass item1 alice@example.com 2 @ 3 bob@x 4 (empty) 5 alice@example.com 6 @ 7 bob@x return out;
24 }25 return out[alice@example.com, @, bob@x];26}empty ← ⟨CustomGeneric lambda D⟩
35System.out.println("inputs: " + inputs);36System.out.println("emailLike: " + filter(inputs[, alice, alice@example.com, @, bob@x], emailLike⟨CustomGeneric$Validator lambda C⟩));3738Validator<String> empty→ ⟨CustomGeneric lambda D⟩ = s -> s.isEmpty();39Validator<String> emptyOrEmail = empty.or(emailLike⟨CustomGeneric$Validator lambda C⟩);40System.out.println("emptyOrEmail: " + filter(inputs, emptyOrEmail));outputemailLike: [alice@example.com, @, bob@x]default Validator<T> or(Validator<T> other)
13default Validator<T> or(Validator<T> other⟨CustomGeneric$Validator lambda C⟩) {14 return v -> this.isValid(v) || other.isValid(v);15}emptyOrEmail ← ⟨CustomGeneric$Validator lambda E⟩
38Validator<String> empty = s -> s.isEmpty();39Validator<String> emptyOrEmail→ ⟨CustomGeneric$Validator lambda E⟩ = empty.or(emailLike⟨CustomGeneric$Validator lambda C⟩);40System.out.println("emptyOrEmail: " + filter(inputs[, alice, alice@example.com, @, bob@x], emptyOrEmail⟨CustomGeneric$Validator lambda E⟩));out ← []
pass 2 of 218private static <T> List<T> filter(List<T> items[, alice, alice@example.com, @, bob@x], Validator<T> validator⟨CustomGeneric$Validator lambda E⟩) {19 List<T> out→ [] = new ArrayList<>();20 for (T item : items) {return out;
24 }25 return out[, alice@example.com, @, bob@x];26}System.out.println("emptyOrEmail: " + filter(inputs, emptyOrEmail));
39Validator<String> emptyOrEmail = empty.or(emailLike);40System.out.println("emptyOrEmail: " + filter(inputs[, alice, alice@example.com, @, bob@x], emptyOrEmail⟨CustomGeneric$Validator lambda E⟩));outputemptyOrEmail: [, alice@example.com, @, bob@x]
Define with generics for maximum reusability.
Pass behavior as parameter
Methods that accept functional interfaces.
import java.util.*;
import java.util.function.*;
public class PassBehavior {
private static <T, R> List<R> map(List<T> items, Function<T, R> fn) {
List<R> out = new ArrayList<>();
for (T item : items) {
out.add(fn.apply(item));
}
return out;
}
private static <T> List<T> filter(List<T> items, Predicate<T> pred) {
List<T> out = new ArrayList<>();
for (T item : items) {
if (pred.test(item)) {
out.add(item);
}
}
return out;
}
private static int reduceInts(List<Integer> items, int identity, IntBinaryOperator op) {
int acc = identity;
for (int v : items) {
acc = op.applyAsInt(acc, v);
}
return acc;
}
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
System.out.println("lengths: " + map(names, s -> s.length()));
int minLength = 5;
System.out.println("long names: " + filter(names, s -> s.length() >= minLength));
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
int sum = reduceInts(nums, 0, (a, b) -> a + b);
int product = reduceInts(nums, 1, (a, b) -> a * b);
System.out.println("sum = " + sum);
System.out.println("product = " + product);
}
}
import java.util.*;
import java.util.function.*;
public class PassBehavior {
private static <T, R> List<R> map(List<T> items, Function<T, R> fn) {
List<R> out = new ArrayList<>();
for (T item : items) {
out.add(fn.apply(item));
}
return out;
}
private static <T> List<T> filter(List<T> items, Predicate<T> pred) {
List<T> out = new ArrayList<>();
for (T item : items) {
if (pred.test(item)) {
out.add(item);
}
}
return out;
}
private static int reduceInts(List<Integer> items, int identity, IntBinaryOperator op) {
int acc = identity;
for (int v : items) {
acc = op.applyAsInt(acc, v);
}
return acc;
}
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
System.out.println("lengths: " + map(names, s -> s.length()));
int minLength = 3;
System.out.println("long names: " + filter(names, s -> s.length() >= minLength));
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
int sum = reduceInts(nums, 0, (a, b) -> a + b);
int product = reduceInts(nums, 1, (a, b) -> a * b);
System.out.println("sum = " + sum);
System.out.println("product = " + product);
}
}
import java.util.*;
import java.util.function.*;
public class PassBehavior {
private static <T, R> List<R> map(List<T> items, Function<T, R> fn) {
List<R> out = new ArrayList<>();
for (T item : items) {
out.add(fn.apply(item));
}
return out;
}
private static <T> List<T> filter(List<T> items, Predicate<T> pred) {
List<T> out = new ArrayList<>();
for (T item : items) {
if (pred.test(item)) {
out.add(item);
}
}
return out;
}
private static int reduceInts(List<Integer> items, int identity, IntBinaryOperator op) {
int acc = identity;
for (int v : items) {
acc = op.applyAsInt(acc, v);
}
return acc;
}
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
System.out.println("lengths: " + map(names, s -> s.length()));
int minLength = 7;
System.out.println("long names: " + filter(names, s -> s.length() >= minLength));
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
int sum = reduceInts(nums, 0, (a, b) -> a + b);
int product = reduceInts(nums, 1, (a, b) -> a * b);
System.out.println("sum = " + sum);
System.out.println("product = " + product);
}
}
names ← [Alice, Bob, Charlie]
32public static void main(String[] args) {33 List<String> names→ [Alice, Bob, Charlie] = Arrays.asList("Alice", "Bob", "Charlie");3435 System.out.println("lengths: " + map(names[Alice, Bob, Charlie], s -> s.length()));out ← []
6private static <T, R> List<R> map(List<T> items[Alice, Bob, Charlie], Function<T, R> fn⟨PassBehavior lambda A⟩) {7 List<R> out→ [] = new ArrayList<>();8 for (T item : items) {for (T item : items)
pass 1 of 37List<R> out = new ArrayList<>();8for (T itemAlice : items[Alice, Bob, Charlie]) {9 out.add(fn.apply(itemAlice));10}All 3 passes — pass 1 is the card above pass item1 Alice 2 Bob 3 Charlie return out;
10 }11 return out[5, 3, 7];12}minLength ← 5
35System.out.println("lengths: " + map(names[Alice, Bob, Charlie], s -> s.length()));3637int minLength→ 5 = 5; //@minLength=5, 3, 738System.out.println("long names: " + filter(names[Alice, Bob, Charlie], s -> s.length() >= minLength));outputlengths: [5, 3, 7]out ← []
14private static <T> List<T> filter(List<T> items[Alice, Bob, Charlie], Predicate<T> pred⟨PassBehavior lambda B⟩) {15 List<T> out→ [] = new ArrayList<>();16 for (T item : items) {for (T item : items)
pass 1 of 315List<T> out = new ArrayList<>();16for (T itemAlice : items[Alice, Bob, Charlie]) {17 if (pred.test(item)) {All 3 passes — pass 1 is the card above pass item1 Alice 2 Bob 3 Charlie if (pred.test(item))
pass 1 of 216for (T item : items) {17 if (pred.test(itemAlice)) {18 out.add(itemAlice);19 }if (pred.test(item))
pass 2 of 216for (T item : items) {17 if (pred.test(itemCharlie)) {18 out.add(itemCharlie);19 }return out;
20 }21 return out[Alice, Charlie];22}nums ← [1, 2, 3, 4]
37int minLength = 5; //@minLength=5, 3, 738System.out.println("long names: " + filter(names[Alice, Bob, Charlie], s -> s.length() >= minLength));3940List<Integer> nums→ [1, 2, 3, 4] = Arrays.asList(1, 2, 3, 4);41int sum = reduceInts(nums[1, 2, 3, 4], 0, (a, b) -> a + b);42int product = reduceInts(nums, 1, (a, b) -> a * b);outputlong names: [Alice, Charlie]acc ← 0
pass 1 of 224private static int reduceInts(List<Integer> items[1, 2, 3, 4], int identity0, IntBinaryOperator op⟨PassBehavior lambda C⟩) {25 int acc→ 0 = identity;26 for (int v : items) {acc ← 1
pass 1 of 825int acc = identity;26for (int v1 : items[1, 2, 3, 4]) {27 acc→ 1 = op.applyAsInt(acc, v1);28}All 8 passes — pass 1 is the card above pass vacc1 1 0 → 1 2 2 1 → 3 3 3 3 → 6 4 4 6 → 10 5 1 1 6 2 1 → 2 7 3 2 → 6 8 4 6 → 24 return acc;
28 }29 return acc10;30}sum ← 10
40List<Integer> nums = Arrays.asList(1, 2, 3, 4);41int sum→ 10 = reduceInts(nums[1, 2, 3, 4], 0, (a, b) -> a + b);42int product = reduceInts(nums[1, 2, 3, 4], 1, (a, b) -> a * b);43System.out.println("sum = " + sum);acc ← 1
pass 2 of 224private static int reduceInts(List<Integer> items[1, 2, 3, 4], int identity1, IntBinaryOperator op⟨PassBehavior lambda D⟩) {25 int acc→ 1 = identity;26 for (int v : items) {return acc;
28 }29 return acc24;30}product ← 24
41int sum = reduceInts(nums, 0, (a, b) -> a + b);42int product→ 24 = reduceInts(nums[1, 2, 3, 4], 1, (a, b) -> a * b);43System.out.println("sum = " + sum10);44System.out.println("product = " + product24);outputsum = 10 product = 24
names ← [Alice, Bob, Charlie]
32public static void main(String[] args) {33 List<String> names→ [Alice, Bob, Charlie] = Arrays.asList("Alice", "Bob", "Charlie");3435 System.out.println("lengths: " + map(names[Alice, Bob, Charlie], s -> s.length()));out ← []
6private static <T, R> List<R> map(List<T> items[Alice, Bob, Charlie], Function<T, R> fn⟨PassBehavior lambda A⟩) {7 List<R> out→ [] = new ArrayList<>();8 for (T item : items) {for (T item : items)
pass 1 of 37List<R> out = new ArrayList<>();8for (T itemAlice : items[Alice, Bob, Charlie]) {9 out.add(fn.apply(itemAlice));10}All 3 passes — pass 1 is the card above pass item1 Alice 2 Bob 3 Charlie return out;
10 }11 return out[5, 3, 7];12}minLength ← 3
35System.out.println("lengths: " + map(names[Alice, Bob, Charlie], s -> s.length()));3637int minLength→ 3 = 3;38System.out.println("long names: " + filter(names[Alice, Bob, Charlie], s -> s.length() >= minLength));outputlengths: [5, 3, 7]out ← []
14private static <T> List<T> filter(List<T> items[Alice, Bob, Charlie], Predicate<T> pred⟨PassBehavior lambda B⟩) {15 List<T> out→ [] = new ArrayList<>();16 for (T item : items) {for (T item : items)
pass 1 of 315List<T> out = new ArrayList<>();16for (T itemAlice : items[Alice, Bob, Charlie]) {17 if (pred.test(item)) {All 3 passes — pass 1 is the card above pass item1 Alice 2 Bob 3 Charlie if (pred.test(item))
pass 1 of 316for (T item : items) {17 if (pred.test(itemAlice)) {18 out.add(itemAlice);19 }All 3 passes — pass 1 is the card above pass item1 Alice 2 Bob 3 Charlie return out;
20 }21 return out[Alice, Bob, Charlie];22}nums ← [1, 2, 3, 4]
37int minLength = 3;38System.out.println("long names: " + filter(names[Alice, Bob, Charlie], s -> s.length() >= minLength));3940List<Integer> nums→ [1, 2, 3, 4] = Arrays.asList(1, 2, 3, 4);41int sum = reduceInts(nums[1, 2, 3, 4], 0, (a, b) -> a + b);42int product = reduceInts(nums, 1, (a, b) -> a * b);outputlong names: [Alice, Bob, Charlie]acc ← 0
pass 1 of 224private static int reduceInts(List<Integer> items[1, 2, 3, 4], int identity0, IntBinaryOperator op⟨PassBehavior lambda C⟩) {25 int acc→ 0 = identity;26 for (int v : items) {acc ← 1
pass 1 of 825int acc = identity;26for (int v1 : items[1, 2, 3, 4]) {27 acc→ 1 = op.applyAsInt(acc, v1);28}All 8 passes — pass 1 is the card above pass vacc1 1 0 → 1 2 2 1 → 3 3 3 3 → 6 4 4 6 → 10 5 1 1 6 2 1 → 2 7 3 2 → 6 8 4 6 → 24 return acc;
28 }29 return acc10;30}sum ← 10
40List<Integer> nums = Arrays.asList(1, 2, 3, 4);41int sum→ 10 = reduceInts(nums[1, 2, 3, 4], 0, (a, b) -> a + b);42int product = reduceInts(nums[1, 2, 3, 4], 1, (a, b) -> a * b);43System.out.println("sum = " + sum);acc ← 1
pass 2 of 224private static int reduceInts(List<Integer> items[1, 2, 3, 4], int identity1, IntBinaryOperator op⟨PassBehavior lambda D⟩) {25 int acc→ 1 = identity;26 for (int v : items) {return acc;
28 }29 return acc24;30}product ← 24
41int sum = reduceInts(nums, 0, (a, b) -> a + b);42int product→ 24 = reduceInts(nums[1, 2, 3, 4], 1, (a, b) -> a * b);43System.out.println("sum = " + sum10);44System.out.println("product = " + product24);outputsum = 10 product = 24
names ← [Alice, Bob, Charlie]
32public static void main(String[] args) {33 List<String> names→ [Alice, Bob, Charlie] = Arrays.asList("Alice", "Bob", "Charlie");3435 System.out.println("lengths: " + map(names[Alice, Bob, Charlie], s -> s.length()));out ← []
6private static <T, R> List<R> map(List<T> items[Alice, Bob, Charlie], Function<T, R> fn⟨PassBehavior lambda A⟩) {7 List<R> out→ [] = new ArrayList<>();8 for (T item : items) {for (T item : items)
pass 1 of 37List<R> out = new ArrayList<>();8for (T itemAlice : items[Alice, Bob, Charlie]) {9 out.add(fn.apply(itemAlice));10}All 3 passes — pass 1 is the card above pass item1 Alice 2 Bob 3 Charlie return out;
10 }11 return out[5, 3, 7];12}minLength ← 7
35System.out.println("lengths: " + map(names[Alice, Bob, Charlie], s -> s.length()));3637int minLength→ 7 = 7;38System.out.println("long names: " + filter(names[Alice, Bob, Charlie], s -> s.length() >= minLength));outputlengths: [5, 3, 7]out ← []
14private static <T> List<T> filter(List<T> items[Alice, Bob, Charlie], Predicate<T> pred⟨PassBehavior lambda B⟩) {15 List<T> out→ [] = new ArrayList<>();16 for (T item : items) {for (T item : items)
pass 1 of 315List<T> out = new ArrayList<>();16for (T itemAlice : items[Alice, Bob, Charlie]) {17 if (pred.test(item)) {All 3 passes — pass 1 is the card above pass item1 Alice 2 Bob 3 Charlie if (pred.test(item))
16for (T item : items) {17 if (pred.test(itemCharlie)) {18 out.add(itemCharlie);19 }return out;
20 }21 return out[Charlie];22}nums ← [1, 2, 3, 4]
37int minLength = 7;38System.out.println("long names: " + filter(names[Alice, Bob, Charlie], s -> s.length() >= minLength));3940List<Integer> nums→ [1, 2, 3, 4] = Arrays.asList(1, 2, 3, 4);41int sum = reduceInts(nums[1, 2, 3, 4], 0, (a, b) -> a + b);42int product = reduceInts(nums, 1, (a, b) -> a * b);outputlong names: [Charlie]acc ← 0
pass 1 of 224private static int reduceInts(List<Integer> items[1, 2, 3, 4], int identity0, IntBinaryOperator op⟨PassBehavior lambda C⟩) {25 int acc→ 0 = identity;26 for (int v : items) {acc ← 1
pass 1 of 825int acc = identity;26for (int v1 : items[1, 2, 3, 4]) {27 acc→ 1 = op.applyAsInt(acc, v1);28}All 8 passes — pass 1 is the card above pass vacc1 1 0 → 1 2 2 1 → 3 3 3 3 → 6 4 4 6 → 10 5 1 1 6 2 1 → 2 7 3 2 → 6 8 4 6 → 24 return acc;
28 }29 return acc10;30}sum ← 10
40List<Integer> nums = Arrays.asList(1, 2, 3, 4);41int sum→ 10 = reduceInts(nums[1, 2, 3, 4], 0, (a, b) -> a + b);42int product = reduceInts(nums[1, 2, 3, 4], 1, (a, b) -> a * b);43System.out.println("sum = " + sum);acc ← 1
pass 2 of 224private static int reduceInts(List<Integer> items[1, 2, 3, 4], int identity1, IntBinaryOperator op⟨PassBehavior lambda D⟩) {25 int acc→ 1 = identity;26 for (int v : items) {return acc;
28 }29 return acc24;30}product ← 24
41int sum = reduceInts(nums, 0, (a, b) -> a + b);42int product→ 24 = reduceInts(nums[1, 2, 3, 4], 1, (a, b) -> a * b);43System.out.println("sum = " + sum10);44System.out.println("product = " + product24);outputsum = 10 product = 24
Accept Predicate<T> to let caller define filtering logic.
Exercise: Practical.java
Build a data processor using functional interfaces