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) -> { return 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");
    }
}

继续:Method References

Lambda表达式的语法糖,当Lambda只是调用一个已存在的方法时,可以使用更简洁的方法引用。

list.forEach(s -> System.out.println(s)); // Lambda 表达式
list.forEach(System.out::println); // 方法引用
  • 静态方法引用:ClassName::staticMethod
  • 实例方法引用:instance::instanceMethod
  • 类的任意对象方法引用:ClassName::instanceMethod
  • 构造器引用:ClassName::new

静态方法引用

Function<String, Integer> parser1 = s -> Integer.parseInt(s); // Lambda
Function<String, Integer> parser2 = Integer::parseInt; // 方法引用

// 使用
Integer num = parser2.apply("123"); // 123
List<String> numbers = Arrays.asList("1", "2", "3");
numbers.stream()
       .map(Integer::parseInt)  // 静态方法引用
       .forEach(System.out::println);

实例方法引用

String prefix = "Hello ";

// Lambda
Function<String, String> greeter1 = name -> prefix.concat(name);

// 方法引用
Function<String, String> greeter2 = prefix::concat;

System.out.println(greeter2.apply("World")); // Hello World

类的任意对象方法引用

// Lambda
Comparator<String> comp1 = (s1, s2) -> s1.compareToIgnoreCase(s2);

// 方法引用 - 第一个参数作为方法调用者
Comparator<String> comp2 = String::compareToIgnoreCase;
List<String> names = Arrays.asList("Alice", "bob", "Charlie");
names.sort(String::compareToIgnoreCase);
// [Alice, bob, Charlie]

构造器引用

// Lambda
Supplier<ArrayList<String>> list1 = () -> new ArrayList<>();

// 构造器引用
Supplier<ArrayList<String>> list2 = ArrayList::new;

// 带参数的构造器
Function<Integer, ArrayList<String>> list3 = ArrayList::new;
ArrayList<String> myList = list3.apply(10); // 初始容量为10

数组构造器引用

// Lambda
Function<Integer, String[]> arrayCreator1 = size -> new String[size];

// 数组构造器引用
Function<Integer, String[]> arrayCreator2 = String[]::new;

String[] arr = arrayCreator2.apply(5); // 创建长度为5的数组

Stream API

Stream API是Lambda表达式最重要的应用场景,提供了声明式的数据处理方式。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 传统方式
List<String> filtered = new ArrayList<>();
for (String name : names) {
    if (name.startsWith("A") || name.startsWith("B")) {
        filtered.add(name.toUpperCase());
    }
}
Collections.sort(filtered);

Stream方式

List<String> result = names.stream()
    .filter(name -> name.startsWith("A") || name.startsWith("B"))
    .map(String::toUpperCase)
    .sorted()
    .collect(Collectors.toList());
// [ALICE, BOB]
  • 声明式:描述做什么,而不是怎么做
  • 可组合:多个操作可以链式调用
  • 可并行:轻松切换到并行处理
  • 延迟执行:只有遇到终止操作才真正执行

Stream的创建

// 从集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();

// 从数组创建
String[] arr = {"a", "b", "c"};
Stream<String> stream2 = Arrays.stream(arr);

// 使用Stream.of()
Stream<String> stream3 = Stream.of("a", "b", "c");

// 无限流
Stream<Integer> stream4 = Stream.iterate(0, n -> n + 2); // 0, 2, 4, 6...
Stream<Double> stream5 = Stream.generate(Math::random);

中间操作 - filter & map

List<Employee> employees = getEmployees();

// filter - 过滤
employees.stream()
    .filter(e -> e.getSalary() > 5000)
    .filter(e -> e.getAge() < 40)
    .forEach(System.out::println);

// map - 转换
List<String> names = employees.stream()
    .map(Employee::getName)
    .collect(Collectors.toList());

