- lambda 管中窥豹
- Java8 常用函数
- Lambdas及函数式接口的例子
- 断言
- 消费数据
- 转换
- 提供数据
- 其他
- Optional
- 什么是flatMap
- 示例一
- 示例二
- 示例三
Java8 常用函数
- 匿名:它不像普通的方法那样有一个明确的名称:写得少而想得多!
- 函数:Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
- 传递:Lambda表达式可以作为参数传递给方法或存储在变量中。
- 简洁:无需像匿名类那样写很多模板代码。
| 函数式接口 | 函数描述符 | 原始类型特化 |
|---|---|---|
| Predicate | T->boolean | IntPredicate,LongPredicate, DoublePredicate |
| Consumer | T->void | IntConsumer,LongConsumer, DoubleConsumer |
| Function | T->R | IntFunction,IntToDoubleFunction,IntToLongFunction, LongFunction,LongToDoubleFunction,LongToIntFunction, DoubleFunction, ToIntFunction,ToDoubleFunction, ToLongFunction |
| Supplier | ()->T | BooleanSupplier,IntSupplier, LongSupplier, DoubleSupplier |
| UnaryOperator | T->T | IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator |
| BinaryOperator | (T,T)->T | IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator |
| BiPredicate | (L,R)->boolean | IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator |
| BiConsumer | (T,U)->void | ObjIntConsumer, ObjLongConsumer, ObjDoubleConsumer |
| BiFunction | (T,U)->R | ToIntBiFunction |
| 使用案例 | Lambda 的例子 | 对应的函数式接口 |
|---|---|---|
| 布尔表达式 | (List list) -> list.isEmpty() | Predicate |
| 创建对象 | () -> new Project() | Supplier |
| 创建对象 | () -> new Project() | Supplier |
| 消费一个 对象 | (Project p) -> System.out.println(p.getStars()) | Consumer |
| 从一个对象 中选择/提取 | (int a, int b) -> a * b | IntBinaryOperator |
| 比较两个 对象 | (Project p1, Project p2) -> p1.getStars().compareTo(p2.getStars()) | Comparator 或 BiFunction 或 ToIntBiFunction |
public void predicate(){
Predicate predicate = name -> name.endsWith(".com");
predicate.test("www.baidu.com");
IntPredicate intPredicate = (int i) -> i % 2 == 0;
intPredicate.test(200);
}
消费数据
public void consumer(){
Consumer consumer = this::consumerMethod;
consumer.accept("Hello World");
}
public String consumerMethod(String message){
return message;
}
转换
public static void function(){
Function toUpperCase = String::toUpperCase;
System.out.println(toUpperCase.apply("Learn Java8"));
Function bigDecimalFunction = x -> x.multiply(new BigDecimal(20));
System.out.println(bigDecimalFunction.apply(new BigDecimal(5)));
BiPredicate, Integer> biPredicate = List::contains;
List list = Stream.of(8, 7, 6, 5).collect(Collectors.toList());
System.out.println(biPredicate.test(list, 9));
}
提供数据
public static void supplier(){
Supplier supplier = () -> new Random().nextInt(10);
System.out.println(supplier.get());
Supplier userSupplier = User::new;
System.out.println(userSupplier.get().getName());
}
static class User{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
其他
public static void main(String[] args) {
List userList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setName("张三疯" + i);
user.setAge(17 + i);
userList.add(user);
}
List users = userList.stream().filter(user -> user.getAge() > 20).collect(Collectors.toList());
List userNames = userList.stream().map(User::getName).collect(Collectors.toList());
long count = userList.stream().map(User::getName).count();
}
Optional
准备工作,首先创建两个实体
import lombok.Data;
import java.util.Optional;
@Data
public class User {
private String username;
private String password;
private Integer age;
private Address address;
private Optional optAddress;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {
private String street;
private String door;
}
创建 Optional
public void createOptional() {
// 声明一个空的Optional
Optional optionalAddress = Optional.empty();
// 依据一个非空值创建Optional
Optional optionalAddress2 = Optional.of(new Address());
// 可接受null的Optional
Optional optionalAddress3 = Optional.ofNullable(new Address());
}
举例:当查询数据时,防止空指针
@Override
public Order getOrderById(String id) {
LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery();
queryWrapper.eq(Order::getOrderId, id);
Optional order = Optional.ofNullable(orderMapper.selectOne(queryWrapper));
return order.orElse(null);
}
举例二:
public static void mapOptional() {
Optional addressOptional = Optional.of(new Address("深南大道", "88号"));
Optional street = addressOptional.map(Address::getStreet);
System.out.println(street.orElse(""));
// return street.orElse("");
}
举例三:
public static void flatMap() {
User user = new User();
Optional addressOptional = Optional.of(new Address("达尔文路", "88号"));
user.setOptAddress(addressOptional);
user.setAddress(new Address("深南大道999", "88号"));
Optional userOptional = Optional.of(user);
String street1 = userOptional.map(User::getAddress)
.map(Address::getStreet)
.orElse("天坛路");
String street2 = userOptional.flatMap(User::getOptAddress)
.map(Address::getStreet).orElse("");
System.out.println(street1 + ", " + street2);
}
什么是flatMap
使用flatMap 可以将2 个级别的 Stream转换为一个 Stream 级别或将 2d 数组转换为 1d 数组。
例如:
下面是一个二维数组,我们可以用 Arrays.stream 或 Stream.of 把它转换成一个 Stream,它产生一个String[] 的 Stream
String[][] array = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};
// array to a stream
Stream stream1 = Arrays.stream(array);
// same result
Stream stream2 = Stream.of(array);
示例一
有这样一个需求,下面数组中过滤掉a,并打印数组所有元素。其他方法实现是非常困难的,我们可以用java8 的 flatMap 实现。
String[][] array = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};
// Java 8, 用Arrays.stream(array)也是可以的
String[] result = Stream.of(array) // Stream
.flatMap(Stream::of) // Stream
.filter(item -> !item.equals("a"))
.toArray(String[]::new); // [a, b, c, d, e, f]
System.out.println(Arrays.toString(result));
示例二
举一个集合的例子,首先建一个实体 Developer
import lombok.Data;
import java.util.HashSet;
import java.util.Set;
@Data
public class Developer {
private Integer id;
private String name;
private Set book;
public void addBook(String book) {
if (this.book == null) {
this.book = new HashSet<>();
}
this.book.add(book);
}
}
public class OptionalTest2 {
public static void main(String[] args) {
Developer o1 = new Developer();
o1.setName("mkyong");
o1.addBook("Java 8 in Action");
o1.addBook("Spring Boot in Action");
o1.addBook("Effective Java (3nd Edition)");
Developer o2 = new Developer();
o2.setName("zilap");
o2.addBook("Learning Python, 5th Edition");
o2.addBook("Effective Java (3nd Edition)");
List list = new ArrayList<>();
list.add(o1);
list.add(o2);
//Developer::getBook 等同于 x-> x.getBook()
//Collection::stream 等同于 x-> x.stream()
Set collect =
list.stream()
.map(Developer::getBook) // Stream>
.flatMap(Collection::stream) // Stream
.filter(x -> !x.toLowerCase().contains("python")) // filter python book
.collect(Collectors.toSet()); // remove duplicated
collect.forEach(System.out::println);
}
}
关键部分代码也可以写成
Set示例三collect1 = list.stream() .flatMap(x -> x.getBook().stream()) // Stream .filter(x -> !x.toLowerCase().contains("python")) // filter python book .collect(Collectors.toSet()); // remove duplicated
创建 Order 和 LineItem 两个实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Integer id;
private String invoice;
private List lineItems;
private BigDecimal total;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LineItem {
private Integer id;
private String item;
private Integer qty;
private BigDecimal price;
private BigDecimal total;
}
实现
import cn.com.java8.pojo.LineItem;
import cn.com.java8.pojo.Order;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class OptionalTest3 {
public static void main(String[] args) {
List orders = findAll();
// sum the line items' total amount
BigDecimal sumOfLineItems = orders.stream()
.flatMap(order -> order.getLineItems().stream()) // Stream
.map(LineItem::getTotal) // Stream
.reduce(BigDecimal.ZERO, BigDecimal::add); // reduce to sum all
System.out.println(sumOfLineItems);
BigDecimal sumOfOrder = orders.stream()
.map(Order::getTotal) // Stream
.reduce(BigDecimal.ZERO, BigDecimal::add); // reduce to sum all
System.out.println(sumOfOrder);
}
private static List findAll() {
LineItem item1 = new LineItem(1, "apple", 1, new BigDecimal("1.20"), new BigDecimal("1.20"));
LineItem item2 = new LineItem(2, "orange", 2, new BigDecimal(".50"), new BigDecimal("1.00"));
Order order1 = new Order(1, "A0000001", Arrays.asList(item1, item2), new BigDecimal("2.20"));
LineItem item3 = new LineItem(3, "monitor BenQ", 5, new BigDecimal("99.00"), new BigDecimal("495.00"));
LineItem item4 = new LineItem(4, "monitor LG", 10, new BigDecimal("120.00"), new BigDecimal("1200.00"));
Order order2 = new Order(2, "A0000002", Arrays.asList(item3, item4), new BigDecimal("1695.00"));
LineItem item5 = new LineItem(5, "One Plus 8T", 3, new BigDecimal("499.00"), new BigDecimal("1497.00"));
Order order3 = new Order(3, "A0000003", Collections.singletonList(item5), new BigDecimal("1497.00"));
return Arrays.asList(order1, order2, order3);
}
}
Stream.reduce()则是Stream的一个聚合方法,它可以把一个Stream的所有元素按照聚合函数聚合成一个结果,如下示例:
Integer integer = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get(); Long aLong = Stream.of(1L, 2L, 3L, 4L).reduce(Long::max).get();



