A preliminary study on Java Lambda expressions
Foreword
This article was inspired by Trisha Gee’s keynote speech Refactoring to Java 8 at JavaOne 2016.
Java 8 has been released for more than two years, but many people are still using JDK7. For enterprises, being cautious in technology is not necessarily a bad thing, but for personal learning, if you do not learn new technologies, you are likely to be abandoned by them. An important change in Java 8 is the introduction of Lambda expression, which sounds awesome. Even though I don’t know what Lambda expression is, I still feel that it is awesome. Don't be afraid, at the language level, Lambda expression is just a new syntax. With it, Java will open the door to functional programming.
Why do you need Lambda expressions
Don’t worry about what is Lambda expression and what is functional programming. Let’s first take a look at the conveniences brought by the new syntax features of Java 8. I believe you will remember them.
Before there is a Lambda expression, to create a new thread, you need to write like this:
new Thread(new Runnable(){ @Override public void run(){ System.out.println("Thread run()"); } }).start();
After there is a Lambda expression, you can write like this:
new Thread( () -> System.out.println("Thread run()") ).start();
As you can see, the previously useless template code is gone! As shown above, a common use of Lambda expressions is to replace (some) anonymous inner classes, but the role of Lambda expressions is not limited to this.
Principle of Lambda Expression
If you are new to Lambda expression, you may think it is magical: you can directly define a function without declaring the name of the class or method. But in fact, this is just a little trick provided by the compiler, and the principle behind it is not difficult to understand. The following are several possible writing forms of Lambda expressions:
Runnable run = () -> System.out.println("Hello World");// 1ActionListener listener = event -> System.out.println("button clicked");// 2Runnable multiLine = () -> {// 3 System.out.println("Hello "); System.out.println("World"); }; BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5
You can find from the above example:
Lambda expressions have types, and the left side of the assignment operation is the type. The type of the lambda expression is actually the type of the corresponding interface.
Lambda expressions can contain multiple lines of code, and you need to use curly brackets to enclose the code block, just like writing a function body.
Most of the time, the type can be omitted from the parameter list of a lambda expression, as in Listings 2 and 5. This is due to javac's type derivation mechanism, the compiler can deduce type information based on context.
In fact, each Lambda expression is the abbreviation of the original anonymous inner class, which implements a functional interface (Functional Interface). The so-called functional interface refers to an interface with the @FunctionalInterface annotation added and only one interface function inside. Java is a strongly typed language. Regardless of whether it is explicitly specified, each variable and object must have a clear type. When not explicitly specified, the compiler will try to determine the type. The type of the lambda expression is the type of the corresponding function interface.
Lambda expressions and Stream
Another important use of Lambda expressions is to use them with Stream. Stream is a sequence of elements supporting sequential and parallel aggregate operations. Stream is a sequence of elements that supports various operations on these elements, and these operations are specified through Lambda expressions. You can think of a Stream as a view of a Java Collection, just like an iterator is a view of a container (but the Stream does not modify the contents of the container). The following examples show common uses of Stream.
Example 1
Suppose you need to select a string starting with a number from a string list and output it. Before Java 7, you needed to write like this:
List<String> list = Arrays.asList("1one", "two", "three", "4four");for(String str : list){ if(Character.isDigit(str.charAt(0))){ System.out.println(str); } }
And in Java 8, you can write like this:
List<String> list = Arrays.asList("1one", "two", "three", "4four"); list.stream()// 1.得到容器的Steam .filter(str -> Character.isDigit(str.charAt(0)))// 2.選出以數(shù)字開頭的字符串 .forEach(str -> System.out.println(str));// 3.輸出字符串
The above code first 1 . Call the List.stream() method to get the Stream of the container, 2. Then call the filter() method to filter out the string starting with a number, 3. Finally, call the forEach() method to output the result.
Using Stream has two obvious benefits:
The template code is reduced, only Lambda expressions are used to specify the required operations, and the code semantics are clearer and easier to read.
Change the external iteration to the internal iteration of Stream, which facilitates the JVM itself to optimize the iteration process (for example, it can be iterated in parallel).
Example 2
Suppose you need to select all strings that do not start with a number from a list of strings, convert them to uppercase, and put the results into a new collection. The code written in Java 8 is as follows:
List<String> list = Arrays.asList("1one", "two", "three", "4four"); Set<String> newList = list.stream()// 1.得到容器的Stream .filter(str -> !Character.isDigit(str.charAt(0)))// 2.選出不以數(shù)字開頭的字符串 .map(String::toUpperCase)// 3.轉(zhuǎn)換成大寫形式 .collect(Collectors.toSet());// 4.生成結(jié)果集
上述代碼首先1. 調(diào)用List.stream()方法得到容器的Stream,2. 然后調(diào)用filter()方法選出不以數(shù)字開頭的字符串,3. 之后調(diào)用map()方法將字符串轉(zhuǎn)換成大寫形式,4. 最后調(diào)用collect()方法將結(jié)果轉(zhuǎn)換成Set。這個例子還向我們展示了方法引用(method references,代碼中標(biāo)號3處)以及收集器(Collector,代碼中標(biāo)號4處)的用法,這里不再展開說明。
通過這個例子我們看到了Stream鏈?zhǔn)讲僮鳎炊鄠€操作可以連成一串。不用擔(dān)心這會導(dǎo)致對容器的多次迭代,因為不是每個Stream的操作都會立即執(zhí)行。Stream的操作分成兩類,一類是中間操作(intermediate operations),另一類是結(jié)束操作(terminal operation),只有結(jié)束操作才會導(dǎo)致真正的代碼執(zhí)行,中間操作只會做一些標(biāo)記,表示需要對Stream進(jìn)行某種操作。這意味著可以在Stream上通過關(guān)聯(lián)多種操作,但最終只需要一次迭代。如果你熟悉Spark RDD,對此應(yīng)該并不陌生。
結(jié)語
Java 8引入Lambda表達(dá)式,從此打開了函數(shù)式編程的大門。如果你之前不了解函數(shù)式編程,不必糾結(jié)于這個概念。編程過程中簡潔明了的書寫形式以及強(qiáng)大的Stream API會讓你很快熟悉Lambda表達(dá)式的。
本文只對Java Lambda表達(dá)式的基本介紹,希望能夠激發(fā)讀者對Java函數(shù)式編程的興趣。如果本文能夠讓你覺得Lambda表達(dá)式很好玩,函數(shù)式編程很有趣,并產(chǎn)生了進(jìn)一步學(xué)習(xí)的欲望,那就再好不過了。文末參考文獻(xiàn)中列出了一些有用的資源。
參考文獻(xiàn)
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
http://www.slideshare.net/trishagee/refactoring-to-java-8-devoxx-uk
《Java 8函數(shù)式編程 [英]沃伯頓》
https://www.oracle.com/javaone/speakers.html#gee

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)
