|
1 | 1 | ## Lambdas |
2 | | -A quicker way to define functions, and looks neater (relative to the complexity of the original code). This is 'advanced java,' so prioritize understanding other 'fundamentals' before moving here. Lambdas are present in many other programming languages, so understanding it here will help you in your career. |
| 2 | +Think of lambdas as a way to store functions for later use, kind of like how we store information (numbers, text, etc) in variables so that you can easily access it later. For example, imagine if you could do this in code: when button "x" is pressed on the joystick, run this function until we let go of the button. To do this requires implementation of a lambda function. |
| 3 | + |
| 4 | +For example, we need to pass in a function into a Command* so that when the button is pressed (at any point while the code is running), Java will take that stored function and run it on the spot. We used lambdas to implement a Command-based robot, in which actions are executed in real-time by functions we store for later through the use of lamdbas. |
| 5 | + |
| 6 | +*Commands are a specific WPILib Class to help with the execution of the lambdas, which we will cover in the FRC section of this textbook. |
| 7 | + |
3 | 8 | >A sample function defined as a method: |
4 | 9 | >```java |
5 | | ->int add(int a, int b) { |
6 | | -> return a + b; |
| 10 | +>void printSequence(String a, String b) { |
| 11 | +> System.out.println(a + b); |
7 | 12 | >} |
8 | 13 | >``` |
9 | 14 |
|
10 | 15 | >A sample lambda function: |
11 | 16 | >```java |
12 | | ->//@FunctionalInterface |
13 | | ->interface MathOperations { |
14 | | -> int operate(int a, int b); |
| 17 | +>@FunctionalInterface //denotes a functional interface, in which there can only be one abstract method. Used to implement lambdas. |
| 18 | +>interface PrintOperations { |
| 19 | +> void operate(int a, int b); |
15 | 20 | >} |
16 | 21 | > |
17 | | ->// Assigning a lambda to a variable. The lambda itself is still annonomous, but the variable is named. |
18 | | ->MathOperations add = (a, b) -> {a + b}; |
19 | | ->//[fINAME] [lName] (params) return |
| 22 | +>//Creates an 'instance' of the FunctionalInterface PrintOperations, called printSequence, which is defined as a lambda function that takes in two inputs, a and b, and prints their sum. We know that a and b are both Strings because of the abstract definition of the 'operate' method. |
| 23 | +>PrintOperations printSequence = (a, b) -> { |
| 24 | +> System.out.println(a + b); |
| 25 | +>}; |
20 | 26 | > |
21 | | ->// Using it |
22 | | ->int result = add.operate(3, 4); |
23 | | ->// [type] [vName] = [lName].[OPERATE bc thats how the param is declared to lambda](params) |
24 | | ->System.out.println(result); // 7 |
| 27 | +>//Using it |
| 28 | +>printSequence.operate("Hello ", "World!"); |
| 29 | +>//Similar to methods, we use the . operator to execute a lambda function |
25 | 30 | >``` |
26 | 31 | In Lambdas, we pass the parameters to a function, without having to declare an entire method. We define a functional interface first, because like a method, if you pass parameters to it like in `(a, b)`, the lambda will not know how to handle it, and will have an error. Java needs to have declared type parameters. |
27 | | ->Notice how the parameters are defined in the `MathOperations` interface, and then again how the same parameters are being referenced from the declaration of the lambda, in `MathOperations add = (a, b) ` |
| 32 | +>Notice how the parameters are defined in the `PrintOperations` interface, and then again how the same parameters are being referenced from the declaration of the lambda, in `PrintOperations printSequence = (a, b) -> {[...]}` |
28 | 33 | After declaring the lambda, we can use the function anywhere within its scope in the code. |
29 | 34 | Right now, Lambdas may appear to be challenging and overcomplicate basic methods, such as `add`. However, we use them for concise syntax, prevent us from writing new methods and classes, and can be paired with loops, forEach. |
30 | 35 |
|
31 | | -
|
32 | | ->A more complicated application of lambdas |
33 | | ->```java |
34 | | ->nums.forEach(new java.util.function.Consumer<Integer>() { |
35 | | -> public void accept(Integer n) { |
36 | | -> System.out.println(n); |
37 | | -> } |
38 | | ->}); |
39 | | ->``` |
40 | | -> *vs* |
41 | | ->```java |
42 | | ->public interface Consumer<T> { |
43 | | -> void accept(T t); |
44 | | ->} |
45 | | ->// Using a lambda expression |
46 | | ->nums.forEach(n -> System.out.println(n)); |
47 | | ->``` |
48 | | -> Notice the difference in complexity and readibility of the code. It is clearly idenfitiable which is written in 'lambda style' and which was written as a 'basic method.' |
49 | | -
|
50 | | -
|
51 | | -For more information, check out [w3schools](https://www.w3schools.com/java/java_lambda.asp) |
52 | | -
|
53 | | -
|
54 | 36 | --- |
55 | 37 | ## Task: Practice with Lambdas |
56 | 38 |
|
@@ -88,4 +70,28 @@ public class LambdaTest { |
88 | 70 | System.out.println(reverse.modify("hello")); // olleh |
89 | 71 | } |
90 | 72 | } |
91 | | -``` |
| 73 | +``` |
| 74 | + |
| 75 | +## Applications of Lambdas |
| 76 | +There are a three types of common FunctionalInterfaces, or lambdas, that we interact with: Consumer, Supplier, and Runnable. Notice how each of these describes the action it will take. A Consumer lambda takes in a variable, with no outputs. A Supplier lambda takes in no inputs, and returns a value. A Runnable lambda is simply code that you want to run later. For example, let's say we want a function to be able to access the robot's arm angle throughout a match? Use lambdas. Want to tell Java, "Here's how we move our elevator to this height," so it can execute it on a button press? Use lambdas. |
| 77 | + |
| 78 | +Here's an example |
| 79 | +```Java |
| 80 | +>//function that takes in a supplier of our arm angle, and prints out the value |
| 81 | +>void printArmAngle(Supplier<T> armAngleSupplier) { |
| 82 | + System.out.println("Arm angle: " + armAngleSupplier.get()); |
| 83 | +} |
| 84 | +>//we can execute this as follows: |
| 85 | +>printArmAngle(() -> getArmAngle()); |
| 86 | +>//notice how we pass in a lambda function to "supply" the function printArmAngle() with a way to get the current arm angle. If we were to simply pass in a variable, that would have the same value throughout the match instead of continuosly updating by ACTIVELY getting the arm angle each time we print it. |
| 87 | +``` |
| 88 | + |
| 89 | +Here's another example |
| 90 | +```Java |
| 91 | +>//Commands.runOnce is a method that accepts a Runnable lambda, a function that we want to run later |
| 92 | +>//When this command, zeroGyro is scheduled, it will proceed to call the function setGyroAngle(double angle) with an input of 0 radians |
| 93 | +>Command zeroGyro = Commands.runOnce(() -> setGyroAngle(0)); |
| 94 | +>//Don't worry about the syntax with commands just yet. This is part of WPILib, which will be covered later |
| 95 | +> |
| 96 | +``` |
| 97 | +For more information, check out [w3schools](https://www.w3schools.com/java/java_lambda.asp) |
0 commit comments