// mapToInt/mapToDouble/mapToLong - 转换为基本类型流
int totalSalary = employees.stream()
    .mapToInt(Employee::getSalary)
    .sum();

中间操作 - flatMap

// flatMap - 扁平化处理
List<List<String>> listOfLists = Arrays.asList(
    Arrays.asList("a", "b"),
    Arrays.asList("c", "d"),
    Arrays.asList("e", "f")
);
List<String> flattened = listOfLists.stream()
    .flatMap(List::stream)  // 将每个List<String>展开为Stream<String>
    .collect(Collectors.toList()); // [a, b, c, d, e, f]
List<String> allSkills = employees.stream() // 实际应用:获取所有员工的所有技能
    .flatMap(e -> e.getSkills().stream())
    .distinct()
    .collect(Collectors.toList());

中间操作 - 其他

// distinct - 去重
Stream.of(1, 2, 2, 3, 3, 3)
      .distinct()
      .forEach(System.out::println); // 1, 2, 3
// sorted - 排序
employees.stream()
    .sorted(Comparator.comparing(Employee::getSalary).reversed())
    .forEach(System.out::println);
// limit - 限制数量
employees.stream()
    .limit(5)  // 只取前5个
    .forEach(System.out::println);
// skip - 跳过
employees.stream()
    .skip(10)  // 跳过前10个
    .forEach(System.out::println);

终止操作 - collect

// 转换为List
List<String> list = stream.collect(Collectors.toList());

// 转换为Set
Set<String> set = stream.collect(Collectors.toSet());

// 转换为Map
Map<Integer, Employee> map = employees.stream()
    .collect(Collectors.toMap(Employee::getId, e -> e));

// 连接字符串
String joined = employees.stream()
    .map(Employee::getName)
    .collect(Collectors.joining(", ", "[", "]"));
// [Alice, Bob, Charlie]

终止操作 - 其他

// forEach - 遍历
stream.forEach(System.out::println);

// count - 计数
long count = employees.stream()
    .filter(e -> e.getSalary() > 5000)
    .count();

// anyMatch/allMatch/noneMatch - 匹配
boolean hasHighEarner = employees.stream()
    .anyMatch(e -> e.getSalary() > 10000);

boolean allAdults = employees.stream()
    .allMatch(e -> e.getAge() >= 18);

// findFirst/findAny - 查找
Optional<Employee> first = employees.stream()
    .filter(e -> e.getName().startsWith("A"))
    .findFirst();

终止操作 - reduce

// reduce - 归约操作
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 求和
int sum = numbers.stream()
    .reduce(0, (a, b) -> a + b);  // 15
// 也可以使用方法引用
int sum2 = numbers.stream()
    .reduce(0, Integer::sum);
// 求最大值
Optional<Integer> max = numbers.stream()
    .reduce(Integer::max);
// 字符串拼接
String concatenated = Stream.of("a", "b", "c")
    .reduce("", String::concat); // "abc"

并行流 Parallel Streams

// 串行流
long count1 = employees.stream()
    .filter(e -> e.getSalary() > 5000)
    .count();
// 并行流 - 利用多核CPU
long count2 = employees.parallelStream()
    .filter(e -> e.getSalary() > 5000)
    .count();
// 或者从串行流转换
long count3 = employees.stream()
    .parallel()  // 转换为并行流
    .filter(e -> e.getSalary() > 5000)
    .count();

不是所有操作都适合并行,数据量小或操作简单时,并行反而会降低性能。

Stream综合示例

// 找出年龄大于30岁、工资前3高的员工姓名
List<String> topEarners = employees.stream()
    .filter(e -> e.getAge() > 30)
    .sorted(Comparator.comparing(Employee::getSalary).reversed())
    .limit(3)
    .map(Employee::getName)
    .collect(Collectors.toList());

// 按部门统计平均工资
Map<String, Double> avgSalaryByDept = employees.stream()
    .collect(Collectors.groupingBy(
        Employee::getDepartment,
        Collectors.averagingDouble(Employee::getSalary)
    ));

