diff --git a/chapter08-lambda.jsh b/chapter08-lambda.jsh index 5803460..ac60926 100644 --- a/chapter08-lambda.jsh +++ b/chapter08-lambda.jsh @@ -7,9 +7,10 @@ // # Lambda and Method reference // Java unlike JavaScript or Python, don't let you pass a method as argument of a method // without ceremony + // Let say i want to write a method that do either the sum of an array of values or the sum of their square, // it can write if that way -int sumOf(int[] array, boolean squareSum) { +int sumOf(boolean squareSum, int... array) { var sum = 0; for(var value: array) { if (squareSum) { @@ -20,9 +21,10 @@ int sumOf(int[] array, boolean squareSum) { } return sum; } +System.out.println(sumOf(true, 1, 2, 3)); // but you every values of the array, squareSum will have the same value so it's equivalent to write -int sumOf(int[] array, boolean squareSum) { +int sumOf(boolean squareSum, int... array) { var sum = 0; if (squareSum) { for(var value: array) { @@ -35,13 +37,14 @@ int sumOf(int[] array, boolean squareSum) { } return sum; } +System.out.println(sumOf(true, 1, 2, 3)); // and at that point, you have code duplication. // Usually testing a condition in the middle of a computation is a code smell. // There is a way to solve that, it's to take the part of the computation that change as parameter // so sumOf instead of a boolean that take a function as parameter more or less like this /* -int sumOf(int[] array, ??? function) { +int sumOf(??? function, int... array) { var sum = 0; for(var value: array) { sum = sum + function(value); @@ -58,8 +61,7 @@ int sumOf(int[] array, ??? function) { interface Fun { int apply(int value); } - -int sumOf(int[] array, Fun function) { +int sumOf(Fun function, int[] array) { var sum = 0; for(var value: array) { sum = sum + function.apply(value); @@ -69,19 +71,21 @@ int sumOf(int[] array, Fun function) { // then using the lambda syntax we have seeing in the previous chapter sumOf can be called var array = new int[] { 1, 2, 3 }; -System.out.println(sumOf(array, x -> x)); -System.out.println(sumOf(array, x -> x * x)); +System.out.println(sumOf(x -> x, array)); +System.out.println(sumOf(x -> x * x, array)); // ## Package java.util.function -// because it's not convenient to have to declare an interface every times you want to send +// Because it's not convenient to have to declare an interface every times you want to send // a function as parameter, Java already provides a bunch of interfaces in the package // java.lang.function, so you often don't have to write your own // Moreover most interface also have variant for primitive types +import java.util.function.*; + // java.lang.Runnable is equivalent to () -> void -Runnable runnable = () -> { System.out.println("hello"); } +Runnable runnable = () -> { System.out.println("hello"); }; runnable.run(); // Supplier is equivalent to () -> T @@ -114,7 +118,7 @@ System.out.println(fun.apply("function")); // IntFunction, LongFunction and DoubleFunction IntFunction arrayCreator = size -> new String[size]; -System.out.println(arrayCreator.apply(0)); +System.out.println(arrayCreator.apply(5).length); // ToIntFunction, ToLongFunction and ToDoubleFunction ToIntFunction stringLength = s -> s.length(); @@ -152,16 +156,19 @@ System.out.println(binaryOp.applyAsInt(40, 2)); // - with 1 parameter: x -> expression // - with 2 or more parameters: (a, b) -> expression DoubleUnaryOperator op = x -> 2.0 * x; +System.out.println(op.applyAsDouble(2)); // instead of an expression, you can have statements between curly braces DoubleUnaryOperator op = x -> { return 2.0 * x; }; +System.out.println(op.applyAsDouble(2)); // The types of the parameters are optional so you can declare them or not // if you don't declare them the parameter types of the abstract method // of the interface are used DoubleUnaryOperator op = (double x) -> 2.0 * x; +System.out.println(op.applyAsDouble(2)); // ## Method references @@ -202,7 +209,7 @@ System.out.println(factory.apply("John")); // Same as above, the return type is the array. IntFunction arrayCreator = String[]::new; -System.out.println(arrayCreator.apply(2)); +System.out.println(arrayCreator.apply(2).length); // A frequent error is to think that String::length is a reference // to a static method because the syntax is close to String.length() diff --git a/guide/chapter08-lambda.md b/guide/chapter08-lambda.md index e975b00..f470964 100644 --- a/guide/chapter08-lambda.md +++ b/guide/chapter08-lambda.md @@ -4,10 +4,11 @@ if you have not read the previous chapter on interfaces, starts by it first # Lambda and Method reference Java unlike JavaScript or Python, don't let you pass a method as argument of a method without ceremony + Let say i want to write a method that do either the sum of an array of values or the sum of their square, it can write if that way ```java -int sumOf(int[] array, boolean squareSum) { +int sumOf(boolean squareSum, int... array) { var sum = 0; for(var value: array) { if (squareSum) { @@ -18,11 +19,12 @@ int sumOf(int[] array, boolean squareSum) { } return sum; } +System.out.println(sumOf(true, 1, 2, 3)); ``` but you every values of the array, squareSum will have the same value so it's equivalent to write ```java -int sumOf(int[] array, boolean squareSum) { +int sumOf(boolean squareSum, int... array) { var sum = 0; if (squareSum) { for(var value: array) { @@ -35,6 +37,7 @@ int sumOf(int[] array, boolean squareSum) { } return sum; } +System.out.println(sumOf(true, 1, 2, 3)); ``` and at that point, you have code duplication. @@ -43,7 +46,7 @@ There is a way to solve that, it's to take the part of the computation that chan so sumOf instead of a boolean that take a function as parameter more or less like this ```java /* -int sumOf(int[] array, ??? function) { +int sumOf(??? function, int... array) { var sum = 0; for(var value: array) { sum = sum + function(value); @@ -62,10 +65,7 @@ Here my interface is a function that takes an int and return an int so interface Fun { int apply(int value); } -``` - -```java -int sumOf(int[] array, Fun function) { +int sumOf(Fun function, int[] array) { var sum = 0; for(var value: array) { sum = sum + function.apply(value); @@ -77,21 +77,25 @@ int sumOf(int[] array, Fun function) { then using the lambda syntax we have seeing in the previous chapter sumOf can be called ```java var array = new int[] { 1, 2, 3 }; -System.out.println(sumOf(array, x -> x)); -System.out.println(sumOf(array, x -> x * x)); +System.out.println(sumOf(x -> x, array)); +System.out.println(sumOf(x -> x * x, array)); ``` ## Package java.util.function -because it's not convenient to have to declare an interface every times you want to send +Because it's not convenient to have to declare an interface every times you want to send a function as parameter, Java already provides a bunch of interfaces in the package java.lang.function, so you often don't have to write your own Moreover most interface also have variant for primitive types +```java +import java.util.function.*; +``` + java.lang.Runnable is equivalent to () -> void ```java -Runnable runnable = () -> { System.out.println("hello"); } +Runnable runnable = () -> { System.out.println("hello"); }; runnable.run(); ``` @@ -140,7 +144,7 @@ System.out.println(fun.apply("function")); IntFunction, LongFunction and DoubleFunction ```java IntFunction arrayCreator = size -> new String[size]; -System.out.println(arrayCreator.apply(0)); +System.out.println(arrayCreator.apply(5).length); ``` ToIntFunction, ToLongFunction and ToDoubleFunction @@ -194,6 +198,7 @@ Lambda syntax is similar to arrow part the switch syntax - with 2 or more parameters: (a, b) -> expression ```java DoubleUnaryOperator op = x -> 2.0 * x; +System.out.println(op.applyAsDouble(2)); ``` instead of an expression, you can have statements between curly braces @@ -201,6 +206,7 @@ instead of an expression, you can have statements between curly braces DoubleUnaryOperator op = x -> { return 2.0 * x; }; +System.out.println(op.applyAsDouble(2)); ``` The types of the parameters are optional so you can declare them or not @@ -208,6 +214,7 @@ if you don't declare them the parameter types of the abstract method of the interface are used ```java DoubleUnaryOperator op = (double x) -> 2.0 * x; +System.out.println(op.applyAsDouble(2)); ``` @@ -258,7 +265,7 @@ System.out.println(factory.apply("John")); Same as above, the return type is the array. ```java IntFunction arrayCreator = String[]::new; -System.out.println(arrayCreator.apply(2)); +System.out.println(arrayCreator.apply(2).length); ``` A frequent error is to think that String::length is a reference diff --git a/jupyter/chapter08-lambda.ipynb b/jupyter/chapter08-lambda.ipynb index d948a3d..b9e2a0e 100644 --- a/jupyter/chapter08-lambda.ipynb +++ b/jupyter/chapter08-lambda.ipynb @@ -14,7 +14,13 @@ { "cell_type": "markdown", "metadata": {}, - "source": ["# Lambda and Method reference \n", "Java unlike JavaScript or Python, don't let you pass a method as argument of a method\n", "without ceremony\n", "Let say i want to write a method that do either the sum of an array of values or the sum of their square,\n", "it can write if that way\n"] + "source": ["# Lambda and Method reference \n", "Java unlike JavaScript or Python, don't let you pass a method as argument of a method\n", "without ceremony\n"] +} +, +{ + "cell_type": "markdown", + "metadata": {}, + "source": ["Let say i want to write a method that do either the sum of an array of values or the sum of their square,\n", "it can write if that way\n"] } , { @@ -22,7 +28,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["int sumOf(int[] array, boolean squareSum) {\n", " var sum = 0;\n", " for(var value: array) {\n", " if (squareSum) {\n", " sum = sum + value * value;\n", " } else {\n", " sum = sum + value;\n", " }\n", " }\n", " return sum;\n", "}\n"] + "source": ["int sumOf(boolean squareSum, int... array) {\n", " var sum = 0;\n", " for(var value: array) {\n", " if (squareSum) {\n", " sum = sum + value * value;\n", " } else {\n", " sum = sum + value;\n", " }\n", " }\n", " return sum;\n", "}\n", "System.out.println(sumOf(true, 1, 2, 3));\n"] } , { @@ -36,7 +42,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["int sumOf(int[] array, boolean squareSum) {\n", " var sum = 0;\n", " if (squareSum) {\n", " for(var value: array) {\n", " sum = sum + value * value;\n", " }\n", " } else {\n", " for(var value: array) {\n", " sum = sum + value;\n", " }\n", " }\n", " return sum;\n", "}\n"] + "source": ["int sumOf(boolean squareSum, int... array) {\n", " var sum = 0;\n", " if (squareSum) {\n", " for(var value: array) {\n", " sum = sum + value * value;\n", " }\n", " } else {\n", " for(var value: array) {\n", " sum = sum + value;\n", " }\n", " }\n", " return sum;\n", "}\n", "System.out.println(sumOf(true, 1, 2, 3));\n"] } , { @@ -50,7 +56,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["/*\n", "int sumOf(int[] array, ??? function) {\n", " var sum = 0;\n", " for(var value: array) {\n", " sum = sum + function(value);\n", " }\n", " return sum;\n", "}\n", "*/\n"] + "source": ["/*\n", "int sumOf(??? function, int... array) {\n", " var sum = 0;\n", " for(var value: array) {\n", " sum = sum + function(value);\n", " }\n", " return sum;\n", "}\n", "*/\n"] } , { @@ -64,15 +70,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["interface Fun {\n", " int apply(int value);\n", "}\n"] -} -, -{ - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": ["int sumOf(int[] array, Fun function) {\n", " var sum = 0;\n", " for(var value: array) {\n", " sum = sum + function.apply(value);\n", " }\n", " return sum;\n", "}\n"] + "source": ["interface Fun {\n", " int apply(int value);\n", "}\n", "int sumOf(Fun function, int[] array) {\n", " var sum = 0;\n", " for(var value: array) {\n", " sum = sum + function.apply(value);\n", " }\n", " return sum;\n", "}\n"] } , { @@ -86,7 +84,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["var array = new int[] { 1, 2, 3 };\n", "System.out.println(sumOf(array, x -> x));\n", "System.out.println(sumOf(array, x -> x * x));\n"] + "source": ["var array = new int[] { 1, 2, 3 };\n", "System.out.println(sumOf(x -> x, array));\n", "System.out.println(sumOf(x -> x * x, array));\n"] } , { @@ -98,7 +96,15 @@ { "cell_type": "markdown", "metadata": {}, - "source": ["because it's not convenient to have to declare an interface every times you want to send\n", "a function as parameter, Java already provides a bunch of interfaces in the package\n", "java.lang.function, so you often don't have to write your own\n", "Moreover most interface also have variant for primitive types \n"] + "source": ["Because it's not convenient to have to declare an interface every times you want to send\n", "a function as parameter, Java already provides a bunch of interfaces in the package\n", "java.lang.function, so you often don't have to write your own\n", "Moreover most interface also have variant for primitive types \n"] +} +, +{ + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": ["import java.util.function.*;\n"] } , { @@ -112,7 +118,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["Runnable runnable = () -> { System.out.println(\"hello\"); }\n", "runnable.run();\n"] + "source": ["Runnable runnable = () -> { System.out.println(\"hello\"); };\n", "runnable.run();\n"] } , { @@ -224,7 +230,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["IntFunction arrayCreator = size -> new String[size];\n", "System.out.println(arrayCreator.apply(0));\n"] + "source": ["IntFunction arrayCreator = size -> new String[size];\n", "System.out.println(arrayCreator.apply(5).length);\n"] } , { @@ -336,7 +342,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["DoubleUnaryOperator op = x -> 2.0 * x;\n"] + "source": ["DoubleUnaryOperator op = x -> 2.0 * x;\n", "System.out.println(op.applyAsDouble(2));\n"] } , { @@ -350,7 +356,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["DoubleUnaryOperator op = x -> {\n", " return 2.0 * x;\n", " };\n"] + "source": ["DoubleUnaryOperator op = x -> {\n", " return 2.0 * x;\n", " };\n", "System.out.println(op.applyAsDouble(2));\n"] } , { @@ -364,7 +370,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["DoubleUnaryOperator op = (double x) -> 2.0 * x;\n"] + "source": ["DoubleUnaryOperator op = (double x) -> 2.0 * x;\n", "System.out.println(op.applyAsDouble(2));\n"] } , { @@ -470,7 +476,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": ["IntFunction arrayCreator = String[]::new;\n", "System.out.println(arrayCreator.apply(2));\n"] + "source": ["IntFunction arrayCreator = String[]::new;\n", "System.out.println(arrayCreator.apply(2).length);\n"] } , {