Java JSON提取工具JsonExtractor的使用
1. 問題場(chǎng)景
Java處理JSON數(shù)據(jù)通常的做法就是通過第三方庫將其轉(zhuǎn)換為一個(gè)Java類的對(duì)象,但是這樣會(huì)導(dǎo)致產(chǎn)生很多跟產(chǎn)品業(yè)務(wù)無關(guān)的臨時(shí)類。在JavaScript中,則可以直接提取,例如obj.user.name,非常方便。但是在Java中,如果不轉(zhuǎn)換為類的對(duì)象,就得小心翼翼地編寫像下面這樣的代碼:
try { JsonElement element = JsonParser.parseString(jsonStr); if (element.isJsonObject()) { JsonObject userJson = element.getAsJsonObject().getAsJsonObject("user"); if (userJson != null) { JsonPrimitive nameJson = userJson.getAsJsonPrimitive("name"); if (nameJson != null && nameJson.isString()) { String name = nameJson.getAsString(); } } } } catch (JsonParseException e) { e.printStackTrace(); }
這樣的方式非常繁瑣,而且里面充滿防御性的代碼,顯得羅嗦,關(guān)鍵信息其實(shí)只有jsonStr.user.name這樣。而本文要介紹的就是不將JSON數(shù)據(jù)轉(zhuǎn)換為某個(gè) Java Bean 對(duì)象來提取JSON數(shù)據(jù)內(nèi)容的一個(gè)工具類--JsonExtractor。
2. 功能介紹
這個(gè)類比較簡(jiǎn)單,但是方法不少,因此我將這個(gè)類里的方法分為兩類來講
2.1 構(gòu)建方法
如名,用于構(gòu)建JsonExtractor的方法,這里不推薦直接調(diào)用構(gòu)造方法,而是以下幾個(gè)方法來構(gòu)建
- 靜態(tài)方法Builder from(String json):這個(gè)方法是整個(gè)過程的開始,傳入?yún)?shù)為需要解析的JSON字符串,返回的對(duì)象是用于構(gòu)建JsonExtractor的建造者。
- 建造者方法JsonExtractor<Integer, JsonArray> forJsonArray():這個(gè)方法指定要處理的JSON數(shù)組是數(shù)組類型,返回對(duì)應(yīng)的處理JSON數(shù)組的提取器。
- 建造者方法JsonExtractor<Void, JsonNull> forNull():這個(gè)方法指定要處理的JSON數(shù)據(jù)是null,基本不用。
- 建造者方法JsonExtractor<Void, JsonPrimitive> forPrimitive():這個(gè)方法指定要處理的JSON數(shù)據(jù)是原始類型(例如,int、String等等),返回處理原始類型的提取器。
- 建造者方法JsonExtractor<String, JsonObject> forJsonObject():這個(gè)方法指定要處理的JSON數(shù)據(jù)是JSON對(duì)象,返回處理JSON對(duì)象的提取器,比較常用。
2.2 提取方法
這些方法的參數(shù)根據(jù)JsonExtractor的泛型K決定,如果當(dāng)前對(duì)象為數(shù)組,則K為Integer,表示數(shù)組的索引;如果是對(duì)象,則K為String,表示屬性對(duì)應(yīng)的鍵值;如果是原始類型或null,由于沒有下一級(jí)屬性或內(nèi)容,因此為Void。
- JsonArray getArray(K key):提取對(duì)應(yīng)鍵值的屬性為數(shù)組。
- Optional<JsonArray> optArray(K key):getArray的Optional版本。
- int getInt(K key):提取對(duì)應(yīng)鍵值的屬性為int,沒有則返回0。
- Optional<Integer> optInt(K key):getInt的Optional版本。
- boolean getBool(K key):提取對(duì)應(yīng)鍵值的屬性為boolean,沒有則返回false。
- Optional<Boolean> optBool(K key):getBool的Optional版本。
- long getLong(K key):提取對(duì)應(yīng)鍵值的屬性為long,沒有則返回0。
- Optional<Long> optLong(K key):getLong的Optional版本。
- String getString(K key):提取對(duì)應(yīng)鍵值的屬性為字符串,沒有則返回空字符串。
- Optional<String> optString(K key):getString的Optional版本。
- JsonElement get(K key)和<T> T get(K key, Class<T> typeClass):提取指定鍵值的屬性為JsonElement或指定Java類型。
- Optional<JsonElement> opt(K key)和<T> Optional<T> opt(K key, Class<T> typeClass):get的Optional版本。
- Builder into(K key):對(duì)指定鍵值的屬性進(jìn)行下一步提取,用于像data.user.name這樣的多級(jí)提取。
- void forEach(BiConsumer<K, JsonElement> entryConsumer):對(duì)JSON數(shù)據(jù)的內(nèi)容進(jìn)行遍歷。
3. 使用示例
例如,我們要提取的json如下:
{ "id": 1, "name": "Li Lei", "pet": { "name": "huahua", "type": "dog", "id": 11 }, "live": true, "age": 20, "friends": [ "James", "Andy", "Tom" ] }
對(duì)應(yīng)的 Java Bean 如下:
class Pet { ? ? private String name; ? ? private String type; ? ? private long id; ? ? public String getName() { ? ? ? ? return name; ? ? } ? ? public void setName(String name) { ? ? ? ? this.name = name; ? ? } ? ? public String getType() { ? ? ? ? return type; ? ? } ? ? public void setType(String type) { ? ? ? ? this.type = type; ? ? } ? ? public long getId() { ? ? ? ? return id; ? ? } ? ? public void setId(long id) { ? ? ? ? this.id = id; ? ? } } class User { ? ? private long id; ? ? private String name; ? ? private Pet pet; ? ? private boolean live; ? ? private int age; ? ? private String[] friends; ? ? public String[] getFriends() { ? ? ? ? return friends; ? ? } ? ? public void setFriends(String[] friends) { ? ? ? ? this.friends = friends; ? ? } ? ? public boolean isLive() { ? ? ? ? return live; ? ? } ? ? public void setLive(boolean live) { ? ? ? ? this.live = live; ? ? } ? ? public int getAge() { ? ? ? ? return age; ? ? } ? ? public void setAge(int age) { ? ? ? ? this.age = age; ? ? } ? ? public Pet getPet() { ? ? ? ? return pet; ? ? } ? ? public void setPet(Pet pet) { ? ? ? ? this.pet = pet; ? ? } ? ? public long getId() { ? ? ? ? return id; ? ? } ? ? public void setId(long id) { ? ? ? ? this.id = id; ? ? } ? ? public String getName() { ? ? ? ? return name; ? ? } ? ? public void setName(String name) { ? ? ? ? this.name = name; ? ? } }
那么提取代碼就是:
String json = "{\"id\":1,\"name\":\"Li Lei\",\"pet\":{\"name\":\"huahua\",\"type\":\"dog\",\"id\":11},\"live\":true,\"age\":20,\"friends\":[\"James\",\"Andy\",\"Tom\"]}"; JsonExtractor<String, JsonObject> extractor = JsonExtractor.from(json).forJsonObject(); //直接獲取屬性 long id = extractor.getLong("id"); //按Optional風(fēng)格獲取基本類型的屬性 extractor.optString("name").ifPresent((String name) -> { ? ? System.out.println("name:" + name); }); extractor.optString("name").ifPresent(System.out::println); //按Optional風(fēng)格獲取屬性并手動(dòng)轉(zhuǎn)換為指定類 extractor.opt("pet").ifPresent((JsonElement element) -> { ? ? System.out.println("pet json:" + element); ? ? Pet pet = new Gson().fromJson(element, Pet.class); ? ? System.out.println("pet bean 1:" + pet.getName()); }); //按Optional風(fēng)格獲取屬性自動(dòng)轉(zhuǎn)換為指定類 extractor.opt("pet", Pet.class).ifPresent((Pet pet) -> { ? ? System.out.println("pet bean 2:" + pet.getName()); }); //直接將屬性提取為指定類型 Pet pet = extractor.get("pet", Pet.class); //提取多級(jí)字段,類似js的 user.pet.name 這樣的風(fēng)格 extractor.into("pet").forJsonObject() ? ? ? ? .optString("name").ifPresent((String name) -> { ? ? ? ? ? ? System.out.println("pet.name:" + name); ? ? ? ? }); //提取并遍歷數(shù)組 extractor.into("friends").forJsonArray() ? ? ? ? .forEach((Integer index, JsonElement element) -> { ? ? ? ? ? ? System.out.println(index + ":" + element.getAsString()); ? ? ? ? });
4. 完整實(shí)現(xiàn)
import com.google.gson.*; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; public abstract class JsonExtractor<K, V> { ? ? private static final Gson gson = new Gson(); ? ? protected V jsonElement; ? ? JsonExtractor(V jsonElement) { ? ? ? ? this.jsonElement = jsonElement; ? ? } ? ? public V getJsonElement() { ? ? ? ? return jsonElement; ? ? } ? ? public static class Builder { ? ? ? ? private JsonElement element; ? ? ? ? protected Builder() { ? ? ? ? } ? ? ? ? public Builder(JsonElement element) { ? ? ? ? ? ? this.element = element; ? ? ? ? } ? ? ? ? public JsonExtractor<Void, JsonNull> forNull() { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return new NullExtractor(element.getAsJsonNull()); ? ? ? ? ? ? } catch (RuntimeException e) { ? ? ? ? ? ? ? ? return new ErrorExtractor<>(e); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? public JsonExtractor<Void, JsonPrimitive> forPrimitive() { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return new PrimitiveExtractor(element.getAsJsonPrimitive()); ? ? ? ? ? ? } catch (RuntimeException e) { ? ? ? ? ? ? ? ? return new ErrorExtractor<>(e); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? public JsonExtractor<String, JsonObject> forJsonObject() { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return new ObjectExtractor(element.getAsJsonObject()); ? ? ? ? ? ? } catch (RuntimeException e) { ? ? ? ? ? ? ? ? return new ErrorExtractor<>(e); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? public JsonExtractor<Integer, JsonArray> forJsonArray() { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return new ArrayExtractor(element.getAsJsonArray()); ? ? ? ? ? ? } catch (RuntimeException e) { ? ? ? ? ? ? ? ? return new ErrorExtractor<>(e); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? private static class ErrorBuilder extends Builder { ? ? ? ? private final Exception exception; ? ? ? ? public ErrorBuilder(Exception exception) { ? ? ? ? ? ? this.exception = exception; ? ? ? ? } ? ? ? ? @Override ? ? ? ? public JsonExtractor<Integer, JsonArray> forJsonArray() { ? ? ? ? ? ? return new ErrorExtractor<>(exception); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public JsonExtractor<Void, JsonNull> forNull() { ? ? ? ? ? ? return new ErrorExtractor<>(exception); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public JsonExtractor<Void, JsonPrimitive> forPrimitive() { ? ? ? ? ? ? return new ErrorExtractor<>(exception); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public JsonExtractor<String, JsonObject> forJsonObject() { ? ? ? ? ? ? return new ErrorExtractor<>(exception); ? ? ? ? } ? ? } ? ? public static Builder from(String json) { ? ? ? ? try { ? ? ? ? ? ? return new Builder(JsonParser.parseString(json)); ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? return new ErrorBuilder(e); ? ? ? ? } ? ? } ? ? public Builder into(K key) { ? ? ? ? return new ErrorBuilder(new RuntimeException("not implements!")); ? ? } ? ? public Optional<JsonElement> opt(K key) { ? ? ? ? return Optional.ofNullable(get(key)); ? ? } ? ? public <T> Optional<T> opt(K key, Class<T> typeClass) { ? ? ? ? return Optional.empty(); ? ? } ? ? public JsonElement get(K key) { ? ? ? ? return null; ? ? } ? ? public <T> T get(K key, Class<T> typeClass) { ? ? ? ? return opt(key, typeClass).orElse(null); ? ? } ? ? public JsonArray getArray(K key) { ? ? ? ? return null; ? ? } ? ? public Optional<JsonArray> optArray(K key) { ? ? ? ? return Optional.ofNullable(getArray(key)); ? ? } ? ? public int getInt(K key) { ? ? ? ? return optInt(key).orElse(0); ? ? } ? ? public Optional<Integer> optInt(K key) { ? ? ? ? return Optional.empty(); ? ? } ? ? public double getDouble(K key) { ? ? ? ? return optDouble(key).orElse(0d); ? ? } ? ? public Optional<Double> optDouble(K key) { ? ? ? ? return Optional.empty(); ? ? } ? ? public boolean getBool(K key) { ? ? ? ? return optBool(key).orElse(false); ? ? } ? ? public Optional<Boolean> optBool(K key) { ? ? ? ? return Optional.empty(); ? ? } ? ? public long getLong(K key) { ? ? ? ? return optLong(key).orElse(0L); ? ? } ? ? public Optional<Long> optLong(K key) { ? ? ? ? return Optional.empty(); ? ? } ? ? public String getString(K key) { ? ? ? ? return optString(key).orElse(""); ? ? } ? ? public Optional<String> optString(K key) { ? ? ? ? return Optional.empty(); ? ? } ? ? public void forEach(BiConsumer<K, JsonElement> entryConsumer) { ? ? } ? ? private static class ObjectExtractor extends JsonExtractor<String, JsonObject> { ? ? ? ? private ObjectExtractor(JsonObject jsonObject) { ? ? ? ? ? ? super(jsonObject); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Builder into(String key) { ? ? ? ? ? ? JsonElement element = this.jsonElement.get(key); ? ? ? ? ? ? return element == null ? new Builder(JsonNull.INSTANCE) : new Builder(element); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public JsonElement get(String key) { ? ? ? ? ? ? return this.jsonElement.getAsJsonObject(key); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<JsonArray> optArray(String key) { ? ? ? ? ? ? return Optional.ofNullable(this.jsonElement.getAsJsonArray(key)); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<Integer> optInt(String key) { ? ? ? ? ? ? return Optional.ofNullable(this.jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsInt); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<Double> optDouble(String key) { ? ? ? ? ? ? return Optional.ofNullable(jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsDouble); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<Boolean> optBool(String key) { ? ? ? ? ? ? return Optional.ofNullable(jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsBoolean); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<Long> optLong(String key) { ? ? ? ? ? ? return Optional.ofNullable(jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsLong); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<String> optString(String key) { ? ? ? ? ? ? return Optional.ofNullable(jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsString); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public <T> Optional<T> opt(String key, Class<T> typeClass) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return Optional.ofNullable(jsonElement.get(key)).map(e -> gson.fromJson(e, typeClass)); ? ? ? ? ? ? } catch (JsonSyntaxException e) { ? ? ? ? ? ? ? ? return Optional.empty(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public void forEach(BiConsumer<String, JsonElement> entryConsumer) { ? ? ? ? ? ? Set<Map.Entry<String, JsonElement>> entrySet = jsonElement.entrySet(); ? ? ? ? ? ? for (Map.Entry<String, JsonElement> entry : entrySet) { ? ? ? ? ? ? ? ? entryConsumer.accept(entry.getKey(), entry.getValue()); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? private static class ArrayExtractor extends JsonExtractor<Integer, JsonArray> { ? ? ? ? private ArrayExtractor(JsonArray array) { ? ? ? ? ? ? super(array); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Builder into(Integer index) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return new Builder(getJsonElement().get(index)); ? ? ? ? ? ? } catch (IndexOutOfBoundsException e) { ? ? ? ? ? ? ? ? return new ErrorBuilder(e); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public JsonElement get(Integer index) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return getJsonElement().get(index); ? ? ? ? ? ? } catch (IndexOutOfBoundsException e) { ? ? ? ? ? ? ? ? return null; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<JsonArray> optArray(Integer index) { ? ? ? ? ? ? return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsJsonArray); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<Integer> optInt(Integer index) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsInt); ? ? ? ? ? ? } catch (IndexOutOfBoundsException e) { ? ? ? ? ? ? ? ? return Optional.empty(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<Double> optDouble(Integer index) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsDouble); ? ? ? ? ? ? } catch (IndexOutOfBoundsException e) { ? ? ? ? ? ? ? ? return Optional.empty(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<Boolean> optBool(Integer index) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsBoolean); ? ? ? ? ? ? } catch (IndexOutOfBoundsException e) { ? ? ? ? ? ? ? ? return Optional.empty(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<Long> optLong(Integer index) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsLong); ? ? ? ? ? ? } catch (IndexOutOfBoundsException e) { ? ? ? ? ? ? ? ? return Optional.empty(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Optional<String> optString(Integer index) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsString); ? ? ? ? ? ? } catch (IndexOutOfBoundsException e) { ? ? ? ? ? ? ? ? return Optional.empty(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public <T> Optional<T> opt(Integer index, Class<T> typeClass) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? return Optional.ofNullable(getJsonElement().get(index)).map(e -> gson.fromJson(e, typeClass)); ? ? ? ? ? ? } catch (JsonSyntaxException e) { ? ? ? ? ? ? ? ? return Optional.empty(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public void forEach(BiConsumer<Integer, JsonElement> entryConsumer) { ? ? ? ? ? ? for (int i = 0; i < getJsonElement().size(); i++) { ? ? ? ? ? ? ? ? entryConsumer.accept(i, getJsonElement().get(i)); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? private static class NullExtractor extends JsonExtractor<Void, JsonNull> { ? ? ? ? NullExtractor(JsonNull jsonElement) { ? ? ? ? ? ? super(jsonElement); ? ? ? ? } ? ? } ? ? private static class PrimitiveExtractor extends JsonExtractor<Void, JsonPrimitive> { ? ? ? ? PrimitiveExtractor(JsonPrimitive jsonElement) { ? ? ? ? ? ? super(jsonElement); ? ? ? ? } ? ? } ? ? private static class ErrorExtractor<K, V> extends JsonExtractor<K, V> { ? ? ? ? private final Exception exception; ? ? ? ? private ErrorExtractor(Exception exception) { ? ? ? ? ? ? super(null); ? ? ? ? ? ? this.exception = exception; ? ? ? ? } ? ? ? ? @Override ? ? ? ? public Builder into(K key) { ? ? ? ? ? ? return new ErrorBuilder(exception); ? ? ? ? } ? ? } }
到此這篇關(guān)于Java JSON提取工具JsonExtractor的使用的文章就介紹到這了,更多相關(guān)Java JSON提取工具JsonExtractor內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot實(shí)現(xiàn)JPA多數(shù)據(jù)源配置小結(jié)
本文主要介紹了SpringBoot實(shí)現(xiàn)JPA多數(shù)據(jù)源配置小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01Java異常處理Guava?Throwables類使用實(shí)例解析
這篇文章主要為大家介紹了Java異常處理神器Guava?Throwables類使用深入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12繼承jpa?Repository?寫自定義方法查詢實(shí)例
這篇文章主要介紹了繼承jpa?Repository?寫自定義方法查詢實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12hadoop中實(shí)現(xiàn)java網(wǎng)絡(luò)爬蟲(示例講解)
下面小編就為大家?guī)硪黄猦adoop中實(shí)現(xiàn)java網(wǎng)絡(luò)爬蟲(示例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09IDEA中Directory創(chuàng)建多級(jí)目錄的實(shí)現(xiàn)
本文主要介紹了IDEA中Directory創(chuàng)建多級(jí)目錄的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06Java SimpleDateFormat線程安全問題原理詳解
這篇文章主要介紹了Java SimpleDateFormat線程安全問題原理詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05java并發(fā)使用CountDownLatch在生產(chǎn)環(huán)境翻車剖析
這篇文章主要為大家介紹了java并發(fā)使用CountDownLatch在生產(chǎn)環(huán)境翻車的示例剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08