<jupyter_start><jupyter_text>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 methodwithout 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<jupyter_code>int sumOf(boolean squareSum, int... array) {
  var sum = 0;
  for(var value: array) {
    if (squareSum) {
      sum = sum + value * value;
    } else {
      sum = sum + value;
    }
  }
  return sum;
}
System.out.println(sumOf(true, 1, 2, 3));<jupyter_output><empty_output><jupyter_text>but you every values of the array, squareSum will have the same value so it's equivalent to write<jupyter_code>int sumOf(boolean squareSum, int... array) {
  var sum = 0;
  if (squareSum) {
    for(var value: array) {
      sum = sum + value * value;
    }
  } else {
    for(var value: array) {
      sum = sum + value;
    }
  }
  return sum;
}
System.out.println(sumOf(true, 1, 2, 3));<jupyter_output><empty_output><jupyter_text>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 parameterso sumOf instead of a boolean that take a function as parameter more or less like this<jupyter_code>/*
int sumOf(??? function, int... array) {
  var sum = 0;
  for(var value: array) {
    sum = sum + function(value);
  }
  return sum;
}
*/<jupyter_output><empty_output><jupyter_text>Functional interfacethe question is what ??? is. The answer in simple in Java, if it can be either a value or another one,then it's an interface. Exactly like in the previous chapter, we have introduce an interface inbetween two records.Here my interface is a function that takes an int and return an int so<jupyter_code>interface Fun {
  int apply(int value);
}
int sumOf(Fun function, int[] array) {
  var sum = 0;
  for(var value: array) {
    sum = sum + function.apply(value);
  }
  return sum;
}<jupyter_output><empty_output><jupyter_text>then using the lambda syntax we have seeing in the previous chapter sumOf can be called<jupyter_code>var array = new int[] { 1, 2, 3 };
System.out.println(sumOf(x -> x, array));
System.out.println(sumOf(x -> x * x, array));<jupyter_output><empty_output><jupyter_text>Package java.util.function Because it's not convenient to have to declare an interface every times you want to senda function as parameter, Java already provides a bunch of interfaces in the packagejava.lang.function, so you often don't have to write your ownMoreover most interface also have variant for primitive types<jupyter_code>import java.util.function.*;<jupyter_output><empty_output><jupyter_text>java.lang.Runnable is equivalent to () -> void<jupyter_code>Runnable runnable = () -> { System.out.println("hello"); };
runnable.run();<jupyter_output><empty_output><jupyter_text>Supplier is equivalent to () -> T<jupyter_code>Supplier<String> supplier = () -> "hello supplier";
System.out.println(supplier.get());<jupyter_output><empty_output><jupyter_text>IntSupplier, LongSupplier and DoubleSupplier<jupyter_code>IntSupplier supplier = () -> 42;
System.out.println(supplier.getAsInt());<jupyter_output><empty_output><jupyter_text>Consumer is equivalent to (T) -> void<jupyter_code>Consumer<String> consumer = message -> System.out.println(message);
consumer.accept("hello consumer");<jupyter_output><empty_output><jupyter_text>IntConsumer, LongConsumer and DoubleConsumer<jupyter_code>DoubleConsumer consumer = message -> System.out.println(message);
consumer.accept(42);<jupyter_output><empty_output><jupyter_text>Predicate is equivalent to (T) -> boolean<jupyter_code>Predicate<String> predicate = text -> text.length() < 5;
System.out.println(predicate.test("hello predicate"));<jupyter_output><empty_output><jupyter_text>IntPredicate, LongPredicate and DoublePredicate<jupyter_code>DoublePredicate isPositive = v -> v >= 0;
System.out.println(isPositive.test(17.3));<jupyter_output><empty_output><jupyter_text>Function is equivalent to (T) -> U<jupyter_code>Function<String, String> fun = s -> "hello " + s;
System.out.println(fun.apply("function"));<jupyter_output><empty_output><jupyter_text>IntFunction, LongFunction and DoubleFunction<jupyter_code>IntFunction<String[]> arrayCreator = size -> new String[size];
System.out.println(arrayCreator.apply(5).length);<jupyter_output><empty_output><jupyter_text>ToIntFunction, ToLongFunction and ToDoubleFunction<jupyter_code>ToIntFunction<String> stringLength = s -> s.length();
System.out.println(stringLength.applyAsInt("hello"));<jupyter_output><empty_output><jupyter_text>UnaryOperator is equivalent to (T) -> T<jupyter_code>UnaryOperator<String> unaryOp =  s -> "hello " + s;
System.out.println(unaryOp.apply("unary operator"));<jupyter_output><empty_output><jupyter_text>IntUnaryOperator, LongUnaryOperator and DoubleUnaryOperator<jupyter_code>IntUnaryOperator unaryOp =  x -> - x;
System.out.println(unaryOp.applyAsInt(7));<jupyter_output><empty_output><jupyter_text>BiPredicate is equivalent to (T, U) -> boolean<jupyter_code>BiPredicate<String, String> predicate = (s, prefix) -> s.startsWith(prefix);
System.out.println(predicate.test("hello", "hell"));<jupyter_output><empty_output><jupyter_text>BiFunction is equivalent to (T, U) -> V<jupyter_code>BiFunction<String, String, String> fun = (s1, s2) -> s1 + " " + s2;
System.out.println(fun.apply("hello", "bi-function"));<jupyter_output><empty_output><jupyter_text>BinaryOperator is equivalent to (T, T) -> T<jupyter_code>BinaryOperator<String> binaryOp =  (s1, s2) -> s1 + " " + s2;
System.out.println(binaryOp.apply("hello", "binary operator"));<jupyter_output><empty_output><jupyter_text>IntBinaryOperator, LongBinaryOperator and DoubleBinaryOperator<jupyter_code>IntBinaryOperator binaryOp =  (a, b) -> a + b;
System.out.println(binaryOp.applyAsInt(40, 2));<jupyter_output><empty_output><jupyter_text>LambdaLambda syntax is similar to arrow part the switch syntax- with 0 parameter: () -> expression- with 1 parameter: x -> expression- with 2 or more parameters: (a, b) -> expression<jupyter_code>DoubleUnaryOperator op = x -> 2.0 * x;
System.out.println(op.applyAsDouble(2));<jupyter_output><empty_output><jupyter_text>instead of an expression, you can have statements between curly braces<jupyter_code>DoubleUnaryOperator op = x -> {
    return 2.0 * x;
  };
