Java高级程序设计

Lambda 表达式

先举个例子

class Employee{
    private Integer id;
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
}

public class JavaSort {
    public static void main(String[] args) {
        ArrayList<Employee> employees = getUnsortedEmployeeList();
        //TODO: sort the list
    }
    //Returns an unordered list of employees
    private static ArrayList<Employee> getUnsortedEmployeeList(){ ... }
}

java.util.Collections

public static <T extends Comparable<? super T>> void sort(List<T> list)

Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface. Furthermore, all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException).

https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html

List<String> names = Arrays.asList("Alex", "Charles", "Brian", "David");
Collections.sort(names);    //[Alex, Brian, Charles, David]

Comparable employees

public class Employee implements Comparable<Employee> {
    private Integer id;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Override
    public String toString() {
        return "Employee [id=" + id + "]";
    }
    @Override
    public int compareTo(Employee o) {
        return this.getId().compareTo(o.getId());
    }
}

Sorting employees

public class JavaSort 
{
    public static void main(String[] args) 
    {
        ArrayList<Employee> employees = getUnsortedEmployeeList();
        Collections.sort(employees);
        System.out.println(employees);
    }
    //Returns an unordered list of employees
    private static ArrayList<Employee> getUnsortedEmployeeList(){ ... }
}

[E [id=13], E [id=46], E [id=80], E [id=90], E [id=93]]

java.util.Collections

public static <T> void sort(List<T> list, Comparator<? super T> c)

Sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable using the specified comparator (that is, .compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the list).

This implementation defers to the List.sort(Comparator) method using the specified list and comparator.

Interface Comparator<T>

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

A comparison function, which imposes a total ordering on some collection of objects. Comparators can be passed to a sort method (such as Collections.sort or Arrays.sort) to allow precise control over the sort order. Comparators can also be used to control the order of certain data structures (such as sorted sets or sorted maps), or to provide an ordering for collections of objects that don't have a natural ordering.

https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html

int compare(T o1, T o2)

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1,  T o2);
    ...
}

Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

Comparator for employees

Comparator<Employee> compareById = new Comparator<Employee>() {
    @Override
    public int compare(Employee o1, Employee o2) {
        return o1.getId().compareTo(o2.getId());
    }
};

ArrayList<Employee> employees = getUnsortedEmployeeList();

Collections.sort(employees, compareById);

In Java 8

Comparator<Employee> compareById = (Employee o1, Employee o2) -> 
                                    o1.getId().compareTo( o2.getId() );
//First name sorter
Comparator<Employee> compareByFirstName = (Employee o1, Employee o2) ->
                                    o1.getFirstName().compareTo( o2.getFirstName() );
//Last name sorter
Comparator<Employee> compareByLastName = (Employee o1, Employee o2) -> 
                                    o1.getLastName().compareTo( o2.getLastName() );
ArrayList<Employee> employees = getUnsortedEmployeeList();
Collections.sort(employees, compareById);
Collections.sort(employees, compareByFirstName);
Collections.sort(employees, compareByLastName);

再看个例子:ActionListener

public class TestActionEvent {  
  
    public static void main(String[] args) {  
        ...
        Button b = new Button("Press me");  
        Monitor mo = new Monitor();  
        b.addActionListener(mo);  
        ...
    }  
}  
  
static class Monitor implements ActionListener {  
  
    @Override  
    public void actionPerformed(ActionEvent e) {  
        System.out.println(e);  
    }  
  
} 

Button需要一个ActionListener

使用匿名类

public class TestActionEvent {  
  
    public static void main(String[] args) {  
        ...
        Button b = new Button("Press me");  
        b.addActionListener(new ActionListener(){
            @Override  
            public void actionPerformed(ActionEvent e) {  
                System.out.println(e);  
            } 
        } );  
        ...
    }  
}  
  

Button并不在意Listener是谁,要的一个函数处理Action

ActionListener

ActionListener只定义了一个函数接口:

void actionPerformed(ActionEvent e)

Invoked when an action occurs.

https://docs.oracle.com/javase/8/docs/api/java/awt/event/ActionListener.html

那直接传个函数不好么?

public class TestActionEvent {  
    public static void main(String[] args) {  
        Button b = new Button("Press me");  
        b.addActionListener((e) -> {
            System.out.println(e)
        });  
    }  
}  

(e) -> {System.out.println(e)}

此事并不稀奇:C Pointer

void MyFun(int x);   
void (*FunP)(int ); 

int main(int argc, char* argv[])
{
   MyFun(10);    
   FunP=&MyFun; 
   (*FunP)(20); 
}

void MyFun(int x) 
{
   printf(“%d\n”,x);
}

真的不稀奇

func backward(_ s1: String, _ s2: String) -> Bool {
   return s1 > s2
}

var reversedNames = names.sorted(by: backward)

Swift Clousure

真的一点不稀奇

float price = 1.99; 
float (^finalPrice)(int) = ^(int quantity) {
	// Notice local variable price is 
	// accessible in the block
	return quantity * price;
};

int orderQuantity = 10;
NSLog(@"Ordering %d units, final price is: $%2.2f", orderQuantity, finalPrice(orderQuantity));

Objective-C block

函数式编程 Functional Programming

In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that each return a value, rather than a sequence of imperative statements which change the state of the program.

