函数式编程深入浅出
案例,声明一个接口和内部类实现一个过滤接口
public static List<User> filterWangUsers(List<User> users) {
return filter(users, new 姓王的条件());
}
static class 姓王的条件 implements 条件 {
@Override
public boolean 满足当前条件(User user) {
return user.name.startsWith("王");
}
}
interface 条件 {
boolean 满足当前条件(User user);
}
public static List<User> filter(List<User> users,条件 一个条件 ) {
List<User> results = new ArrayList<>();
for (User user : users) {
if (一个条件.满足当前条件(user)) {
results.add(user);
}
}
return results;
}
}
public static List<User> filterWangUsers(List<User> users) {
return filter(users, new 姓王的条件());
}
static class 姓王的条件 implements Predicate<User> {
@Override
public boolean test(User user) {
return false;
}
}
public static List<User> filter(List<User> users,Predicate<User> predicate ) {
List<User> results = new ArrayList<>();
for (User user : users) {
if (predicate.test(user)) {
results.add(user);
}
}
return results;
}
- predicate就是一个判断一个条件,是抽象的是一个接口,必须要传递进去一个实现类
- java8之前的写法,只能通过接口加匿名类的方式去实现一个抽象的函数式操作
package com.github.hcsp.polymorphism;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class User {
private final Integer id;
private final String name;
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public static List<User> filterUsersWithEvenId(List<User> users) {
return filter(users, new IdIsEvenPredicate());
}
static class IdIsEvenPredicate implements Predicate<User> {
@Override
public boolean test(User user) {
return user.id % 2 == 0
}
}
public static List<User> filterZhangUsers(List<User> users) {
List<User> results = new ArrayList<>();
for (User user : users) {
if (user.name.startsWith("张")) {
results.add(user);
}
}
return results;
}
public static List<User> filterWangUsers(List<User> users) {
return filter(users, new 姓王的条件());
}
static class 姓王的条件 implements Predicate<User> {
@Override
public boolean test(User user) {
return false;
}
}
public static List<User> filter(List<User> users,Predicate<User> 一个条件 ) {
List<User> results = new ArrayList<>();
for (User user : users) {
if (一个条件.test(user)) {
results.add(user);
}
}
return results;
}
}
package com.github.hcsp.polymorphism;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class User {
private final Integer id;
private final String name;
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
// 过滤ID为偶数的用户
public static List<User> filterUsersWithEvenId(List<User> users) {
return filter(users, user -> user.id % 2 == 0);
}
// 过滤姓张的用户
public static List<User> filterZhangUsers(List<User> users) {
List<User> results = new ArrayList<>();
for (User user : users) {
if (user.name.startsWith("张")) {
results.add(user);
}
}
return results;
}
// 过滤姓王的用户
public static List<User> filterWangUsers(List<User> users) {
return filter(users, new Predicate<User>() {
@Override
public boolean test(User user) {
return user.getName().startsWith("王");
}
});
}
// 你可以发现,在上面三个函数中包含大量的重复代码。
// 请尝试通过Predicate接口将上述代码抽取成一个公用的过滤器函数
// 并简化上面三个函数
public static List<User> filter(List<User> users,Predicate<User> 一个条件 ) {
List<User> results = new ArrayList<>();
for (User user : users) {
if (一个条件.test(user)) {
results.add(user);
}
}
return results;
}
}
private static boolean userWithEvenId(User user) {
return user.getId() % 2 == 0;
}
- 方法引用的写法,这样的好处是
- 1.他是有名字的,可以对做什么事情进行解释
- 2.可以写多行,超过两行就不要写lambada表达式了
private static boolean userWithEvenId(User user) {
return user.getId() % 2 == 0;
}
public static List<User> filterUsersWithEvenId(List<User> users) {
return filter(users, User::userWithEvenId);
}
public boolean isWang() {
return this.name.startsWith("王");
}
什么是函数接口
- 任何只包含一个抽象方法的接口都可以被自动转换为函数接口
- abstract 方法,抽象方法就是没有方法体
public static List<User> filter(List<User> users,阿猫阿狗 predicate ) {
List<User> results = new ArrayList<>();
for (User user : users) {
if (predicate.吃骨头(user)) {
results.add(user);
}
}
return results;
}
interface 阿猫阿狗 {
boolean 吃骨头(User user);
}
Predicate之外其他的函数接口
- 在java.util.function包中
- consumer,输入是一个具体的对象,输出是虚空,把一个对象虚空
- 例子1
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.forEach(new Consumer<User>() {
@Override
public void accept(User user) {
System.out.println(user);
}
});
}
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.forEach(user -> System.out.println(user));
}
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.forEach(System.out::println);
}
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.forEach(User::print);
}
private static void print(User user) {
}
Function接口
public String getName() {
return name;
}
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.forEach(System.out::println);
map(new User(1, "name"), User::getName);
}
public static String map(User user, Function<User, String> function) {
return function.apply(user);
}
Supplier接口
public static String map(User user, Function<User, St ring> function) {
create(Object::new);
create(()->"");
create(()->new User(1, "name"));
}
private static Object create(Supplier<Object> supplier) {
return supplier.get();
}
除了常见的这些,还有三套平行的Double int lang
传统方法实现比较器
public static void main(String[] args) throws IOException {
List<Point> points =
Arrays.asList(
new Point(2, 0),
new Point(-1, 1),
new Point(1, -1),
new Point(2, 1),
new Point(2, -1));
Collections.sort(points, new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
if (o1.x < o2.x) {
return 1;
} else if (o1.x > o2.x) {
return -1;
}
if (o1.y < o2.y) {
return 1;
} else if (o1.y > o2.y) {
return -1;
}
return 0;
}
});
}
Collections.sort(points, comparing(Point::getX)
.reversed()
.thenComparing(comparing(Point::getY).reversed()));
课后练习题
package com.github.hcsp.functional;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
public class RefactorToSupplier {
private static int randomInt() {
return new Random().nextInt();
}
static int a = 0;
public static void main(String[] args) {
System.out.println(createObjects());
System.out.println(createStrings());
System.out.println(createRandomIntegers());
}
private static Object getObject() {
return new Object();
}
private static String getString() {
return "" + a++;
}
private static int getRandom() {
return randomInt();
}
public static List<Object> create(Supplier<Object> supplier) {
List<Object> result = new ArrayList<>();
for (int i = 0; i < 10; i++) {
result.add(supplier.get());
}
return result;
}
public static List<Object> createObjects() {
return create(RefactorToSupplier::getObject);
}
public static List<Object> createStrings() {
return create(RefactorToSupplier::getString);
}
public static List<Object> createRandomIntegers() {
return create(RefactorToSupplier::getRandom);
}
}
package com.github.hcsp.functional;
public class PriceCalculator {
public static void main(String[] args) {
int originalPrice = 100;
User vipUser = User.vip("张三");
calculatePrice((price, user) -> price, originalPrice, vipUser);
calculatePrice((price, user) -> (int) (price * 0.95), originalPrice, vipUser);
calculatePrice(
(price, user) -> user.isVip() ? (int) (price * 0.95) : price,
originalPrice,
vipUser);
}
interface DiscountStrategy {
int discount(int price, User user);
}
static int calculatePrice(DiscountStrategy strategy, int price, User user) {
return strategy.discount(price, user);
}
}
package com.github.hcsp.functional;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
public class Order {
private Integer id;
private Instant orderTime;
private boolean open;
private BigDecimal amount;
public Order(Integer id, Instant orderTime, boolean open, BigDecimal amount) {
this.id = id;
this.orderTime = orderTime;
this.open = open;
this.amount = amount;
}
public Integer getId() {
return id;
}
public Instant getOrderTime() {
return orderTime;
}
public boolean isOpen() {
return open;
}
public BigDecimal getAmount() {
return amount;
}
@Override
public String toString() {
return "Order{"
+ "id="
+ id
+ ", orderTime="
+ orderTime
+ ", open="
+ open
+ ", amount="
+ amount
+ '}';
}
public static TreeSet<Order> toTreeSet(List<Order> orders) {
TreeSet orderTreeSet = new TreeSet<>(Comparator.comparing(Order::isOpen)
.thenComparing(Order::getAmount)
.reversed()
.thenComparing(Order::getOrderTime)
.thenComparing(Order::getId));
orderTreeSet.addAll(orders);
return orderTreeSet;
}
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println(
toTreeSet(
Arrays.asList(
new Order(1, now, false, new BigDecimal("1")),
new Order(2, now.minusSeconds(1), true, new BigDecimal("2")),
new Order(3, now.minusSeconds(-1), true, new BigDecimal("3")),
new Order(4, now.minusSeconds(2), false, new BigDecimal("4")))));
}
}