System.out.println(op.applyAsDouble(2));<jupyter_output><empty_output><jupyter_text>The types of the parameters are optional so you can declare them or notif you don't declare them the parameter types of the abstract methodof the interface are used<jupyter_code>DoubleUnaryOperator op = (double x) -> 2.0 * x;
System.out.println(op.applyAsDouble(2));<jupyter_output><empty_output><jupyter_text>Method referencesThere are 5 kinds of method references 1. a reference to an instance method    Seeing an instance method as a function means you have to   take the type of `this` into account, here `startsWith` as   one parameter but the function as two<jupyter_code>BiPredicate<String,String> predicate = String::startsWith;
System.out.println(predicate.test("hello", "hell"));<jupyter_output><empty_output><jupyter_text>2. a bound reference to an instance method    The value of this is fixed so the parameter of the function   are the same as the parameter of the instance method<jupyter_code>var text = "hello";
IntSupplier supplier = text::length;
System.out.println(supplier.getAsInt());<jupyter_output><empty_output><jupyter_text>3. a reference to a static method    No instance here, so the parameter of the function are the   same as the parameter of the static method<jupyter_code>ToIntFunction<String> function = Integer::parseInt;
System.out.println(function.applyAsInt("42"));<jupyter_output><empty_output><jupyter_text>4. a reference to a new instance    The parameter of the function are the same as the parameter of   the constructor. The return type is the class of the constructor<jupyter_code>record Person(String name) {}
Function<String, Person> factory = Person::new;
System.out.println(factory.apply("John"));<jupyter_output><empty_output><jupyter_text>5. a reference to a new array    Same as above, the return type is the array.<jupyter_code>IntFunction<String[]> arrayCreator = String[]::new;
System.out.println(arrayCreator.apply(2).length);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11357210179076344, 'fraction_numerical': 0.006597549481621112, 'mean_word_length': 6.175824175824176, 'pattern_counts': {'":': 0, '<': 136, '<?xml version=': 0, '>': 169, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '30', 'dir': 'jupyter-structured-clean-dedup', 'id': '382343', 'license': 'MIT', 'n_tokens_mistral': 2730, 'n_tokens_neox': 2675, 'n_words': 753, 'path': 'jupyter/chapter08-lambda.ipynb', 'repo_name': 'cynthiaZV/java-guide-1', 'size': '8488'}