【優(yōu)雅代碼】11-stream精選/@functional懶加載示例
歡迎關(guān)注b站賬號(hào)/公眾號(hào)【六邊形戰(zhàn)士夏寧】氮采,一個(gè)要把各項(xiàng)指標(biāo)拉滿的男人摇庙。該文章已在github目錄收錄。
屏幕前的大帥比和大漂亮如果有幫助到你的話請(qǐng)順手點(diǎn)個(gè)贊宁改、加個(gè)收藏這對(duì)我真的很重要街佑。別下次一定了,都不關(guān)注上哪下次一定盾舌。
- 視頻講解
- 可直接運(yùn)行的完整代碼
- 上一篇拒絕if/else數(shù)據(jù)校驗(yàn)及轉(zhuǎn)換
- 下一篇hessian、kryo蘸鲸、json序列化大對(duì)比
1.背景
主要是對(duì)@functional簡(jiǎn)單示例矿筝,復(fù)雜示例會(huì)在18~20期展示。之前在優(yōu)雅代碼系列的第3節(jié)分享過了optional的用法,這邊就不再贅述了
2.常用部分
2.1示例
該部分包含了個(gè)人日常開發(fā)中95%以上的使用場(chǎng)景棚贾,或者其變種
public static void ordinaryUsed() {
// 并行流,會(huì)亂序
System.out.println("Step1");
Stream.of(1, 2, 3, 4).parallel().forEach(System.out::print);
System.out.println();
System.out.println("Step2");
// 并行流+收集保證不會(huì)亂序
Stream.of(1, 2, 3, 4).parallel().collect(Collectors.toList()).forEach(System.out::print);
System.out.println();
System.out.println("Step3");
// 獲取唯一數(shù)據(jù)
System.out.println(Stream.of(1, 2, 3, 4).filter(s -> s.equals(1)).findAny().get());
System.out.println("Step4");
// 條件過濾獲取新數(shù)據(jù)-list/set
System.out.println(Stream.of(1, 2, 3, 4).filter(s -> s > 3).collect(Collectors.toList()));
// 條件過濾獲取新數(shù)據(jù)-map
System.out.println("Step5");
System.out.println(new HashMap<Integer, Integer>() {{
put(1, 1);
put(2, 2);
put(3, 3);
put(4, 4);
}}.entrySet().stream().filter(s -> s.getKey() > 3).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
System.out.println("Step6");
// list做物理分頁(yè)
List<Integer> list = Stream.of(1, 2, 3, 4, 5).collect(Collectors.toList());
int pageNum = 2;
int pageSize = 3;
System.out.println(list.stream().skip((pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList()));
// 循環(huán)創(chuàng)建連續(xù)數(shù)字list
System.out.println("Step7");
System.out.println(IntStream.range(0, 10).boxed().collect(Collectors.toList()));
// list循環(huán)獲取索引下標(biāo)
System.out.println("Step8");
IntStream.range(0, list.size()).forEach(x -> System.out.print(list.get(x)));
System.out.println();
// list對(duì)象-轉(zhuǎn)map榆综,注意key不能相同妙痹,否則會(huì)報(bào)錯(cuò)
System.out.println("Step9");
System.out.println(Stream.of(TestEnum.values()).collect(Collectors.toMap(TestEnum::getCode, s -> s)));
System.out.println("Step10");
// list對(duì)象-轉(zhuǎn)map嵌list,根據(jù)選擇的屬性進(jìn)行合并
System.out.println(Arrays.stream(TestEnum.values()).collect(Collectors.groupingBy(TestEnum::getDesc)));
}
- 輸出如下
Step1
3421
Step2
1234
Step3
1
Step4
[4]
Step5
{4=4}
Step6
[4, 5]
Step7
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Step8
12345
Step9
{1=TestEnum.EXCEL(super=EXCEL, code=1, desc=excel), 2=TestEnum.PPT(super=PPT, code=2, desc=ppt)}
Step10
{excel=[TestEnum.EXCEL(super=EXCEL, code=1, desc=excel)], ppt=[TestEnum.PPT(super=PPT, code=2, desc=ppt)]}
2.2說明
Lambda 表達(dá)式免去了使用匿名方法的麻煩
使用方法 | 對(duì)應(yīng)lambda表達(dá)式 |
---|---|
object::instanceMethod | (a,b,.....)->特定對(duì)象.實(shí)例方法(a,b....) |
Class::statucMethod | (a,b,.....)->類名.類方法(a,b....) |
Class::instanceMethod | (a,b,.....)->a.實(shí)例方法(b....) |
Class::new | (a,b,.....)->new 類名(a,b....) |
3.@functional懶加載應(yīng)用
模擬場(chǎng)景1,從redis獲取數(shù)據(jù)鼻疮。
模擬場(chǎng)景2怯伊,打印日志。
/**
* Consumer :
* 1.主要適用于沒有返回值的,
* 2.可以在方法內(nèi)部抽1個(gè)小方法判沟,注意該方法只能傳1個(gè)參數(shù)耿芹,且一定要簡(jiǎn)單崭篡,復(fù)雜的話還是直接抽方法,僅僅是處理代碼重復(fù)問題
* Supplier主要適用于有返回值的
* predicate
* 1.和consumer類似吧秕,可以在方法內(nèi)抽小方法琉闪,也只接受一個(gè)參數(shù)
* 2.接受傳參方式的判斷,可應(yīng)用于多個(gè)復(fù)雜判斷拆成小單元時(shí)再行組合砸彬,應(yīng)用場(chǎng)景少
* <p>
* 雖然只接收一個(gè)參數(shù)但可以是對(duì)象
*
* @author 876651109@qq.com
* @date 2021/2/10 9:25 上午
*/
public class Delay {
public static <T> T getFromRedisAndRefresh(String redisKey, Supplier<T> method) {
// 從redis獲取數(shù)據(jù)
T redisData = getKey(redisKey);
if (redisData != null) {
System.out.println("redis hit");
return redisData;
} else {
System.out.println("redis not hit");
T data = method.get();
System.out.println("redis refresh");
return data;
}
}
private static <T> T getKey(String redisKey) {
if (redisKey.equals("1")) {
return (T) new Integer(0);
}
return null;
}
public static void showLog(int level, Consumer method) {
// 日志級(jí)別等于3的時(shí)候輸出日志同時(shí)執(zhí)行計(jì)算颠毙,避免了傳統(tǒng)的先計(jì)算再判斷
if (level >= 4) {
method.accept(String.format("current level is %s", JSON.toJSONString(level)));
}
}
public static void main(String[] args) throws InterruptedException {
// 模擬場(chǎng)景1,從redis獲取數(shù)據(jù)砂碉。
// 輸出
int data1 = 1;
getFromRedisAndRefresh("1", () -> {
// 從數(shù)據(jù)庫(kù)拿到1
System.out.println("get From database" + data1);
return data1;
});
// 不輸出
int data2 = 2;
getFromRedisAndRefresh("2", () -> {
// 從數(shù)據(jù)庫(kù)拿到2
System.out.println("get From database" + data2);
return data2;
});
// 模擬場(chǎng)景2蛀蜜,打印日志。
// 不輸出
showLog(3, System.out::println);
// 輸出
showLog(4, System.out::println);
}
}
輸出如下,代表redisKey如果是1則直接返回redis結(jié)果redisKey如果是2則沒有命中增蹭,需要去數(shù)據(jù)庫(kù)加載滴某。日志級(jí)別大于等于4的時(shí)候輸出日志同時(shí)執(zhí)行計(jì)算,避免了傳統(tǒng)的先計(jì)算再判斷
redis hit
redis not hit
get From database2
redis refresh
current level is 4
4.非常用部分
這部分就不是個(gè)人感悟了滋迈,網(wǎng)上有各種使用霎奢,這里僅列舉部分場(chǎng)景
public static void predicate() {
Predicate<Integer> predicate = x -> x > 7;
System.out.println(predicate.test(10)); //輸出 true
System.out.println(predicate.test(6)); //輸出 fasle
/**
* 2、大于7并且
*/
//在上面大于7的條件下杀怠,添加是偶數(shù)的條件
predicate = predicate.and(x -> x % 2 == 0);
System.out.println(predicate.test(6)); //輸出 fasle
System.out.println(predicate.test(12)); //輸出 true
System.out.println(predicate.test(13)); //輸出 fasle
/**
* 3椰憋、add or 簡(jiǎn)化寫法
*/
predicate = x -> x > 5 && x < 9;
System.out.println(predicate.test(10)); //輸出 false
System.out.println(predicate.test(6)); //輸出 true
}
public static void reduce() {
// 從40開始,迭代+2赔退,共20個(gè)
List<Integer> list3 = Stream.iterate(40, n -> n + 2).limit(20).collect(Collectors.toList());
System.out.println(list3);
// 從10的基礎(chǔ)上全部相加
int reducedParams = Stream.of(1, 2, 3)
.reduce(10, (a, b) -> a + b, (a, b) -> {
return a + b;
});
System.out.println(reducedParams);
}