Summary : This article focuses on the background and usage of the Java8 lambda expression, and the difference between a lambda expression and an anonymous class. This article is compiled and collated by OneAPM engineers.
Java is a first-class object-oriented language, except for some simple data types, everything in Java is an object, even if an array is an object, and the instance created by each class is also an object. A function or method defined in Java cannot be completely independent, nor can a method be used as a parameter or a method to be returned to an instance.
Starting with Swing, we always pass the function function to the method through anonymous classes, the following is the old version of the event listener code:
someObject.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
//Event listener implementation goes here...
}
});
In the above example, in order to add custom code to the Mouse listener, we define an anonymous inner class Mouseadapter and create its object, in this way, we pass some function functions to the Addmouselistener method.
In short, it's not easy to pass a normal method or function as a parameter in Java, and Java 8 adds a new language-level feature called a Lambda expression .
Why does Java need a LAMBDA expression?
If you neglect the annotations (Annotations), generics (generics) and other features, it has not changed much since the Java language was born. Java has always been committed to preserving its object-oriented features, and after using functional languages such as JavaScript, how Java emphasizes its object-oriented nature and how the data types of the source layer are strictly becoming clearer. In fact, the function is not important to Java, in the Java world, functions cannot exist independently.
In functional programming languages, functions are class-one citizens, they can exist independently, you can assign them to a variable, or pass them as arguments to other functions. JavaScript is the most typical functional programming language. Click here and here to get a clear picture of the benefits of this functional language for JavaScript. Functional languages provide a powerful feature-closures, which have many advantages over traditional programming methods, and closures are a callable object that records information from the scope in which it was created. Java now provides the closest concept of closure to a lambda expression, although there is a significant difference between a closure and a lambda expression, but at least the lambda expression is a good substitute for closures.
In Steve Yegge's spicy and humorous blog post, describing how the Java world is strictly noun-centric, if you haven't read it, read it, write it very funny, and properly explain why Java is introducing LAMBDA expressions.
Lambda expressions add missing functional programming features to Java, allowing us to treat functions as a class citizen. Although not entirely true, we will soon see the difference between Lambda and closure, but infinitely close to closures. In a language that supports a class of functions, the type of the LAMBDA expression will be a function. However, in Java, Lambda expressions are objects that must be attached to a particular type of object-the functional interface (functional interface). We will describe the functional interface in detail later in this article.
Mario Fusco's clear-minded article explains why Java needs Lambda expressions. He explains why modern programming languages must contain features such as closures.
Introduction to Lambda expressions
A LAMBDA expression is an anonymous function (which is not entirely true for Java, but now it is considered), simply, it is a method that is not declared, that is, there is no access modifier, a return value declaration, and a name.
You can think of it as a shorthand and write it where you need to use a method. When a method is used only once and the definition is brief, this shorthand substitution is especially effective, so you don't have to bother writing declarations and methods in the class.
Lambda expressions in Java are typically written using(argument) -> (body)syntax, such as:
(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }
Here are some examples of LAMBDA expressions:
(int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42 () -> { return 3.1415 };
Structure of a LAMBDA expression
Let's look at the structure of a LAMBDA expression.
- A LAMBDA expression can have 0 or more parameters
- The type of the parameter can be either explicitly declared or inferred from the context. For example:(int a)the same as the(a)effect
- All parameters need to be enclosed in parentheses, and the parameters are separated by commas. For example:(a, b)or(int a, int b)or(String a, int b, float c)
- An empty parenthesis indicates that the parameter set is empty. For example:() -> 42
- When there is only one argument, and its type is inferred, parentheses () can be omitted. For example:a -> return a*a
- The body of a LAMBDA expression can contain 0 or more statements
- If the body of a LAMBDA expression has only one statement, the curly brace {} can be omitted. The return type of an anonymous function is consistent with the body expression
- If the body of a LAMBDA expression contains more than one statement, the expression must be enclosed in curly braces {} (forming a code block). The return type of the anonymous function is the same as the return type of the code block, or null if no return
What is a functional interface
In Java, an interface of type Marker (tag) is an interface that has no method or property declaration, and simply, the Marker interface is an empty interface. Similarly, a functional interface is an interface that contains only an abstract method declaration.
java.lang.Runnableis a functional interface, only one method is declared in the Runnable interface,void run()Similarly, the ActionListener interface is a functional interface, and we use an anonymous inner class to instantiate the object of the functional interface, which can be simplified by using a LAMBDA expression.
Each lambda expression can be implicitly assigned to a functional interface, for example, we can create a reference to the Runnable interface through a lambda expression.
Runnable r = (), System.out.println ("Hello World");
When you do not specify a functional interface, the compiler automatically interprets this conversion:
new Thread(
() -> System.out.println("hello world")
).start();
Therefore, in the above code, the compiler automatically infers thatpublic Thread(Runnable r) { }the LAMBDA expression is assigned to the Runnable interface based on the constructor signature of the thread class.
Here are some Lambda expressions and their functional interfaces:
Consumer<Integer> c = (int x) -> { System.out.println(x) };
BiConsumer<Integer, String> b = (Integer x, String y) -> System.out.println(x + " : " + y);
Predicate<String> p = (String s) -> { s == null };
@FunctionalInterface is a new interface added to Java 8 to indicate that the interface type declaration is a functional interface defined by the Java language Specification. Java 8 also declares some functional interfaces that Lambda expressions can use, and when you annotate an interface that is not a valid functional interface, you can use @FunctionalInterface to resolve compiler-level errors.
The following is a custom functional interface: @FunctionalInterface public interface Workerinterface {
Public void dosomework ();}
By definition, a functional interface can have only one abstract method, and if you try to add a second abstract method, a compile-time error will be thrown. For example:
@FunctionalInterface
public interface WorkerInterface {
public void doSomeWork();
public void doSomeMoreWork();
}
Error:
Unexpected @FunctionalInterface annotation
@FunctionalInterface ^ WorkerInterface is not a functional interface multiple
non-overriding abstract methods found in interface WorkerInterface 1 error
Once the functional interface is well defined, we can use it in the API while taking advantage of LAMBDA expressions. For example:
// Define a functional interface
@FunctionalInterface
public interface WorkerInterface {
public void doSomeWork ();
}
public class WorkerInterfaceTest {
public static void execute (WorkerInterface worker) {
worker.doSomeWork ();
}
public static void main (String [] args) {
// invoke doSomeWork using Annonymous class
execute (new WorkerInterface () {
@Override
public void doSomeWork () {
System.out.println ("Worker invoked using Anonymous class");
}
});
// invoke doSomeWork using Lambda expression
execute (()-> System.out.println ("Worker invoked using Lambda expression"));
}
}
Output:
Worker invoked using Anonymous class Worker invoked using Lambda expression
In the example above, we created a custom functional interface and used it with a LAMBDA expression. The Execute () method can now use a LAMBDA expression as an argument.
Examples of LAMBDA expressions
The best way to learn LAMBDA expressions is to learn examples.
Threads can be initialized by the following methods:
// Old method:
new Thread (new Runnable () {
@Override
public void run () {
System.out.println ("Hello from thread");
}
}). start ();
//new method:
new Thread (
()-> System.out.println ("Hello from thread")
) .start ();
Event handling can be resolved using a LAMBDA expression in Java 8. In the following code, we will add ActionListener to a UI component using both new and old methods:
//Old way: button.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked using old fashion code!");
}
}); //New way: button.addActionListener( (e) -> {
System.out.println("The button was clicked. From Lambda expressions !");
});
The function of the following code is to print out all the elements in the given array. Note that there are more than one way to use LAMBDA expressions. In the following example, we first create a lambda expression with common arrow syntax, and then use the new double colon (::) operator of Java 8 to convert a regular method into a lambda expression:
//Old way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for(Integer n: list) {
System.out.println(n);
}
//New way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.forEach(n -> System.out.println(n));
//or we can use :: double colon operator in Java 8
list.forEach(System.out::println);
In the following example, we use the assertion (predicate) functional interface to create a test and print all the elements that pass the test, so that you can use a LAMBDA expression to prescribe some logic and make a difference on that basis:
import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class Main { public static void main(String [] a) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
System.out.println("Print all numbers:");
evaluate(list, (n)->true);
System.out.println("Print no numbers:");
evaluate(list, (n)->false);
System.out.println("Print even numbers:");
evaluate(list, (n)-> n%2 == 0 );
System.out.println("Print odd numbers:");
evaluate(list, (n)-> n%2 == 1 );
System.out.println("Print numbers greater than 5:");
evaluate(list, (n)-> n > 5 );
} public static void evaluate(List<Integer> list, Predicate<Integer> predicate) { for(Integer n: list) { if(predicate.test(n)) {
System.out.println(n + " ");
}
}
}
}
Output:
Print all numbers: 1 2 3 4 5 6 7
Print no numbers:
Print even numbers: 2 4 6
Print odd numbers: 1 3 5 7
Print numbers greater than 5: 6 7
The following example uses a LAMBDA expression to print the square of each element in a numeric value, and note that we use the. Stream () method to convert a regular array to a stream. Java 8 adds some awesome streaming APIs. The Java.util.stream.Stream interface contains a number of useful methods to produce magical effects in conjunction with LAMBDA expressions. We pass the LAMBDA expression to thex -> x*xmap () method, which is used for all elements in the stream. After that, we use the ForEach method to print all the elements in the data:
//Old way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
for(Integer n : list) {
int x = n * n;
System.out.println(x);
}
//New way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
list.stream().map((x) -> x*x).forEach(System.out::println);
The following example calculates the sum of squares of each element in a given number. Note that a LAMBDA expression can achieve this function with just one statement, which is also a primary example of MapReduce. We use map () to square each element and then use reduce () to count all the elements into one value:
//Old way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
int sum = 0;
for(Integer n : list) {
int x = n * n;
sum = sum + x;
}
System.out.println(sum);
//New way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
int sum = list.stream().map(x -> x*x).reduce((x,y) -> x + y).get();
System.out.println(sum);
The difference between a LAMBDA expression and an anonymous class
One of the big differences between using anonymous classes and LAMBDA expressions is the use of keywords. For anonymous classes, the keywordsthisare interpreted as anonymous classes, and for lambda expressions, the key wordsthisare interpreted as external classes that write on lambda.
Another difference between a LAMBDA expression and an anonymous class is the way they are compiled. The Java compiler compiles lambda expressions and translates them into private functions inside the class, which dynamically binds the method with the new instructions in Java 7invokedynamic, and about how Java compiles lambda expressions into bytecode, and Tal Weiss writes a good article.
That's it, kiss!
Mark Reinhold, chief architect of Oracle, describes LAMBDA expressions as the biggest boost to the programming model-more powerful than generics (generics). It is true that lambda expressions give Java programmers a feature that is missing from other functional programming languages, and that, in combination with features such as virtual extension methods, lambda expressions can write some excellent code.
Hopefully this article will let you know all about the new features of Java 8.
Original address: http://viralpatel.net/blogs/Lambda-expressions-java-tutorial/
OneAPM for Java is able to perform application performance management and monitoring within all Java applications, including visibility of code-level performance issues, rapid identification and traceability of performance bottlenecks, real user experience monitoring, server monitoring, and end-to-end application management. To read more technical articles, please visit the OneAPM official blog.
Java 8 LAMBDA expression