资讯专栏INFORMATION COLUMN

Start Using Java Lambda Expressions(转载)

FullStackDeveloper / 1238人阅读

摘要:原文

Introduction (Business Case)

Lambda expressions are a new and important feature included in Java SE 8. A lambda expression provides a way to represent one method interface using an expression. A lambda expression is like a method, it provides a list of formal parameters and a body (which can be an expression or a block of code) expressed in terms of those parameters.
Lambda expressions also improve the Collection libraries. Java SE 8 added two packages related to bulk data operations for Collections, the java.util.function package, and the java.util.stream. A stream is like an iterator, but with a lot of extra functionality. Taken together, lambda expressions and streams are the biggest change to Java programming since the generics and annotations were added to the language. In this article, we will explore the power of lambda expressions and streams, from simple to complex examples.

Prerequisites

If you haven’t installed Java 8, then this is the first thing you should do to be able to work with lambdas and streams. Tools and IDE’s like NetBeans and IntelliJ IDEA support Java 8 features, such as lambda expressions, repeatable annotations, compact profiles and others.
Below are the download links for Java SE 8 and NetBeans IDE 8:

Java Platform (JDK 8): Download Java 8 from Oracle, it can also be bundled with NetBeans IDE

NetBeans IDE 8: Download NetBeans IDE from the NetBeans official site

Lambda Expressions Syntax

The basic syntax of a lambda is either:

(parameters) ->expression                or         (parameters) ->{ statements; }

The following are examples of Java lambda expressions:

1.  () -> 5    // takes no value and returns 5
2.  x -> 2 * x    // takes a number and returns the result of doubling it
3.  (x, y) -> x – y   // takes two numbers and returns their difference
4.  (int x, int y) -> x + y   // takes two integers and returns their sum
5.  (String s) -> System.out.print(s)   // takes a string and prints it to console without returning anything
Basic Lambdas Examples

Now that we have an idea of what lambdas are, let us start with some basic examples. In this section, we will see how lambda expressions affect the way we code. Having a list of players, the “for loop”, as programmers often refers to the for statement, can be translated in Java SE 8 as below:

String[] atp = {"Rafael Nadal", "Novak Djokovic", "Stanislas Wawrinka", "David Ferrer", "Roger Federer", "Andy Murray", "Tomas Berdych", "Juan Martin Del Potro"};
List players =  Arrays.asList(atp);
       
// Old looping
for (String player : players) {
     System.out.print(player + "; ");
}
       
// Using lambda expression and functional operations
players.forEach((player) -> System.out.print(player + "; "));
 
// Using double colon operator in Java 8
players.forEach(System.out::println);
As you can see, lambda expressions can reduced our code to one single line. Another example is in a graphical user interface application, when anonymous classes can be replaced with lambda expressions. The same thing happens when implementing the Runnable interface:
// Using anonymous innerclass
btn.setOnAction(new EventHandler() {
              @Override
                public void handle(ActionEvent event) {
                    System.out.println("Hello World!"); 
            }
        });
 
// Using lambda expression
btn.setOnAction(event -> System.out.println("Hello World!"));

Here is how we can write a Runnable using lambdas:

// Using anonymous innerclass 
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello world !");
    }
}).start();
 
// Using lambda expression
new Thread(() -> System.out.println("Hello world !")).start();
 
// Using anonymous innerclass
Runnable race1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello world !");
    }
};
 
// Using lambda expression
Runnable race2 = () -> System.out.println("Hello world !");
 
// Run em!
race1.run();
race2.run();

The Runnable lambda expression, which uses the block format, converts five lines of code into one statement. Going further, in the next section we will use lambdas for sorting collections.

Sorting Collections with Lambdas

In Java, the Comparator class is used for sorting collections. In the following examples, we will sort a list of players based on name, surname, name length and last name letter. We will first sort them as we did before, using anonymous inner classes, and then reduce our code using lambda expressions.
In the first example, we will sort our list by name. Using the old way, this looks like this:

String[] players = {"Rafael Nadal", "Novak Djokovic", "Stanislas Wawrinka", "David Ferrer", "Roger Federer", "Andy Murray", "Tomas Berdych", "Juan Martin Del Potro", "Richard Gasquet", "John Isner"};
 
// Sort players by name using anonymous innerclass
Arrays.sort(players, new Comparator() {
    @Override
    public int compare(String s1, String s2) {
        return (s1.compareTo(s2));
    }
});

With lambdas, the same thing can be achieved like this:

// Sort players by name using lambda expression
Comparator sortByName = (String s1, String s2) -> (s1.compareTo(s2));
 
Arrays.sort(players, sortByName);
// or this
Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));

The remaining sorts are listed below. The same as the above example, the code applies a Comparator by using an anonymous inner class and a couple of lambda expressions:

// Sort players by surname using anonymous innerclass
Arrays.sort(players, new Comparator() {
    @Override
    public int compare(String s1, String s2) {
        return (s1.substring(s1.indexOf(" ")).compareTo(s2.substring(s2.indexOf(" "))));
    }
});
 
// Sort players by surname using lambda expression
Comparator sortBySurname = (String s1, String s2) -> (s1.substring(s1.indexOf(" ")).compareTo(s2.substring(s2.indexOf(" "))));
 
Arrays.sort(players, sortBySurname);
// or this
Arrays.sort(players, (String s1, String s2) -> (s1.substring(s1.indexOf(" ")).compareTo(s2.substring(s2.indexOf(" ")))));
 
// Sort players by name lenght using anonymous innerclass
Arrays.sort(players, new Comparator() {
    @Override
    public int compare(String s1, String s2) {
        return (s1.length() - s2.length());
    }
});
 
// Sort players by name lenght using lambda expression
Comparator sortByNameLenght = (String s1, String s2) -> (s1.length() - s2.length());
 
Arrays.sort(players, sortByNameLenght);
// or this
Arrays.sort(players, (String s1, String s2) -> (s1.length() - s2.length()));
 
// Sort players by last letter using anonymous innerclass
Arrays.sort(players, new Comparator() {
    @Override
    public int compare(String s1, String s2) {
        return (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));
    }
});
 
// Sort players by last letter using lambda expression
Comparator sortByLastLetter = (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));
Arrays.sort(players, sortByLastLetter);
// or this
Arrays.sort(players, (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1)));

That’s all, pretty straightforward. We will explore more lambdas capabilities in the next section, where we will combine them with streams.

Working with Lambdas and Streams

Streams are wrappers around collections that use lambdas pervasively. They support many operations that use lambdas, like map, filter, limit, sorted, count, min, max, sum, collect and others. Also, streams use lazy evaluation and they are not actually reading all the data and methods like getFirst() can end the stream. In the next examples, we will explore what lambdas and streams can do. We created a Person class and use this class to add some data to a list that will be used in further streams operations. The Person class is just a simple POJO:

public class Person {
 
private String firstName, lastName, job, gender;
private int salary, age;
 
public Person(String firstName, String lastName, String job, String gender, int age, int salary)       {
          this.firstName = firstName;
          this.lastName = lastName;
          this.gender = gender;
          this.age = age;
          this.job = job;
          this.salary = salary;
}
// Getter and Setter 
. . . . .   
}          

Going further, we will create two lists, both containing Person objects:

            List javaProgrammers = new ArrayList() {
            {
                add(new Person("Elsdon", "Jaycob", "Java programmer", "male", 43, 2000));
                add(new Person("Tamsen", "Brittany", "Java programmer", "female", 23, 1500));
                add(new Person("Floyd", "Donny", "Java programmer", "male", 33, 1800));
                add(new Person("Sindy", "Jonie", "Java programmer", "female", 32, 1600));
                add(new Person("Vere", "Hervey", "Java programmer", "male", 22, 1200));
                add(new Person("Maude", "Jaimie", "Java programmer", "female", 27, 1900));
                add(new Person("Shawn", "Randall", "Java programmer", "male", 30, 2300));
                add(new Person("Jayden", "Corrina", "Java programmer", "female", 35, 1700));
                add(new Person("Palmer", "Dene", "Java programmer", "male", 33, 2000));
                add(new Person("Addison", "Pam", "Java programmer", "female", 34, 1300));
            }
        };
 
        List phpProgrammers = new ArrayList() {
            {
                add(new Person("Jarrod", "Pace", "PHP programmer", "male", 34, 1550));
                add(new Person("Clarette", "Cicely", "PHP programmer", "female", 23, 1200));
                add(new Person("Victor", "Channing", "PHP programmer", "male", 32, 1600));
                add(new Person("Tori", "Sheryl", "PHP programmer", "female", 21, 1000));
                add(new Person("Osborne", "Shad", "PHP programmer", "male", 32, 1100));
                add(new Person("Rosalind", "Layla", "PHP programmer", "female", 25, 1300));
                add(new Person("Fraser", "Hewie", "PHP programmer", "male", 36, 1100));
                add(new Person("Quinn", "Tamara", "PHP programmer", "female", 21, 1000));
                add(new Person("Alvin", "Lance", "PHP programmer", "male", 38, 1600));
                add(new Person("Evonne", "Shari", "PHP programmer", "female", 40, 1800));
            }
        };

Let’s now use the forEach method to iterate the above lists:

System.out.println("Show programmers names:");
javaProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
phpProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
We will now use the same forEach method and try to increase programmer’s salary by 5%:
System.out.println("Increase salary by 5% to programmers:");
Consumer giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary());
 
javaProgrammers.forEach(giveRaise);
phpProgrammers.forEach(giveRaise);
 
Another useful method is the filter method. To make use of that, let’s show PHP programmers that earn more than $1,400:
System.out.println("Show PHP programmers that earn more than $1,400:")
phpProgrammers.stream()
          .filter((p) -> (p.getSalary() > 1400))
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
We can also define filters and then reuse them in further operations:
// Define some filters
Predicate ageFilter = (p) -> (p.getAge() > 25);
Predicate salaryFilter = (p) -> (p.getSalary() > 1400);
Predicate genderFilter = (p) -> ("female".equals(p.getGender()));
 
System.out.println("Show female PHP programmers that earn more than $1,400 and are older than 24 years:");
phpProgrammers.stream()
          .filter(ageFilter)
          .filter(salaryFilter)
          .filter(genderFilter)
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
 
// Reuse filters
System.out.println("Show female Java programmers older than 24 years:");
javaProgrammers.stream()
          .filter(ageFilter)
          .filter(genderFilter)
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
            
Results can also be limited, if we use the limit method:
System.out.println("Show first 3 Java programmers:");
javaProgrammers.stream()
          .limit(3)
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
 
System.out.println("Show first 3 female Java programmers:");
javaProgrammers.stream()
          .filter(genderFilter)
          .limit(3)
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));

What about sorting? Can we do that with streams? The answer is yes, we can. In the examples below, we will sort Java programmers by name and salary, collect them into a list and then show the list:

System.out.println("Sort and show the first 5 Java programmers by name:");
List sortedJavaProgrammers = javaProgrammers
          .stream()
          .sorted((p, p2) -> (p.getFirstName().compareTo(p2.getFirstName())))
          .limit(5)
          .collect(toList());
 
sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));
 
System.out.println("Sort and show Java programmers by salary:");
sortedJavaProgrammers = javaProgrammers
          .stream()
          .sorted((p, p2) -> (p.getSalary() - p2.getSalary()))
          .collect(toList());
 
sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));

If we are interested only in the lowest and the highest salary, faster than sorting and choosing the first (or the last) are the min and max methods:

System.out.println("Get the lowest Java programmer salary:");
Person pers = javaProgrammers
          .stream()
          .min((p1, p2) -> (p1.getSalary() - p2.getSalary()))
          .get()
 
System.out.printf("Name: %s %s; Salary: $%,d.", pers.getFirstName(), pers.getLastName(), pers.getSalary())
 
System.out.println("Get the highest Java programmer salary:");
Person person = javaProgrammers
          .stream()
          .max((p, p2) -> (p.getSalary() - p2.getSalary()))
          .get()
 
System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary())

We have already seen above an example on how the collect method works. Combined with the map method, we can use collect method to gather our results in a String, in a Set or in a TreeSet:

System.out.println("Get PHP programmers first name to String:");
String phpDevelopers = phpProgrammers
          .stream()
          .map(Person::getFirstName)
          .collect(joining(" ; "));    // this can be used as a token in further operations
 
System.out.println("Get Java programmers first name to Set:");
Set javaDevFirstName = javaProgrammers
          .stream()
          .map(Person::getFirstName)
          .collect(toSet());
 
System.out.println("Get Java programmers last name to TreeSet:");
TreeSet javaDevLastName = javaProgrammers
          .stream()
          .map(Person::getLastName)
          .collect(toCollection(TreeSet::new));
 
Streams can also be parallel. An example is below:
System.out.println("Calculate total money spent for paying Java programmers:");
int totalSalary = javaProgrammers
          .parallelStream()
          .mapToInt(p -> p.getSalary())
          .sum();
To obtain various summary data about the elements of a stream we can use the summaryStatistics method. Going further, we then have access to methods like getMax, getMin, getSum or getAverage:
//Get count, min, max, sum, and average for numbers
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
IntSummaryStatistics stats = numbers
          .stream()
          .mapToInt((x) -> x)
          .summaryStatistics();
 
System.out.println("Highest number in List : " + stats.getMax());
System.out.println("Lowest number in List : " + stats.getMin());
System.out.println("Sum of all numbers : " + stats.getSum());
System.out.println("Average of all numbers : " + stats.getAverage()); 

That’s all, hope you like it!

Conclusion

In this article, we have discovered different ways of using lambda expressions, starting from basic examples to complex ones, where we used lambdas with streams. Moreover, we have also learned how to use lambda expressions with the Comparator class for sorting Java collections.

原文:Start Using Java Lambda Expressions

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64791.html

相关文章

  • Java8 新特性:Lambda表达式和虚拟扩展方法标注

    摘要:摘要添加了表达式闭包和特性支持,包括方法的引用,增强类型推断,和虚拟扩展方法。围绕的语言功能支持包括虚拟扩展方法,这将使接口的源代码和二进制兼容的方式演变升级。 Author:Joseph D. Darcy Organization:Oracle Owner:Brian Goetz Created:2011/11/1 Updated:2013/2/21 Type:Feature Sta...

    UsherChen 评论0 收藏0
  • 深入浅出 Java 8 Lambda 表达式

    摘要:在支持一类函数的语言中,表达式的类型将是函数。匿名函数的返回类型与该主体表达式一致如果表达式的主体包含一条以上语句,则表达式必须包含在花括号中形成代码块。注意,使用表达式的方法不止一种。 摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等。本文系 OneAPM 工程师编译整理。 Java 是一流的面向对象语言,除了部分简...

    wdzgege 评论0 收藏0
  • Java Lambda表达式入门

    摘要:表达式还增强了集合库。和前面的示例一样先使用匿名内部类来排序然后再使用表达式精简我们的代码。使用旧的方式代码如下所示使用匿名内部类根据排序使用可以通过下面的代码实现同样的功能使用排序也可以采用如下形式其他的排序如下所示。 本文转自:http://blog.csdn.net/renfufei...转载请注明出处 原文链接: Start Using Java Lambda Expressi...

    youkede 评论0 收藏0
  • Java Lambda 表达式(又名闭包 (Closure)/ 匿名函数 ) 笔记

    摘要:表达式又名闭包匿名函数笔记根据终于在中引入了表达式。函数式接口要介绍中表达式的实现,需要知道什么是函数式接口。但同样需要保证外部的自由变量不能在表达式中被改变。 Java Lambda 表达式(又名闭包 (Closure)/ 匿名函数 ) 笔记 根据 JSR 335, Java 终于在 Java 8 中引入了 Lambda 表达式。也称之为闭包或者匿名函数。 showImg(https...

    fou7 评论0 收藏0

发表评论

0条评论

FullStackDeveloper

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<