闭包与变量捕获

Lambda表达式可以访问外部变量,形成闭包(Closure)

int baseValue = 10;

Function<Integer, Integer> adder = x -> x + baseValue;

System.out.println(adder.apply(5)); // 15

但有重要限制:被Lambda捕获的局部变量必须是final或effectively final的

Effectively Final

int baseValue = 10;
Function<Integer, Integer> adder = x -> x + baseValue; // OK

baseValue = 20; // 编译错误!Variable used in lambda should be final or effectively final

Effectively Final: 变量初始化后从未被修改,虽然没有声明为final,但实际上是final的。

final int baseValue = 10; // 显式final
Function<Integer, Integer> adder = x -> x + baseValue; // OK

为什么有这个限制?

Function<Integer, Integer> createAdder(int base) {
    return x -> x + base;  // base必须是final的
}

Function<Integer, Integer> adder = createAdder(10);
// base变量已经不在栈上了,但Lambda仍需要访问它
// 所以Lambda会捕获base的值(值拷贝),而不是引用

原因:

  1. Lambda可能在其他线程执行
  2. Lambda可能在变量作用域外执行
  3. 避免并发修改问题

访问实例变量

public class Counter {
    private int count = 0;  // 实例变量可以修改
    
    public void doCount() {
        IntStream.range(0, 5).forEach(i -> {
            count++;  // OK! 实例变量可以修改
            System.out.println(count);
        });
    }
}

实例变量静态变量可以在Lambda中修改,因为它们不是局部变量。

变通方案

// 使用数组或包装对象
int[] count = {0};
IntStream.range(0, 5).forEach(i -> {
    count[0]++;  // 数组引用是final的,但数组内容可变
});

// 使用AtomicInteger(线程安全)
AtomicInteger atomicCount = new AtomicInteger(0);
IntStream.range(0, 5).forEach(i -> {
    atomicCount.incrementAndGet();
});

不推荐:这违背了函数式编程的不可变原则。

函数组合 Function Composition

函数式编程的核心思想之一:将小函数组合成大函数。

Function<Integer, Integer> times2 = x -> x * 2;
Function<Integer, Integer> squared = x -> x * x;

// andThen - 先执行调用者,再执行参数
Function<Integer, Integer> times2ThenSquared = times2.andThen(squared);
System.out.println(times2ThenSquared.apply(4)); // (4 * 2)^2 = 64

// compose - 先执行参数,再执行调用者
Function<Integer, Integer> squaredThenTimes2 = times2.compose(squared);
System.out.println(squaredThenTimes2.apply(4)); // (4^2) * 2 = 32

Predicate组合

Predicate<String> startsWithA = s -> s.startsWith("A");
Predicate<String> longString = s -> s.length() > 5;

// and - 逻辑与
Predicate<String> combined = startsWithA.and(longString);
System.out.println(combined.test("Alice")); // true
System.out.println(combined.test("Amy"));   // false

// or - 逻辑或
Predicate<String> either = startsWithA.or(longString);

// negate - 逻辑非
Predicate<String> notStartsWithA = startsWithA.negate();

Comparator组合

List<Employee> employees = getEmployees();

// 先按部门排序,部门相同再按工资排序
Comparator<Employee> comparator = 
    Comparator.comparing(Employee::getDepartment)
              .thenComparing(Employee::getSalary);

employees.sort(comparator);

// 倒序
employees.sort(comparator.reversed());

// 空值处理
Comparator<Employee> nullSafeComparator = 
    Comparator.nullsLast(
        Comparator.comparing(Employee::getName)
    );

Consumer组合

Consumer<String> c1 = s -> System.out.println("First: " + s);
Consumer<String> c2 = s -> System.out.println("Second: " + s);

