Java函数式编程最佳实践

别人说烂了的stream api不就不想赘述了,我想和大家分享一下,如何用函数式编程来简化我们的开发,想说点不一样的东西

简化事务

对于事务而言,应该粒度越小越好,并且读写逻辑应该分开,只在写的逻辑上执行事务,可以用函数式编程来简化抽去写逻辑这一步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码@Service
public class TransactionService {
@Transactional
public void process(ThrowExceptionRunnable runnable){
try {
runnable.run();
}catch (Exception e){
new RuntimeException(e);
}
}
}

//使用方式
public void regist(String username){
User user = userService.findByUserName(username);
if(user != null) return;

//执行事务 注册用户 开通余额账号
transactionService.process(() -> {
userService.save(new User(username));
balanceService.save(new Balance(username));
});
}

赋予方法重试能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
java复制代码    public static void retryFunction(ThrowExceptionRunnable runnable, int time) {
while (true) {
try {
runnable.run();
return;
} catch (Exception e) {
time--;
if (time <= 0) throw new RuntimeException(e);
}
}
}
public static <T, R> R retryFunction(ThrowExceptionFunction<T, R> function, T t, int time) {
while (true) {
try {
return function.apply(t);
} catch (Exception e) {
time--;
if (time <= 0) throw new RuntimeException(e);
}
}
}
public static <T, U, R> R retryFunction(ThrowExceptionBiFunction<T, U, R> function, T t, U u, int time) {
while (true) {
try {
return function.apply(t, u);
} catch (Exception e) {
time--;
if (time <= 0) throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
//http调用,失败会重试3次
retryFunction(()->http.call(),3);
//把数字1转成数字 失败会重试三次
String s = retryFunction(String::valueOf, 1, 3);
String ss = retryFunction(i -> String.valueOf(i), 1, 3);
}

赋予函数缓存能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码public static <T, R> R cacheFunction(Function<T, R> function, T t, Map<T, R> cache) {
R r = cache.get(t);
if (r != null) return r;
R result = function.apply(t);
cache.put(t,result);
return result;
}

public static void main(String[] args) {
Map<String,User> cache = new HashMap<Integer, User>();
String username = "张三";
//不走缓存
cacheFunction(u -> userService.findByUserName(u),username,cache);
//走缓存
cacheFunction(u -> userService.findByUserName(u),username,cache);
}

赋予函数报错返回默认值能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
java复制代码    public static <T, R> R computeOrGetDefault(ThrowExceptionFunction<T, R> function, T t, R r) {
try {
return function.apply(t);
} catch (Exception e) {
return r;
}
}
public static <R> R computeOrGetDefault(ThrowExceptionSupplier<R> supplier,R r){
try {
return supplier.get();
} catch (Exception e) {
return r;
}
}

public static void main(String[] args) {
//返回0
computeOrGetDefault(i -> {
if (i < 0) throw new RuntimeException();
else return i;
}, -1, 0);
//返回5
computeOrGetDefault(i -> {
if (i < 0) throw new RuntimeException();
else return i;
},5,0);
}

赋予函数处理异常的能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
java复制代码    public static <T, R> R computeAndDealException(ThrowExceptionFunction<T, R> function, T t, Function<Exception, R> dealFunc) {
try {
return function.apply(t);
} catch (Exception e) {
return dealFunc.apply(e);
}
}

public static <T, U, R> R computeAndDealException(ThrowExceptionBiFunction<T,U, R> function, T t, U u,Function<Exception, R> dealFunc) {
try {
return function.apply(t,u);
} catch (Exception e) {
return dealFunc.apply(e);
}
}

public static <R> R computeAndDealException(ThrowExceptionSupplier<R> supplier, Function<Exception, R> dealFunc) {
try {
return supplier.get();
} catch (Exception e) {
return dealFunc.apply(e);
}
}

public static void main(String[] args) {
//返回异常message的hashcode
Integer integer = computeAndDealException(i -> {
if (i < 0) throw new RuntimeException("不能小于0");
else return i;
}, -1, e -> e.getMessage().hashCode());
System.out.println(integer);

}

赋予函数记录日志能力

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码public static <T, R> R logFunction(Function<T, R> function, T t, String logTitle) {
long startTime = System.currentTimeMillis();
log.info("[[title={}]],request={},requestTime={}", logTitle, t.toString(),
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
R apply = function.apply(t);
long endTime = System.currentTimeMillis();
log.info("[[title={}]],response={},spendTime={}ms", logTitle, apply.toString(), endTime - startTime);
return apply;
}

public static void main(String[] args) {
logFunction(String::valueOf,"s","String.valueOf");
}

自定义函数接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码    @FunctionalInterface
public interface ThrowExceptionFunction<T, R> {
R apply(T t) throws Exception;
}

@FunctionalInterface
public interface ThrowExceptionBiFunction<T, U, R> {
R apply(T t, U u) throws Exception;
}
@FunctionalInterface
public interface ThrowExceptionSupplier<T> {
T get() throws Exception;
}
@FunctionalInterface
public interface ThrowExceptionRunnable {
void run() throws Exception;
}

Q:为什么要自定义函数接口

A:自带的函数接口无法处理检查异常,遇见带检查异常的方法会报错

我哪些场景用到了?

链式取数

在翻译php代码的时候我们常常遇到如下情况

1
php复制代码$s = a.b.c.d.e.f.g

然后翻译成java代码的时候是这样的

1
java复制代码String s = a.getB().getC().getD().getE().getF().getG();

有啥问题?没有没有判空,只要中间有一层为空,那么就是NPE,要是去写判空逻辑的话,真是要了命了

这时我们就可以用上上面提到的骚操作了

代码改写

1
java复制代码String s = computeOrGetDefault(()->a.getB().getC().getD().getE().getF().getG(),"");
事务
简单的降级操作(computeAndDealException)
接口重试
接口缓存
记录日志

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%