In functional programming, functions are treated as first-class citizens, meaning that they can be bound to names, passed as arguments, and returned from other functions, just as any other data type can. This allows programs to be written in a declarative and composable style, where small functions are combined in a modular manner.

Java?

很多时候我们只是需要一个函数,Java里将普通的方法或函数像参数一样传值并不简单。

Java 世界是严格地以名词为中心的。 Why?

Execution in the Kingdom of Nouns

Imperative versus Declarative

  • Imperative: is a style of programming where you program the algorithm with control flow and explicit steps.
  • Declarative: is a style of programming where you declare what needs be done without concern for the control flow.
  • Functional programming: is a declarative programming paradigm that treats computation as a series of functions and avoids state and mutable data to facilitate concurrency http://www.ruanyifeng.com/blog/2012/04/functional_programming.html

Java缺少函数式编程特点, 为此Java 8 增加了一个语言级的新特性,名为Lambda表达式。

Lambda 表达式

Lambda表达式是一种匿名函数(并不完全正确),简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。

你可以将其想做一种速记,在你需要使用某个方法的地方写上它。当某个方法只使用一次,而且定义很简短,使用这种速记替代之尤其有效,这样,你就不必在类中费力写声明与方法了。

(arg1, arg2...) -> { body }

(type1 arg1, type2 arg2...) -> { body }

例如

(int a, int b) -> {  return a + b; }

() -> System.out.println("Hello World");

(String s) -> { System.out.println(s); }

() -> 42

() -> { return 3.1415 };

Lambda 表达式的结构

  • 一个Lambda表达式可以有零个或多个参数
    • 参数类型既可以明确声明,也可以根据上下文来推断。例如(int a)(a)等效
    • 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a, b)(int a, int b)(String a, int b, float c)
    • 空圆括号代表参数集为空。例如:() -> 42;当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> return a*a
  • Lambda 表达式的主体可包含零条或多条语句
    • 若只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致
    • 若包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空

函数式接口

  • 函数式接口是只包含一个抽象方法声明的接口
    • java.lang.Runnable就是一种函数式接口,在Runnable接口中只声明了一个方法void run()
    • 相似地,ActionListener接口也是一种函数式接口,我们使用匿名内部类来实例化函数式接口的对象,有了Lambda表达式,这一方式可以得到简化。
  • 每个 Lambda 表达式都能隐式地赋值给函数式接口

例如

Runnable r = () -> System.out.println("hello world");

Or even

new Thread(
   () -> System.out.println("hello world")
).start();

根据线程类的构造函数签名public Thread(Runnable r) { },将该Lambda表达式赋给Runnable接口。

其他常见的函数式接口

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是 Java 8 新加入的一种接口,用于指明该接口类型声明是根据 Java 语言规范定义的函数式接口。

@FunctionalInterface public interface WorkerInterface {
   public void doSomeWork();
}

使用

@FunctionalInterface
public interface WorkerInterface {
   public void doSomeWork();
}

public class WorkerInterfaceTest {
    public static void execute(WorkerInterface worker) { worker.doSomeWork(); }
    public static void main(String [] args) {
        execute(new WorkerInterface() {
            @Override
            public void doSomeWork() {
                System.out.println("Worker invoked using Anonymous class");
            }
        });
        execute(() -> System.out.println("Worker invoked using Lambda expression"));
    }
}

参考文献

Lambda Quick Start

http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html

java.util.function.Function

Interface Function<T,R>

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

R apply(T t)

Applies this function to the given argument.

https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html

回头看

@FunctionalInterface
public interface Predicate<T>

Represents a predicate (boolean-valued function) of one argument.
This is a functional interface whose functional method is test(Object).

https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html

Method Summary










What's static methods & default methods in interfaces?

自己写一下

import java.util.function.Function;

public class FunctionClass {

    public <T> void printer(Function<T, String> function, T t) {
        System.out.println(function.apply(t));
    }

    public static void main(String[] args) {
        new FunctionClass().<String>printer((s) -> "Length is " + s.length(), "abc");
    }
}

FaaS: Function as a service

Function as a service is a category of cloud computing services that provides a platform allowing customers to develop, run, and manage application functionalities without the complexity of building and maintaining the infrastructure typically associated with developing and launching an app.

AWS Lambda was the first FaaS offering by a large public cloud vendor.

https://en.wikipedia.org/wiki/Function_as_a_service

Spring Cloud Function

  • Spring Cloud Function 是来自 Pivotal 的 Spring 团队的新项目,它致力于促进函数作为主要的开发单元。
  • 该项目提供了一个通用的模型,用于在各种平台上部署基于函数的软件,包括像 Amazon AWS Lambda 这样的 FaaS(函数即服务,function as a service)平台。

Demo

https://github.com/sa-spring/spring-cloudfunction

@SpringBootApplication
public class CloudFunctionApplication {
    ...
    @Bean
    public Function<String, String> reverseString() {
        return value -> new StringBuilder(value).reverse().toString();
	}
}
$ curl localhost:8080/reverseString -H "Content-Type: text/plain" -d  "hello world"

Demo Pojo Function

import java.util.function.Function;

public class Greeter implements Function<String, String> {
 
    @Override
    public String apply(String s) {
        return "Hello " + s + ", and welcome to Spring Cloud Function!!!";
    }
}
$ curl localhost:8080/greeter -H "Content-Type: text/plain" -d "World"