// andThen - 依次执行
Consumer<String> combined = c1.andThen(c2);
combined.accept("Test");
// 输出:
// First: Test
// Second: Test
List<String> list = Arrays.asList("a", "b", "c");
list.forEach(
    ((Consumer<String>) String::toUpperCase)
        .andThen(System.out::println)
);

实际应用:验证器链

class Validator {
    public static Predicate<Employee> isAdult() {
        return e -> e.getAge() >= 18;
    }
    public static Predicate<Employee> hasValidSalary() {
        return e -> e.getSalary() > 0;
    }
    public static Predicate<Employee> hasValidEmail() {
        return e -> e.getEmail() != null && e.getEmail().contains("@");
    }
}

Predicate<Employee> employeeValidator = 
    Validator.isAdult()
             .and(Validator.hasValidSalary())
             .and(Validator.hasValidEmail());

boolean isValid = employeeValidator.test(employee);

Optional 与 Lambda

// 传统方式
Employee employee = findEmployeeById(id);
if (employee != null) {
    String name = employee.getName();
    if (name != null) {
        System.out.println(name.toUpperCase());
    }
}

// Optional方式
findEmployeeById(id)
    .map(Employee::getName)
    .map(String::toUpperCase)
    .ifPresent(System.out::println);

创建Optional

// 空Optional
Optional<String> empty = Optional.empty();

// 非空Optional(值不能为null)
Optional<String> opt1 = Optional.of("Hello");
Optional<String> opt2 = Optional.of(null); // NullPointerException!

// 可能为空的Optional
Optional<String> opt3 = Optional.ofNullable("Hello");
Optional<String> opt4 = Optional.ofNullable(null); // OK,返回empty

Optional的map

Optional<Employee> empOpt = findEmployeeById(id);

// map - 转换值
Optional<String> nameOpt = empOpt.map(Employee::getName);

// 链式调用
String upperName = empOpt
    .map(Employee::getName)
    .map(String::toUpperCase)
    .orElse("UNKNOWN");

Optional的flatMap

// flatMap - 避免Optional嵌套
class Employee {
    private Optional<Address> address;
    public Optional<Address> getAddress() { return address; }
}

Optional<String> city = empOpt
    .flatMap(Employee::getAddress)  // 不是Optional<Optional<Address>>
    .map(Address::getCity)
    .orElse("Unknown");

Optional的filter

Optional<Employee> empOpt = findEmployeeById(id);
// 只有满足条件才保留
empOpt.filter(e -> e.getSalary() > 5000)
      .ifPresent(e -> System.out.println("High earner: " + e.getName()));
// 链式过滤
empOpt.filter(e -> e.getAge() > 25)
      .filter(e -> e.getDepartment().equals("IT"))
      .map(Employee::getName)
      .ifPresent(System.out::println);

Lambda中的异常处理

Lambda表达式不能抛出受检异常(Checked Exception),这是一个常见的痛点。

List<String> files = Arrays.asList("a.txt", "b.txt", "c.txt");

// 编译错误!Lambda不能抛出IOException
files.forEach(file -> {
    String content = Files.readString(Path.of(file)); // throws IOException
    System.out.println(content);
});

解决方案1:Try-Catch包装

files.forEach(file -> {
    try {
        String content = Files.readString(Path.of(file));
        System.out.println(content);
    } catch (IOException e) {
        throw new RuntimeException(e); // 转换为运行时异常
    }
});

缺点:代码冗长,破坏了Lambda的简洁性。

解决方案2:包装函数

@FunctionalInterface
public interface ThrowingConsumer<T> {
    void accept(T t) throws Exception;
    
    static <T> Consumer<T> wrap(ThrowingConsumer<T> consumer) {
        return t -> {
            try {
                consumer.accept(t);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        };
    }
}

// 使用
files.forEach(ThrowingConsumer.wrap(file -> {
    String content = Files.readString(Path.of(file));
    System.out.println(content);
}));

解决方案3:提取方法

public class FileProcessor {
    public static void processFile(String file) {
        try {
            String content = Files.readString(Path.of(file));
            System.out.println(content);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

// 使用方法引用
files.forEach(FileProcessor::processFile);

解决方案4:使用Try类型(函数式库)

// 使用Vavr等函数式库
import io.vavr.control.Try;

files.forEach(file -> {
    Try.of(() -> Files.readString(Path.of(file)))
       .onSuccess(System.out::println)
       .onFailure(e -> System.err.println("Error: " + e.getMessage()));
});

// 或者收集结果
List<Try<String>> results = files.stream()
    .map(file -> Try.of(() -> Files.readString(Path.of(file))))
    .collect(Collectors.toList());

性能考虑

Lambda vs 匿名类

// Lambda使用invokedynamic,首次调用稍慢,后续调用很快
Runnable r1 = () -> System.out.println("Lambda");

// 匿名类每次都会生成新的类文件
Runnable r2 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Anonymous");
    }
};

Lambda在性能和内存占用上都优于匿名类。

Stream的开销

List<Integer> numbers = IntStream.range(0, 100).boxed().collect(Collectors.toList());

// 简单操作,传统循环可能更快
long sum1 = 0;
for (int n : numbers) {
    sum1 += n;
}

// Stream有创建、装箱等开销
long sum2 = numbers.stream()
    .mapToLong(Integer::longValue)
    .sum();

// 对于基本类型,使用IntStream/LongStream/DoubleStream避免装箱
long sum3 = IntStream.range(0, 100).sum();

并行流的注意事项

// 适合并行:计算密集型、数据量大、无状态操作
List<Integer> result1 = IntStream.range(0, 1_000_000)
    .parallel()
    .map(i -> i * i)  // CPU密集
    .boxed()
    .collect(Collectors.toList());

// 不适合并行:数据量小、有状态操作、线程安全问题
List<Integer> result2 = IntStream.range(0, 100)  // 数据太少
    .parallel()
    .mapToObj(i -> i)
    .collect(Collectors.toList());

并行流使用ForkJoinPool.commonPool(),线程数默认为CPU核心数。

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"

# Collector 高级用法 `Collectors`提供了丰富的收集器用于Stream的终止操作。 ## 基本收集器 ```java List<Employee> employees = getEmployees(); // toList/toSet List<String> names = employees.stream() .map(Employee::getName) .collect(Collectors.toList()); // toCollection - 指定集合类型 TreeSet<String> sortedNames = employees.stream() .map(Employee::getName) .collect(Collectors.toCollection(TreeSet::new)); ``` --- ## 统计收集器 ```java // counting long count = employees.stream() .collect(Collectors.counting()); // summingInt/summingDouble/summingLong int totalSalary = employees.stream() .collect(Collectors.summingInt(Employee::getSalary)); // averagingInt/averagingDouble/averagingLong double avgSalary = employees.stream() .collect(Collectors.averagingDouble(Employee::getSalary)); // summarizingInt - 获取统计摘要 IntSummaryStatistics stats = employees.stream() .collect(Collectors.summarizingInt(Employee::getSalary)); System.out.println("Max: " + stats.getMax()); System.out.println("Min: " + stats.getMin()); System.out.println("Avg: " + stats.getAverage()); ``` --- ## 分组 groupingBy ```java // 按部门分组 Map<String, List<Employee>> byDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment)); // 按条件分组 Map<Boolean, List<Employee>> byHighSalary = employees.stream() .collect(Collectors.partitioningBy(e -> e.getSalary() > 5000)); // 多级分组 Map<String, Map<Integer, List<Employee>>> byDeptAndAge = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.groupingBy(Employee::getAge) )); ``` --- ## groupingBy + 下游收集器 ```java // 按部门统计人数 Map<String, Long> countByDept = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.counting() )); // 按部门计算平均工资 Map<String, Double> avgSalaryByDept = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.averagingDouble(Employee::getSalary) )); // 按部门获取工资最高的员工 Map<String, Optional<Employee>> topByDept = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.maxBy(Comparator.comparing(Employee::getSalary)) )); ``` --- ## 字符串连接 ```java // joining - 连接字符串 String names = employees.stream() .map(Employee::getName) .collect(Collectors.joining()); // AliceBobCharlie String namesWithDelimiter = employees.stream() .map(Employee::getName) .collect(Collectors.joining(", ")); // Alice, Bob, Charlie String formatted = employees.stream() .map(Employee::getName) .collect(Collectors.joining(", ", "Employees: [", "]")); // Employees: [Alice, Bob, Charlie] ``` --- ## toMap ```java // 转换为Map Map<Integer, String> idToName = employees.stream() .collect(Collectors.toMap( Employee::getId, // key Employee::getName // value )); // 处理重复key Map<String, Employee> nameToEmp = employees.stream() .collect(Collectors.toMap( Employee::getName, e -> e, (existing, replacement) -> existing // 保留现有的 )); // 指定Map类型 TreeMap<Integer, String> sortedMap = employees.stream() .collect(Collectors.toMap( Employee::getId, Employee::getName, (e1, e2) -> e1, TreeMap::new )); ``` --- ## 自定义Collector ```java // 使用Collector.of()创建自定义收集器 Collector<Employee, ?, String> employeeNameCollector = Collector.of( StringBuilder::new, // supplier (sb, emp) -> sb.append(emp.getName()).append(", "), // accumulator (sb1, sb2) -> sb1.append(sb2), // combiner StringBuilder::toString // finisher ); String allNames = employees.stream() .collect(employeeNameCollector); ```

---

# Stream调试技巧 ## 使用peek() ```java List<Integer> result = IntStream.range(0, 10) .peek(x -> System.out.println("原始值: " + x)) .filter(x -> x % 2 == 0) .peek(x -> System.out.println("过滤后: " + x)) .map(x -> x * 2) .peek(x -> System.out.println("映射后: " + x)) .boxed() .collect(Collectors.toList()); ``` **注意**:`peek()`是中间操作,只在有终止操作时才执行。 --- ## 设置断点 在IDE中可以在Lambda表达式内部设置断点: ```java employees.stream() .filter(e -> { // 在这里设置断点 return e.getSalary() > 5000; }) .map(e -> { // 或者这里 return e.getName(); }) .collect(Collectors.toList()); ``` --- ## 分步执行 ```java // 不好调试的写法 List<String> result = employees.stream() .filter(e -> e.getSalary() > 5000) .map(Employee::getName) .sorted() .collect(Collectors.toList()); // 分步执行便于调试 Stream<Employee> highEarners = employees.stream() .filter(e -> e.getSalary() > 5000); Stream<String> names = highEarners.map(Employee::getName); Stream<String> sorted = names.sorted(); List<String> result = sorted.collect(Collectors.toList()); ``` --- ## 打印Stream内容(调试用) ```java public static <T> void printStream(Stream<T> stream) { System.out.println( stream.collect(Collectors.toList()) ); } // 注意:Stream只能消费一次 Stream<Integer> stream = Stream.of(1, 2, 3); printStream(stream); // OK printStream(stream); // 错误!Stream已关闭 ``` --- # Lambda最佳实践总结 1. **保持Lambda简短**:一行最好,最多3-5行 2. **复杂逻辑提取为方法**:使用方法引用 3. **避免副作用**:不修改外部状态 4. **合理使用类型推断**:让代码更简洁 5. **优先使用方法引用**:更清晰、更简洁 6. **善用Stream API**:处理集合数据 7. **谨慎使用并行流**:不是万能的性能提升 8. **Optional处理null**:避免显式null检查 9. **组合小函数**:而不是写大Lambda 10. **异常处理要妥善**:不要吞没异常

---