520 likes | 552 Views
„Lambda expressions, Optional ”. Lambda expression. New in Java 8. Java lambda expression is a function which can be created without belonging to any class. Java lambda expression can be passed around as if it was an object and executed on demand.
E N D
Lambda expressions, Optional Lambda expression New in Java 8. Java lambda expression is a function which can be created without belonging to any class. Java lambda expression can be passed around as if it was an object and executed on demand. Java lambda expressions are commonly used to implement simple event listeners / callbacks, or in functional programming (see Java Streams API) Let’s see this on example…
Lambda expressions, Optional Lambda expression as a single method interface Let's look for the classic implementation of a listener in Java 7. This Java interface defines a single method which is called whenever the state changes (in whatever is being observed).
Lambda expressions, Optional Lambda expression as a single method interface In Java 7 you would have to implement this interface in order to listen for state changes. Imagine you have a class calledStateOwnerwhich can register state event listeners. Here is an example:
Lambda expressions, Optional Lambda expression as a single method interface Let’s add implementation of event listener:
Lambda expressions, Optional Lambda expression as a single method interface Rewrite it in Java 8 using lambda expression: Below statement is out lambda expression:
Lambda expressions, Optional Lambda expression as a single method interface The lambda expression is matched against the parameter type of the addStateListener() method's parameter. If the lambda expression matches the parameter type (in this case the StateChangeListener interface), then the lambda expression is turned into a function that implements the same interface as that parameter. Java lambda expressions can only be used where the type they are matched against is a single method interface. In the example above, a lambda expression is used as parameter where the parameter type was the StateChangeListener interface. This interface only has a single method. Thus, the lambda expression is matched successfully against that interface.
Lambda expressions, Optional Lambda expression- type inference With lambda expressions the type can often be inferred from the surrounding code. For instance, the interface type of the parameter can be inferred from the method declaration of the addStateListener() method (the single method on the StateChangeListener interface). This is called type inference. The compiler infers the type of a parameter by looking elsewhere for the type - in this case the method definition. In the lambda expression the parameter types can often be inferred too. In the example, the compiler can infer their type from the onStateChange() method declaration. Thus, the type of the parameters oldState and newState are inferred from the method declaration of the onStateChange() method.
Lambda expressions, Optional Lambda expression- parameters Since Java lambda expressions are effectively just methods, lambda expressions can take parameters just like methods. When a lambda expression takes a single parameter, you can also omit the parentheses, like this:
Lambda expressions, Optional Lambda expression- parameters If the method you match your Java lambda expression against takes multiple parameters, the parameters need to be listed inside parentheses.
Lambda expressions, Optional Lambda expression- parameter type Specifying parameter types for a lambda expression may sometimes be necessary if the compiler cannot infer the parameter types from the functional interface method the lambda is matching. Don't worry, the compiler will tell you when that is the case.
Lambda expressions, Optional Lambda expression- body The body of a lambda expression, and thus the body of the function / method it represents, is specified to the right of the -> in the lambda declaration. If your lambda expression needs to consist of multiple lines, you can enclose the lambda function body inside the { } bracket.
Lambda expressions, Optional Lambda expression- returning value You can return values from Java lambda expressions, just like you can from a method. You just add a return statement to the lambda function body. In case all your lambda expression is doing is to calculate a return value and return it, you can specify the return value in a shorter way.
Lambda expressions, Optional Lambda expression- an object A Java lambda expression is essentially an object. You can assign a lambda expression to a variable and pass it around, like you do with any other object.
Lambda expressions, Optional Lambda expression as a single method interface- major difference Even though lambda expressions are close to anonymous interface implementations, there are a few differences that are worth noting. The major difference is, that an anonymous interface implementation can have state (member variables) whereas a lambda expression cannot. Look at this interface:
Lambda expressions, Optional Lambda expression as a single method interface- major difference This interface can be implemented using an anonymous interface implementation. This anonymous MyEventConsumer implementation can have its own internal state.
Lambda expressions, Optional Lambda expression as a single method interface- major difference Notice how the anonymous MyEventConsumer implementation now has a field named eventCount. A lambda expression cannot have such fields. A lambda expression is thus said to be stateless.
Lambda expressions, Optional Lambda expression- variable capture A Java lambda expression is capable of accessing variables declared outside the lambda function body under certain circumstances. Java lambdas can capture the following types of variables: • Local variables • Instance variables • Static variables
Lambda expressions, Optional Lambda expression- local variable The lambda body references the local variable myString which is declared outside the lambda body. This is possible if, and only if, the variable being references is "effectively final", meaning it does not change its value after being assigned. If the myString variable had its value changed later, the compiler would complain about the reference to it from inside the lambda body.
Lambda expressions, Optional Lambda expression- instance variable This captures the name instance variable of the enclosing EventConsumerImpl object. It is even possible to change the value of the instance variable after its capture - and the value will be reflected inside the lambda.
Lambda expressions, Optional Lambda expression- static variable This is not surprising, as static variables are reachable from everywhere in a Java application, provided the static variable is accessible (packaged scoped or public).
Lambda expressions, Optional Lambda expression- functional interface Functionalinterfaceisanyinterfacethathas one abstractmethod and onlythosecan be implemented by lambda expression. Therearefew of them in Java: • Function<T, R> • Consumer<T> • Predicate<T> • Supplier<T> • UnaryOperator<T> Wheneveryouseethem in methodparameters, youcanuse lambda expression.
Lambda expressions, Optional Lambda expression- functional interface Examples are in java.util.Stream
Lambda expressions, Optional Optional Java 8 has introduced a new class Optional in java.util package. It is used to represent a value is present or absent. The main advantage of this new construct is that no more too many null checks and NullPointerException. It avoids any runtime NullPointerExceptions and supports us in developing clean and neat Java APIs or Applications. Like Collections and arrays, it is also a Container to hold at most one value.
Lambda expressions, Optional Optional- creating object There are several ways of creating Optional objects. To create an empty Optional object, we simply need to use its empty static method: We can also create an Optional object with the static method of:
Lambda expressions, Optional Optional- creating object However, the argument passed to the of() method can’t be null. Otherwise, we’ll get a NullPointerException: But, in case we expect some null values, we can use the ofNullable() method:
Lambda expressions, Optional Optional- checking value When we have an Optional object returned from a method or created by us, we can check if there is a value in it or not with the isPresent() method: This method returns true if the wrapped value is not null.
Lambda expressions, Optional Optional- checking value The ifPresent() method enables us to run some code on the wrapped value if it’s found to be non-null. Before Optional, we’d do: Let us now look at how the above code could be refactored in Java 8.
Lambda expressions, Optional Optional- checking value Do you remember functional interface? ifPresent method is using it:
Lambda expressions, Optional Optional- returning value There are several ways of returning values from Optional objects. The get() method:
Lambda expressions, Optional Optional- returning value The orElse() method is used to retrieve the value wrapped inside an Optional instance. It takes one parameter which acts as a default value. The orElse() method returns the wrapped value if it’s present and its argument otherwise:
Lambda expressions, Optional Optional- returning value The orElseGet() method is similar to orElse(). However, instead of taking a value to return if the Optional value is not present, it takes a supplier functional interface which is invoked and returns the value of the invocation:
Lambda expressions, Optional Optional- returning value The orElseThrow() method follows from orElse() and orElseGet() and adds a new approach for handling an absent value. Instead of returning a default value when the wrapped value is not present, it throws an exception:
Lambda expressions, Optional Optional- difference between orElse and orElseGet The difference between orElse() and orElseGet() is not clear. As a matter of fact, these two methods give the impression that they overlap each other in functionality. However, there’s a subtle but very important difference between the two which can affect the performance of our code drastically if not well understood. Let’s create a method called getMyDefault() in the test class which takes no arguments and returns a default value:
Lambda expressions, Optional Optional- difference between orElse and orElseGet Let’s see two tests and observe their side effects to establish both where orElse() and orElseGet() overlap and where they differ:
Lambda expressions, Optional Optional- difference between orElse and orElseGet We wrap a null text inside an Optional object and we attempt to get the wrapped value using each of the two approaches. The side effect is as below: The getMyDefault() method is called in each case. It so happens that when the wrapped value is not present, then both orElse() and orElseGet() work exactly the same way.
Lambda expressions, Optional Optional- difference between orElse and orElseGet Now let’s run another test where the value is present and ideally, the default value should not even be created:
Lambda expressions, Optional Optional- difference between orElse and orElseGet We are no longer wrapping a null value and the rest of the code remains the same. Now let’s take a look at the side effect of running this code:
Lambda expressions, Optional Optional- difference between orElse and orElseGet Notice that when using orElseGet() to retrieve the wrapped value, the getMyDefault() method is not even invoked since the contained value is present. However, when using orElse(), whether the wrapped value is present or not, the default object is created. So in this case, we have just created one redundant object that is never used. In this simple example, there is no significant cost to creating a default object, as the JVM knows how to deal with such. However, when a method such as getMyDefault() has to make a web service call or even query a database, then the cost becomes very obvious.
Lambda expressions, Optional Optional- filter We can run an inline test on our wrapped value with the filter method. It takes a predicate as an argument and returns an Optional object. If the wrapped value passes testing by the predicate, then the Optional is returned as-is.However, if the predicate returns false, then it will return an empty Optional:
Lambda expressions, Optional Optional- map We can use a similar syntax to transform the Optional value with the map() method:
Lambda expressions, Optional Optional- map In this example, we wrap a list of strings inside an Optional object and use its map method to perform an action on the contained list. The action we perform is to retrieve the size of the list. The map method returns the result of the computation wrapped inside Optional. We then have to call an appropriate method on the returned Optional to retrieve its value.
Lambda expressions, Optional Optional- chaining We can chain map and filter together to do something more powerful:
Lambda expressions, Optional Optional- flatMap Just like the map() method, we also have the flatMap() method as an alternative for transforming values. The difference is that map transforms values only when they are unwrapped whereas flatMap takes a wrapped value and unwraps it before transforming it. Let’s see this on example:
Lambda expressions, Optional Optional- flatMap We would normally create such an object and wrap it in an Optional object just like we did with String. Alternatively, it can be returned to us by another method call:
Lambda expressions, Optional Optional- flatMap Notice now that when we wrap a Person object, it will contain nested Optional instances:
Lambda expressions, Optional Optional- flatMap Here, we’re trying to retrieve the name attribute of the Person object to perform an assertion. Note how we achieve this with map() method in the third statement and then notice how we do the same with flatMap() method afterwards.
Lambda expressions, Optional Optional- where Finally, let’s see a tempting, however dangerous, way to use Optionals: passing an Optional parameter to a method. Imagine we have a list of Person and we want a method to search through that list for people having a given name. Also, we would like that method to match entries with at least a certain age, if it’s specified. With this parameter being optional, we come with this method:
Lambda expressions, Optional Optional- where Then, we release our method and another developer tries to use it: Now, the developer executes its code and gets a NullPointerException. There we are, having to null check our optional parameter, which defeats our initial purpose in wanting to avoid this kind of situation.
Lambda expressions, Optional Optional- where Here are some possibilities we could have done to handle it better: