Java 8 new features (a): Lambda Expressions

Original link: http://www.cnblogs.com/xzy-/p/10912756.html

March 2014 release of Java 8, there is likely to be the biggest change in the updated version of Java. The new heavyweight Java 8 brings many new features for developers, including Lambda expressions, streaming data processing, new Optional class, the new date and time API and so on. These new features to Java developers to bring the gospel, particularly in support of Lambda expressions make the program more streamlined design. This article will discuss the behavior of parameters, characteristics Lambda expressions, functional interface.

Parameterized behavior

In the process of software development, developers may encounter frequently changing requirements, so that they continue to modify the program to address the needs of these changes, resulting in project delays or even slow the progress of the project. Parameterized behavior is a kind of development model can help you cope with frequent changes in demand, simply put, is a pre-defined block of code to execute without it, pass it as a parameter to another method, so that this method of behavior this code block is parameterized.

To facilitate understanding, we have to explain the behavior parameterized by using an example. Suppose we are developing a library management system, the author of books needs to be filtered, screened specify the author of the books. The more common practice is to write a method, as the parameters of the method:

public List<Book> filterByAuthor(List<Book> books, String author) {
    List<Book> result = new ArrayList<>();
    for (Book book : books) {
        if (author.equals(book.getAuthor())) {
            result.add(book);
        }
    }
    return result;
}

Now customers need to demand change, add filters, filter by publishers, so we have to write a method again:

public List<Book> filterByPublisher(List<Book> books, String publisher) {
    List<Book> result = new ArrayList<>();
    for (Book book : books) {
        if (publisher.equals(book.getPublisher())) {
            result.add(book);
        }
    }
    return result;
}

In addition to the name of the two methods, the internal logic to achieve almost exactly the same, the only difference is that if the judgment condition, the former judge of the author, the latter judgment of the publishing house. If we have to increase customer demand, the price needs to be filtered according to the book, is not needed again to copy the above method again, will determine if conditions changed price? No! This practice violates the DRY (Do not Repeat Yourself, Do not Repeat Yourself) principle, and not conducive to post-maintenance, if you need to change the internal traversal methods to improve performance, meaning that each filterByXxx () methods need to be modified, over work load.

One possible approach is to filter conditions do higher level of abstraction, the filter condition is nothing more than some of the properties of the books (such as price, publisher, publication date, author, etc.), you can declare an interface for the construction of the filter conditions mold:

public interface BookPredicate {
    public boolean test(Book book);
}

BookPredicate only an abstract interface to Test Method (), which accepts a Book type and returns a boolean value that can be used to represent different filter conditions book.

Next we reconstruct prior to filtration method, the second parameter filterByXxx () method defined above into the interface:

public List<Book> filter(List<Book> books, BookPredicate bookPredicate) {
    List<Book> result = new ArrayList<>();
    for (Book book : books) {
        if (bookPredicate.test(book)) {
            result.add(book);
        }
    }
    return result;
}

The filter condition into BookPredicate implementation class, inner class employed herein:

// 根据作者过滤
final String author = "张三";
List<Book> result = filter(books, new BookPredicate() {
    @Override
    public boolean test(Book book) {
        return author.equals(book.getAuthor());
    }
});

// 根据图书价格过滤
final double price = 100.00D;
List<Book> result = filter(books, new BookPredicate() {
    @Override
    public boolean test(Book book) {
        return price > book.getPrice();
    }
});

What is the difference before and after the reconstruction? The method we determined if conditions replaced BookPredicate interface definition test () method for determining whether or not filtered, the filter logic books to BookPredicate interface implementation class, instead of () internal method the filter achieved by filtration, and the interface is BookPredicate parameter filter () method. The above steps, the behavior is parameterized, parameters of the method is the filtration behavior of the book (BookPredicate interface implementation class) as the filter (). Now, you can delete all filterByXxx () method, leaving only the filter () method, even if the latter very large scale data, it is necessary to change the traversal collection to improve performance, only the filter () internal method to make the appropriate changes, other business without having to modify the code.

However, BookPredicate interface to filter only for books, if you need to sort a collection of other objects (such as: user), you have to re declare an interface. There is a way that we can do it in Java Generics further abstraction:

public interface Predicate<T> {
    public boolean test(T t);
}

Now you can filter () method used in the filtration of any object.

Lambda expressions

While we carry out reconstruction of the filter () method, and abstracts the Predicate interface as the condition of the filter, but actually need to write a lot of internal classes to implement the Predicate interface. Use inner classes implement Predicate interface has many drawbacks: First, the code appears bloated, poor readability; secondly, if a local variable is used internally by the class, this variable must use the keyword final modification. In Java 8, using a Lambda expression can be further simplified internal classes:

// 根据作者过滤
List<Book> result = filter(books, book -> "张三".equals(book.getAuthor()));

// 根据图书价格过滤
List<Book> result = filter(books, book -> 100 > book.getPrice());

Lambda use only one line of code inside of conversion classes, and the code becomes more legible. Where the book -> "John Doe" .equals (book.getAuthor ()) and book -> 100> Lambda expressions book.getPrice () that we are going to study.

What is Lambda expressions

Lambda expressions (lambda expression) is an anonymous function, the λ calculus mathematics named. In Java 8 in Lambda expressions can be understood as anonymous functions, it has no name, but the parameter list, function body, such as the return type.

Lambda expressions syntax is as follows:

(parameters) -> { statements; }

Why use Lambda expressions? Front you can see, the use of inner classes in Java is very long, you want to write a lot of boilerplate code, Lambda expressions precisely in order to simplify these steps occur, it makes the code becomes clear and understandable.

How to use Lambda expressions

Lambda expressions to simplify internal class, you can use it as a shorthand way within the class, as long as there is a block of code within the class, can be transformed into Lambda expressions:

// Comparator排序
List<Integer> list = Arrays.asList(3, 1, 4, 5, 2);
list.sort(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
    }
});
// 使用Lambda表达式简化
list.sort((o1, o2) -> o1.compareTo(o2));
// Runnable代码块
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello Man!");
    }
});

// 使用Lambda表达式简化
Thread thread = new Thread(() -> System.out.println("Hello Man!"));

As can be seen, as long as the inner code block type, it can be used to simplify the expression Lambda, a simplified and legible code. Even, Comparator sort of Lambda expressions can be further simplified:

list.sort(Integer::compareTo);

The wording cited method is called, a reference method is simple wording Lambda expressions. If your Lambda expressions just call this method, it is best to use the name calling, rather than describing how to call, this can increase the readability of the code.

The method of using a reference :: delimiter, the delimiter is a reference to the first half of half type, name of the reference representation later. For example: Integer :: compareTo represents a reference type Integer, the reference name for the method compareTo.

Similar examples also use reference print elements in a set to the console:

list.forEach(System.out::println);

Functional Interface

If your curiosity makes you look Runnable interface source code, you will find that the interface is a modification @FunctionalInterface notes, this is the new annotations added in Java 8, is used to represent functional interface.

Function interface is what the hell? In the Java 8, the method is only an abstract interface that is called a function interface. If an interface is @FunctionalInterface notes marked, indicating that the interface is designed to be functional interface can have only an abstract way, if you add more abstract methods will be prompted to "Multiple non-overriding abstract methods found in interface XXX" compile time error and the like.

What function do you approach? Java8 function interface allows you to provide implementation, popular to say, you can implement the entire Lambda expression as a class interface in a manner Lambda expression is.

In addition to Runnable, Java 8 are built into many functions interface for developers to use, these interfaces located java.util.function package, we previously used Predicate interface has been included in this package, they were Predicate, Consumer and Function, because we have introduced the use of Predicate in the example of the previous books in the filter, so the next introduces the Consumer Function and usage.

Consumer
java.util.function.Consumer defines an abstract method named accept (), which accepts the object T is generic, does not return (void). If you need to access an object of type T, and perform certain actions, you can use this interface. For example, you can use it to create a forEach () method accepts a collection, and set each element do:

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

public static <T> void forEach(List<T> list, Consumer<T> consumer) {
    for(T t: list){
        consumer.accept(t);
    }
}

public static void main(String[] args) {
    List<String> list = Arrays.asList("A", "B", "C", "D");
    forEach(list, str -> System.out.println(str));
    // 也可以写成
    forEach(list, System.out::println);
}

Function

java.util.function.Function <T, R> interface defines a method called apply (), which accepts a generic target T and R of the generic object returns. If you need to define a Lambda, enter information into objects mapped to the output, you can use this interface. For example, we need to calculate a collection of books in the name of the author of each book there are a few characters (assuming that the authors of these books are Chinese):

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
    List<R> result = new ArrayList<>();
    for(T s: list){
        result.add(f.apply(s));
    }
    return result;
}

public static void main(String[] args) {
    List<Book> books = Arrays.asList(
        new Book("张三", 99.00D),
        new Book("李四", 59.00D),
        new Book("王老五", 59.00D)
    );
    List<Integer> results = map(books, book -> book.getAuthor().length());
}

Now, there is a basic understanding of Lambda expressions, you can try using Lambda expressions to refactor your code, improve code readability; use of behavioral parameters to design your program, make the program more flexible.

Reproduced in: https: //www.cnblogs.com/xzy-/p/10912756.html

Guess you like

Origin blog.csdn.net/weixin_30662539/article/details/95045696