一文教你如何通過(guò) Stream API 批量 Mock 數(shù)據(jù)
在日常開發(fā)的過(guò)程中我們經(jīng)常會(huì)遇到需要 mock? 一些數(shù)據(jù)的場(chǎng)景,比如說(shuō) mock? 一些接口的返回或者說(shuō) mock? 一些測(cè)試消息用于隊(duì)列生產(chǎn)者發(fā)送消息,可能很多時(shí)候我們都是使用一些固定的 case? 或者一條相同的數(shù)據(jù)重復(fù)使用。今天阿粉就教大家用 Stream 去構(gòu)造一些偽真實(shí)的一些數(shù)據(jù)。
Mock 任意個(gè) UUID
首先我們通過(guò)普通寫法來(lái)構(gòu)造 100 個(gè) UUID,代碼如下相信大家都會(huì)寫,就不多說(shuō)了。
public static List<UUID> listUUID(int size) {
List<UUID> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
UUID uuid = UUID.randomUUID();
list.add(uuid);
}
return list;
}
下面再提供 Stream 的寫法,代碼如下,一行搞定
public static List<UUID> listUUID2(int size) {
return Stream.generate(UUID::randomUUID).limit(size).collect(Collectors.toList());
}
這里我們使用了 Stream? 的 generate? 方法,該方法接收一個(gè) Supplier? 類型的參數(shù),Supplier? 是一個(gè)功能接口,只有一個(gè) get? 方法,返回一個(gè)對(duì)象,不接收任何參數(shù),上面我們就是通過(guò) UUID? 靜態(tài)引用的方式獲得一個(gè) UUID? 對(duì)象,另外我們使用 limit 方法來(lái)進(jìn)行截?cái)嘀猾@取 100 個(gè)。
Mock 消息
接下來(lái)我們?cè)偈褂?nbsp;Stream API 批量構(gòu)造一批消息,作為隊(duì)列的生產(chǎn)者進(jìn)行數(shù)據(jù)發(fā)送
定義消息體
package com.example.demo.dto;
/**
* <br>
* <b>Function:</b><br>
* <b>Author:</b>@author Java 極客技術(shù)<br>
* <b>Date:</b>2022-09-03 11:49<br>
* <b>Desc:</b>無(wú)<br>
*/
public class Message {
int id;
String message;
public Message(int id, String message) {
this.id = id;
this.message = message;
}
@Override
public String toString() {
return "Message{" +
"id=" + id +
", message='" + message + '\'' +
'}';
}
}
測(cè)試代碼
public static void main(String[] args) {
List<Message> messages = genMessage(10);
messages.forEach(System.out::println);
}
public static List<Message> genMessage(int size) {
AtomicInteger atomicInteger = new AtomicInteger();
Supplier<Message> supplier = () -> {
Message message = new Message(new Random().nextInt(), "Message : " + atomicInteger.getAndIncrement());
System.out.println("inner:" + message.toString());
return message;
};
System.out.println(99);
return Stream.generate(supplier).limit(size).collect(Collectors.toList());
}
先看下運(yùn)行結(jié)果,我們?cè)賮?lái)分析,可以看到第一個(gè) case? 我們是使用靜態(tài)引用來(lái)返回一個(gè) UUID? 對(duì)象,這個(gè) case? 我們通過(guò)創(chuàng)建 lambda? 表達(dá)式的形式來(lái)實(shí)現(xiàn)一個(gè) Supplier?,在表達(dá)式中我們進(jìn)行 message? 對(duì)象的構(gòu)造,然后進(jìn)行返回。其實(shí)上文的靜態(tài)引用,本質(zhì)上也是一個(gè) lambda,所以跟下面的實(shí)現(xiàn)是一個(gè)原理,只不過(guò)是一些語(yǔ)法糖而已。
public static List<UUID> listUUID2(int size) {
Supplier<UUID> supplier = () -> UUID.randomUUID();
return Stream.generate(supplier).limit(size).collect(Collectors.toList());
}
如果對(duì) Stream? 流有理解的可以看到,我們這里有兩個(gè)點(diǎn)需要注意,一個(gè)是我們這里的輸出 99 是在 inner? 之前的,另一個(gè)是我們這里使用的 limit 方法,不然會(huì)一直進(jìn)行輸出不會(huì)停止的,這兩點(diǎn)其實(shí)都是流的基本特性,就不多說(shuō)了。
Supplier 是個(gè)啥
上文提到 Stream? 的 generate? 方法接收的是一個(gè) Supplier? 類型的參數(shù),那么這個(gè) Supplier 是個(gè)啥呢?我們來(lái)仔細(xì)看一下。
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
通過(guò)代碼我們可以看到首先 Supplier? 是個(gè)接口,既然是接口那就可以進(jìn)行具體的實(shí)現(xiàn),并且這個(gè)接口只有一個(gè)方法 get? 返回指定的類型,同時(shí)該接口還有一個(gè) @FunctionalInterface 注解,表名這個(gè)接口是一個(gè)函數(shù)是編程的接口,函數(shù)式接口是指僅僅只包含一個(gè)抽象方法的接口。
我們看到這個(gè)注解的 javadoc? 里面大概的意思是這個(gè)注解是用來(lái)標(biāo)識(shí)一個(gè)函數(shù)接口,函數(shù)式接口只有一個(gè)抽象方法,但是如果有 default? 方法或者覆蓋了 Object? 的 public? 方法都不算是抽象方法。還有一句講的是函數(shù)式接口可以通過(guò) lambda? 表達(dá)式,方法引用或者構(gòu)造方法引用來(lái)創(chuàng)建。我們上面的兩個(gè)例子演示了 lambda 表達(dá)式和方法引用,構(gòu)造函數(shù)其實(shí)也一樣。
所以總結(jié)來(lái)說(shuō) Stream? 的 generate? 方法通過(guò)接收一個(gè) Supplier? 類型的參數(shù)來(lái)創(chuàng)建一個(gè)數(shù)據(jù)流,得到數(shù)據(jù)流以后就可以進(jìn)行各種流的操作了。我們這篇文章更多的是通過(guò) Stream? 來(lái)構(gòu)造 mock? 數(shù)據(jù),創(chuàng)建一個(gè)流,對(duì)于流的各種操作就不在本文的討論范圍之內(nèi)了,阿粉之前也有相應(yīng)的文章介紹過(guò) Stream 感興趣的小伙伴可以去翻翻看。
總結(jié)
工作中 mock? 數(shù)據(jù)在很多場(chǎng)景都會(huì)遇到,但是可能很多時(shí)候我們都不會(huì)太關(guān)注 mock? 的數(shù)據(jù)的形式,雖然說(shuō)一個(gè)循環(huán)也可以 mock 到相應(yīng)的數(shù)據(jù),但是能寫的優(yōu)雅一點(diǎn)為什么我們不寫的優(yōu)雅一點(diǎn)呢?