|
| 1 | +package funcprog; |
| 2 | +import java.util.function.BiFunction; |
| 3 | +import java.util.function.Function; |
| 4 | +import java.util.function.Supplier; |
| 5 | + |
| 6 | +public class ClosureDemo { |
| 7 | + |
| 8 | + public static void main(String[] args) { |
| 9 | + closureType1Demo(); |
| 10 | + closureType2Demo(); |
| 11 | + closureType3Demo(); |
| 12 | + closureType4Demo(); |
| 13 | + closureType5Demo(); |
| 14 | + closureType6Demo(); |
| 15 | + closureType7Demo(); |
| 16 | + } |
| 17 | + |
| 18 | + /* |
| 19 | + CLOSURES: |
| 20 | + A closure is the combination of a function bundled together (enclosed) with |
| 21 | + references to its surrounding state (the lexical environment). In other words, |
| 22 | + a closure gives you access to an outer function’s scope from an inner function. |
| 23 | +
|
| 24 | + Closures are commonly used to give objects data privacy. When you use closures for data privacy, |
| 25 | + the enclosed variables are only in scope within the containing (outer) function. |
| 26 | + You can’t get at the data from an outside scope except through the object’s privileged methods. |
| 27 | + In JavaScript, any exposed method defined within the closure scope is privileged. |
| 28 | +
|
| 29 | + Closures are also used when we need to partially apply functions and also for currying. The returned partial function is the privileged function |
| 30 | + that remembers the applied parameters. |
| 31 | +
|
| 32 | + Closures are basically stateful functions |
| 33 | + */ |
| 34 | + |
| 35 | + @FunctionalInterface // optional |
| 36 | + public interface NumToTextConverter { |
| 37 | + String convert(int x); |
| 38 | + } |
| 39 | + |
| 40 | + // Type 1: Closure with custom Functional Interface and inner class |
| 41 | + static void closureType1Demo() { |
| 42 | + NumToTextConverter textOfWeekday = new NumToTextConverter() { |
| 43 | + String [] weeks = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; |
| 44 | + @Override |
| 45 | + public String convert(int num) { |
| 46 | + return (num > 0 && num <= weeks.length) ? weeks[num-1] : null; |
| 47 | + }; |
| 48 | + }; |
| 49 | + System.out.println(textOfWeekday.convert(1)); // Mon |
| 50 | + } |
| 51 | + |
| 52 | + // Type 2: Closure with custom Functional Interface & Lambda expression |
| 53 | + static void closureType2Demo() { |
| 54 | + NumToTextConverter textOfWeekday = num -> { |
| 55 | + String [] weeks = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; |
| 56 | + return (num > 0 && num <= weeks.length) ? weeks[num-1] : null; |
| 57 | + }; |
| 58 | + System.out.println(textOfWeekday.convert(2)); // Tue |
| 59 | + } |
| 60 | + |
| 61 | + // Type 3: Closure with pre-defined Functional Interface, with Lambda expression |
| 62 | + static void closureType3Demo() { |
| 63 | + Function<Integer, String> getTextOfWeekday = num -> { |
| 64 | + String [] weeks = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; |
| 65 | + return (num > 0 && num <= weeks.length) ? weeks[num-1] : null; |
| 66 | + }; |
| 67 | + System.out.println(getTextOfWeekday.apply(3)); // Wed |
| 68 | + } |
| 69 | + |
| 70 | + // Type 4: [ACTUAL] Closure with pre-defined Functional Interface, with Lambda expression, with inner function |
| 71 | + // having access to parent scope (String [] weeks) |
| 72 | + static Function<Integer, String> getTextOfWeekday() { |
| 73 | + String [] weeks = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; |
| 74 | + return num -> (num > 0 && num <= weeks.length) ? weeks[num-1] : null; // privileged inner function that encloses/remembers weeks |
| 75 | + } |
| 76 | + static void closureType4Demo() { |
| 77 | + System.out.println(getTextOfWeekday().apply(4)); // Thu |
| 78 | + } |
| 79 | + |
| 80 | + // Type 5: Closure with pre-defined Functional Interface, with Lambda expression, with inner function having access to parent scope |
| 81 | + // parent scope, in this scope, is nothing but state passed by client |
| 82 | + static Function<Integer, String> getTextOfWeekday(String [] weeks) { |
| 83 | + return num -> (num > 0 && num <= weeks.length) ? weeks[num-1] : null; |
| 84 | + } |
| 85 | + static void closureType5Demo() { |
| 86 | + Function<Integer, String> getArabTextOfWeekday = getTextOfWeekday(new String[]{ "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu"}); |
| 87 | + Function<Integer, String> getIndianTextOfWeekday = getTextOfWeekday(new String[]{ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}); |
| 88 | + System.out.println(getArabTextOfWeekday.apply(5)); // Tue |
| 89 | + System.out.println(getIndianTextOfWeekday.apply(5)); // Fri |
| 90 | + } |
| 91 | + |
| 92 | + |
| 93 | + // Type 6: Closure with lambda and with pre-defined Functional Interface, demonstrating the fact that |
| 94 | + // Lambdas/CLosures in Java 8 cover values and not variables |
| 95 | + static Supplier<Integer> getNextInSequence() { |
| 96 | + int lastInSequence = 0; |
| 97 | + return () -> lastInSequence + 1; // ++lastSequence will be a compiler error coz Java 8 forces the parent scope variables (non heaps) to be immutable |
| 98 | + }; |
| 99 | + static void closureType6Demo() { |
| 100 | + System.out.println(getNextInSequence().get()); // 1 |
| 101 | + System.out.println(getNextInSequence().get()); // 1 and not 2 |
| 102 | + } |
| 103 | + |
| 104 | + // Type 7: Closure, used to partially apply |
| 105 | + static Function<Integer, Integer> partial(BiFunction<Integer, Integer, Integer> fn, Integer x) { |
| 106 | + return y -> fn.apply(x, y); // privileged inner function that remembers x (value and not variable) |
| 107 | + } |
| 108 | + static void closureType7Demo() { |
| 109 | + BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y; |
| 110 | + Function<Integer, Integer> tenAdder = partial(add, 10); |
| 111 | + System.out.println(tenAdder.apply(5)); |
| 112 | + Function<Integer, Integer> twentyAdder = partial(add, 20); |
| 113 | + System.out.println(twentyAdder.apply(5)); |
| 114 | + } |
| 115 | + |
| 116 | +} |
0 commit comments