Guava工具库实战

Guava工具库实战:Map、List、Splitter、Joiner高效使用

一、引言:为什么选择Guava?

在Java开发中,我们经常会遇到这样的痛点:

  • 创建不可变集合:JDK原生API过于繁琐
  • 处理null值:需要大量的判空代码
  • 字符串分割String.split()功能有限,无法优雅处理空白
  • 集合操作:缺少便捷的工具方法

Google Guava正是为了解决这些问题而生。它是Google开源的Java核心库,提供了大量优雅、高效的工具类,被Spring、Hibernate、MyBatis等众多知名框架广泛使用。

Guava的核心优势:

代码简洁 :一行代码完成复杂操作 ✅ 空值安全 :内置null处理机制 ✅ 性能优化 :经过Google生产环境验证 ✅ 易于使用:流畅的API设计,链式调用

本文将深入介绍Guava中最常用的四大工具:Map、List、Splitter、Joiner,通过真实案例展示它们在生产环境中的应用。

二、Guava Map:强大的映射集合

Guava提供了多种增强的Map实现,每种都针对特定场景优化。

2.1 ImmutableMap:不可变映射

特点:

  • 线程安全,无需同步
  • 创建后不可修改
  • 性能优于Collections.unmodifiableMap()
java 复制代码
import com.google.common.collect.ImmutableMap;

// 方式1:直接构建
ImmutableMap<String, Integer> map = ImmutableMap.of(
    "Java", 1,
    "Python", 2,
    "Go", 3
);

// 方式2:Builder模式(超过5个键值对时使用)
ImmutableMap<String, String> configMap = ImmutableMap.<String, String>builder()
    .put("db.host", "localhost")
    .put("db.port", "3306")
    .put("db.name", "test")
    .put("db.user", "root")
    .put("db.password", "123456")
    .build();

// 方式3:从已有Map复制
Map<String, Integer> originalMap = new HashMap<>();
originalMap.put("A", 1);
originalMap.put("B", 2);
ImmutableMap<String, Integer> immutableCopy = ImmutableMap.copyOf(originalMap);

生产案例:配置管理

java 复制代码
public class DatabaseConfig {

    // 环境配置映射,不可变且线程安全
    private static final ImmutableMap<String, String> ENV_CONFIG = ImmutableMap.of(
        "dev", "jdbc:mysql://dev-db:3306/app",
        "test", "jdbc:mysql://test-db:3306/app",
        "prod", "jdbc:mysql://prod-db:3306/app"
    );

    // HTTP状态码映射
    private static final ImmutableMap<Integer, String> HTTP_STATUS =
        ImmutableMap.<Integer, String>builder()
            .put(200, "OK")
            .put(201, "Created")
            .put(400, "Bad Request")
            .put(401, "Unauthorized")
            .put(403, "Forbidden")
            .put(404, "Not Found")
            .put(500, "Internal Server Error")
            .build();

    public static String getDbUrl(String env) {
        return ENV_CONFIG.getOrDefault(env, ENV_CONFIG.get("dev"));
    }

    public static String getStatusMessage(int code) {
        return HTTP_STATUS.getOrDefault(code, "Unknown Status");
    }
}

优势:

  • 避免了同步开销
  • 内存占用更少(优化的内部结构)
  • 编译期就能发现修改错误

2.2 BiMap:双向映射

BiMap允许你根据值反向查找键,非常适合双向映射场景。

基本用法:

java 复制代码
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;

// 创建BiMap
BiMap<String, Integer> userIdMap = HashBiMap.create();
userIdMap.put("Alice", 1001);
userIdMap.put("Bob", 1002);
userIdMap.put("Charlie", 1003);

// 正向查找
Integer aliceId = userIdMap.get("Alice");  // 1001

// 反向查找
BiMap<Integer, String> inverse = userIdMap.inverse();
String user = inverse.get(1002);  // "Bob"

// 注意:值必须唯一,否则抛出异常
userIdMap.put("David", 1001);  // 抛出IllegalArgumentException

// 强制替换
userIdMap.forcePut("David", 1001);  // Alice被移除,David映射到1001

生产案例:错误码管理

java 复制代码
public class ErrorCodeManager {

    // 错误码与消息的双向映射
    private static final BiMap<String, Integer> ERROR_CODES = HashBiMap.create();

    static {
        ERROR_CODES.put("USER_NOT_FOUND", 1001);
        ERROR_CODES.put("INVALID_PASSWORD", 1002);
        ERROR_CODES.put("ACCOUNT_LOCKED", 1003);
        ERROR_CODES.put("PERMISSION_DENIED", 1004);
    }

    // 根据错误名获取错误码
    public static Integer getErrorCode(String errorName) {
        return ERROR_CODES.get(errorName);
    }

    // 根据错误码获取错误名
    public static String getErrorName(Integer errorCode) {
        return ERROR_CODES.inverse().get(errorCode);
    }

    // 示例:日志记录
    public void logError(Integer errorCode) {
        String errorName = getErrorName(errorCode);
        System.out.println("Error [" + errorCode + "]: " + errorName);
    }
}

2.3 Multimap:一键多值映射

Multimap允许一个键对应多个值,避免了Map<K, List<V>>的繁琐操作。

基本用法:

java 复制代码
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

// 创建Multimap
Multimap<String, String> tagMap = ArrayListMultimap.create();

// 添加多个值
tagMap.put("Java", "Spring");
tagMap.put("Java", "MyBatis");
tagMap.put("Java", "Guava");
tagMap.put("Python", "Django");
tagMap.put("Python", "Flask");

// 获取某个键的所有值
Collection<String> javaTags = tagMap.get("Java");
// ["Spring", "MyBatis", "Guava"]

// 获取所有键值对
for (Map.Entry<String, String> entry : tagMap.entries()) {
    System.out.println(entry.getKey() + " -> " + entry.getValue());
}

// 移除特定值
tagMap.remove("Java", "MyBatis");

生产案例:文章标签系统

java 复制代码
public class ArticleTagService {

    // 文章ID -> 标签列表的映射
    private Multimap<Long, String> articleTags = ArrayListMultimap.create();

    // 添加标签
    public void addTag(Long articleId, String tag) {
        articleTags.put(articleId, tag);
    }

    // 批量添加标签
    public void addTags(Long articleId, List<String> tags) {
        articleTags.putAll(articleId, tags);
    }

    // 获取文章的所有标签
    public Collection<String> getTags(Long articleId) {
        return articleTags.get(articleId);
    }

    // 移除标签
    public void removeTag(Long articleId, String tag) {
        articleTags.remove(articleId, tag);
    }

    // 查找包含某标签的所有文章
    public List<Long> findArticlesByTag(String tag) {
        return articleTags.entries().stream()
            .filter(entry -> entry.getValue().equals(tag))
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());
    }
}

// 使用示例
ArticleTagService service = new ArticleTagService();
service.addTags(1001L, Arrays.asList("Java", "Spring", "后端"));
service.addTags(1002L, Arrays.asList("Java", "MyBatis", "数据库"));

Collection<String> tags = service.getTags(1001L);
// ["Java", "Spring", "后端"]

List<Long> javaArticles = service.findArticlesByTag("Java");
// [1001, 1002]

2.4 Table:双键映射表

Table提供了类似数据库表的结构,支持行键和列键。

基本用法:

java 复制代码
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

// 创建Table
Table<String, String, Integer> scoreTable = HashBasedTable.create();

// 添加数据(学生、科目、分数)
scoreTable.put("Alice", "Math", 95);
scoreTable.put("Alice", "English", 88);
scoreTable.put("Bob", "Math", 82);
scoreTable.put("Bob", "English", 90);

// 获取特定单元格的值
Integer aliceMath = scoreTable.get("Alice", "Math");  // 95

// 获取某一行
Map<String, Integer> aliceScores = scoreTable.row("Alice");
// {Math=95, English=88}

// 获取某一列
Map<String, Integer> mathScores = scoreTable.column("Math");
// {Alice=95, Bob=82}

生产案例:权限矩阵

java 复制代码
public class PermissionMatrix {

    // 用户角色、资源、权限的映射表
    private Table<String, String, Set<String>> permissionTable = HashBasedTable.create();

    public PermissionMatrix() {
        initPermissions();
    }

    private void initPermissions() {
        // 管理员权限
        permissionTable.put("ADMIN", "USER", Sets.newHashSet("CREATE", "READ", "UPDATE", "DELETE"));
        permissionTable.put("ADMIN", "ORDER", Sets.newHashSet("CREATE", "READ", "UPDATE", "DELETE"));

        // 普通用户权限
        permissionTable.put("USER", "USER", Sets.newHashSet("READ", "UPDATE"));
        permissionTable.put("USER", "ORDER", Sets.newHashSet("CREATE", "READ"));

        // 访客权限
        permissionTable.put("GUEST", "USER", Sets.newHashSet("READ"));
        permissionTable.put("GUEST", "ORDER", Sets.newHashSet("READ"));
    }

    // 检查权限
    public boolean hasPermission(String role, String resource, String action) {
        Set<String> permissions = permissionTable.get(role, resource);
        return permissions != null && permissions.contains(action);
    }

    // 获取角色在某资源上的所有权限
    public Set<String> getPermissions(String role, String resource) {
        return permissionTable.get(role, resource);
    }
}

三、Guava List:强大的列表工具

3.1 ImmutableList:不可变列表

基本用法:

java 复制代码
import com.google.common.collect.ImmutableList;

// 方式1:直接构建
ImmutableList<String> languages = ImmutableList.of("Java", "Python", "Go");

// 方式2:Builder模式
ImmutableList<Integer> numbers = ImmutableList.<Integer>builder()
    .add(1, 2, 3)
    .add(4, 5)
    .build();

// 方式3:从已有集合复制
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
ImmutableList<String> immutableCopy = ImmutableList.copyOf(list);

3.2 Lists工具类

创建列表:

java 复制代码
import com.google.common.collect.Lists;

// 创建ArrayList并初始化
List<String> list = Lists.newArrayList("a", "b", "c");

// 创建指定容量的ArrayList
List<String> listWithCapacity = Lists.newArrayListWithCapacity(100);

// 创建LinkedList
List<Integer> linkedList = Lists.newLinkedList();

列表分割:

java 复制代码
// 将大列表分割为固定大小的子列表
List<Integer> bigList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<List<Integer>> partitions = Lists.partition(bigList, 3);

// 结果:[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
for (List<Integer> partition : partitions) {
    System.out.println(partition);
}

生产案例:批量处理

java 复制代码
public class BatchProcessor {

    private static final int BATCH_SIZE = 100;

    // 批量插入数据
    public void batchInsert(List<User> users) {
        // 将用户列表分割为每100个一批
        List<List<User>> batches = Lists.partition(users, BATCH_SIZE);

        for (List<User> batch : batches) {
            // 批量插入到数据库
            userDao.batchInsert(batch);

            // 避免过快的插入导致数据库压力
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    // 批量发送通知
    public void batchNotify(List<Long> userIds, String message) {
        Lists.partition(userIds, 50).forEach(batch -> {
            // 每批最多50个用户
            notificationService.sendBatch(batch, message);
        });
    }
}

列表反转:

java 复制代码
List<String> list = Lists.newArrayList("A", "B", "C", "D");
List<String> reversed = Lists.reverse(list);
// ["D", "C", "B", "A"]

列表转换:

java 复制代码
List<String> names = Lists.newArrayList("alice", "bob", "charlie");

// 转换为大写
List<String> upperNames = Lists.transform(names, String::toUpperCase);
// ["ALICE", "BOB", "CHARLIE"]

// 注意:transform返回的是视图,不是新列表

笛卡尔积:

java 复制代码
List<String> colors = Lists.newArrayList("Red", "Green");
List<String> sizes = Lists.newArrayList("S", "M", "L");

List<List<String>> product = Lists.cartesianProduct(colors, sizes);
// [[Red, S], [Red, M], [Red, L], [Green, S], [Green, M], [Green, L]]

生产案例:商品SKU生成

java 复制代码
public class ProductSkuGenerator {

    public List<ProductSku> generateSkus(Product product) {
        // 获取所有属性值
        List<String> colors = product.getColors();      // ["黑色", "白色"]
        List<String> sizes = product.getSizes();        // ["S", "M", "L"]
        List<String> materials = product.getMaterials(); // ["棉质", "涤纶"]

        // 计算笛卡尔积
        List<List<String>> combinations = Lists.cartesianProduct(
            colors, sizes, materials
        );

        // 生成SKU
        return combinations.stream()
            .map(combo -> {
                ProductSku sku = new ProductSku();
                sku.setProductId(product.getId());
                sku.setColor(combo.get(0));
                sku.setSize(combo.get(1));
                sku.setMaterial(combo.get(2));
                sku.setSkuCode(generateSkuCode(combo));
                return sku;
            })
            .collect(Collectors.toList());
    }

    private String generateSkuCode(List<String> attributes) {
        return Joiner.on("-").join(attributes);
    }
}

四、Splitter:智能字符串分割

JDK的String.split()存在诸多问题:无法优雅处理空白、空字符串等。Guava的Splitter提供了更强大的功能。

4.1 基础用法

java 复制代码
import com.google.common.base.Splitter;

// 按逗号分割
String str = "a,b,c,d";
Iterable<String> parts = Splitter.on(',').split(str);
// ["a", "b", "c", "d"]

// 转换为List
List<String> list = Splitter.on(',').splitToList(str);

4.2 处理空白和空字符串

java 复制代码
String messyStr = "a,b,,c, ,d,  ,e";

// 去除空格并忽略空字符串
List<String> cleaned = Splitter.on(',')
    .trimResults()           // 去除每个元素的首尾空格
    .omitEmptyStrings()      // 忽略空字符串
    .splitToList(messyStr);

// 结果:["a", "b", "c", "d", "e"]

对比JDK方式:

java 复制代码
// JDK方式:繁琐且容易出错
String[] parts = messyStr.split(",");
List<String> result = new ArrayList<>();
for (String part : parts) {
    String trimmed = part.trim();
    if (!trimmed.isEmpty()) {
        result.add(trimmed);
    }
}

// Guava方式:一行搞定
List<String> result = Splitter.on(',')
    .trimResults()
    .omitEmptyStrings()
    .splitToList(messyStr);

4.3 限制分割次数

java 复制代码
String str = "key:value:extra:data";

// 最多分割为2部分
List<String> parts = Splitter.on(':')
    .limit(2)
    .splitToList(str);

// 结果:["key", "value:extra:data"]

4.4 MapSplitter:分割为Map

java 复制代码
String queryString = "name=Alice&age=25&city=Beijing";

// 分割为Map
Map<String, String> params = Splitter.on('&')
    .withKeyValueSeparator('=')
    .split(queryString);

// 结果:{name=Alice, age=25, city=Beijing}

生产案例:URL参数解析

java 复制代码
public class UrlParamParser {

    private static final Splitter.MapSplitter PARAM_SPLITTER =
        Splitter.on('&')
            .trimResults()
            .omitEmptyStrings()
            .withKeyValueSeparator('=');

    // 解析URL参数
    public Map<String, String> parseQueryString(String url) {
        int questionMarkIndex = url.indexOf('?');
        if (questionMarkIndex == -1) {
            return Collections.emptyMap();
        }

        String queryString = url.substring(questionMarkIndex + 1);
        return PARAM_SPLITTER.split(queryString);
    }

    // 示例使用
    public static void main(String[] args) {
        UrlParamParser parser = new UrlParamParser();

        String url = "https://api.example.com/search?keyword=guava&page=1&size=20";
        Map<String, String> params = parser.parseQueryString(url);

        System.out.println("关键词: " + params.get("keyword"));  // guava
        System.out.println("页码: " + params.get("page"));      // 1
        System.out.println("大小: " + params.get("size"));      // 20
    }
}

4.5 正则表达式分割

java 复制代码
String log = "2024-01-15 10:30:45 ERROR User not found";

// 按空格分割
List<String> parts = Splitter.onPattern("\\s+")
    .splitToList(log);

// 结果:["2024-01-15", "10:30:45", "ERROR", "User", "not", "found"]

生产案例:日志解析

java 复制代码
public class LogParser {

    private static final Splitter LOG_SPLITTER = Splitter.onPattern("\\s+")
        .limit(4);

    public LogEntry parseLog(String logLine) {
        List<String> parts = LOG_SPLITTER.splitToList(logLine);

        if (parts.size() < 4) {
            throw new IllegalArgumentException("Invalid log format");
        }

        LogEntry entry = new LogEntry();
        entry.setDate(parts.get(0));
        entry.setTime(parts.get(1));
        entry.setLevel(parts.get(2));
        entry.setMessage(parts.get(3));  // 剩余部分作为消息

        return entry;
    }
}

4.6 固定长度分割

java 复制代码
String str = "123456789012";

// 每3个字符分割
Iterable<String> parts = Splitter.fixedLength(3).split(str);
// ["123", "456", "789", "012"]

五、Joiner:优雅的字符串连接

5.1 基础用法

java 复制代码
import com.google.common.base.Joiner;

List<String> list = Arrays.asList("Google", "Guava", "Java");

// 用逗号连接
String result = Joiner.on(", ").join(list);
// "Google, Guava, Java"

// 用换行符连接
String multiLine = Joiner.on("\n").join(list);

5.2 处理null值

java 复制代码
List<String> listWithNull = Arrays.asList("A", null, "B", "C");

// 跳过null值
String skipNull = Joiner.on(", ")
    .skipNulls()
    .join(listWithNull);
// "A, B, C"

// 用默认值替换null
String useForNull = Joiner.on(", ")
    .useForNull("N/A")
    .join(listWithNull);
// "A, N/A, B, C"

5.3 连接Map

java 复制代码
Map<String, String> map = new LinkedHashMap<>();
map.put("host", "localhost");
map.put("port", "8080");
map.put("path", "/api");

// 连接Map为字符串
String mapStr = Joiner.on("&")
    .withKeyValueSeparator("=")
    .join(map);

// 结果:"host=localhost&port=8080&path=/api"

生产案例:生成URL查询参数

java 复制代码
public class UrlBuilder {

    private static final Joiner.MapJoiner QUERY_JOINER =
        Joiner.on('&').withKeyValueSeparator('=');

    private String baseUrl;
    private Map<String, String> params = new LinkedHashMap<>();

    public UrlBuilder(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    public UrlBuilder addParam(String key, String value) {
        if (value != null) {
            params.put(key, value);
        }
        return this;
    }

    public String build() {
        if (params.isEmpty()) {
            return baseUrl;
        }
        return baseUrl + "?" + QUERY_JOINER.join(params);
    }

    // 示例使用
    public static void main(String[] args) {
        String url = new UrlBuilder("https://api.example.com/search")
            .addParam("q", "guava")
            .addParam("page", "1")
            .addParam("size", "20")
            .build();

        System.out.println(url);
        // https://api.example.com/search?q=guava&page=1&size=20
    }
}

5.4 追加到StringBuilder

java 复制代码
StringBuilder sb = new StringBuilder("Results: ");
List<String> items = Arrays.asList("A", "B", "C");

Joiner.on(", ").appendTo(sb, items);
// sb内容:"Results: A, B, C"

生产案例:SQL生成

java 复制代码
public class SqlBuilder {

    public String buildInsertSql(String tableName, Map<String, Object> data) {
        List<String> columns = new ArrayList<>(data.keySet());
        List<String> placeholders = Collections.nCopies(columns.size(), "?");

        StringBuilder sql = new StringBuilder("INSERT INTO ");
        sql.append(tableName).append(" (");

        Joiner.on(", ").appendTo(sql, columns);
        sql.append(") VALUES (");
        Joiner.on(", ").appendTo(sql, placeholders);
        sql.append(")");

        return sql.toString();
    }

    // 示例
    public static void main(String[] args) {
        SqlBuilder builder = new SqlBuilder();

        Map<String, Object> data = new LinkedHashMap<>();
        data.put("name", "Alice");
        data.put("age", 35);
        data.put("email", "alice@example.com");

        String sql = builder.buildInsertSql("users", data);
        System.out.println(sql);
        // INSERT INTO users (name, age, email) VALUES (?, ?, ?)
    }
}

六、Guava vs JDK:性能与易用性对比

6.1 代码简洁度对比

场景:创建不可变Map

java 复制代码
// JDK方式
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
Map<String, Integer> immutableMap = Collections.unmodifiableMap(map);

// Guava方式
ImmutableMap<String, Integer> immutableMap = ImmutableMap.of(
    "A", 1,
    "B", 2,
    "C", 3
);

场景:字符串分割并处理空白

java 复制代码
// JDK方式
String str = "a,b,,c, ,d";
String[] parts = str.split(",");
List<String> result = new ArrayList<>();
for (String part : parts) {
    String trimmed = part.trim();
    if (!trimmed.isEmpty()) {
        result.add(trimmed);
    }
}

// Guava方式
List<String> result = Splitter.on(',')
    .trimResults()
    .omitEmptyStrings()
    .splitToList(str);

6.2 性能对比

Guava在很多场景下性能优于JDK:

ImmutableMap vs HashMap:

  • 内存占用:ImmutableMap更少(优化的数据结构)
  • 访问速度:ImmutableMap略快(无锁开销)
  • 线程安全:ImmutableMap无需同步

Splitter vs String.split():

  • 复用性:Splitter可复用,避免重复编译正则
  • 灵活性:Splitter支持链式配置

七、生产实战案例

案例一:CSV文件解析

java 复制代码
public class CsvParser {

    private static final Splitter CSV_SPLITTER = Splitter.on(',')
        .trimResults()
        .omitEmptyStrings();

    public List<User> parseCsvFile(String filePath) throws IOException {
        List<User> users = new ArrayList<>();

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            // 跳过标题行
            String header = reader.readLine();

            String line;
            while ((line = reader.readLine()) != null) {
                List<String> fields = CSV_SPLITTER.splitToList(line);

                if (fields.size() >= 3) {
                    User user = new User();
                    user.setName(fields.get(0));
                    user.setAge(Integer.parseInt(fields.get(1)));
                    user.setEmail(fields.get(2));
                    users.add(user);
                }
            }
        }

        return users;
    }
}

案例二:配置文件解析

java 复制代码
public class ConfigLoader {

    private static final Splitter.MapSplitter CONFIG_SPLITTER =
        Splitter.on('\n')
            .trimResults()
            .omitEmptyStrings()
            .withKeyValueSeparator('=');

    public ImmutableMap<String, String> loadConfig(String configText) {
        // 移除注释行
        String cleanedConfig = Splitter.on('\n')
            .splitToStream(configText)
            .filter(line -> !line.trim().startsWith("#"))
            .collect(Collectors.joining("\n"));

        return ImmutableMap.copyOf(CONFIG_SPLITTER.split(cleanedConfig));
    }
}

案例三:生成缓存Key

java 复制代码
public class CacheKeyGenerator {

    private static final Joiner KEY_JOINER = Joiner.on(':').skipNulls();

    // 生成用户缓存键
    public String generateUserKey(Long userId) {
        return KEY_JOINER.join("user", userId);
        // "user:12345"
    }

    // 生成订单缓存键
    public String generateOrderKey(String userId, String orderId) {
        return KEY_JOINER.join("order", userId, orderId);
        // "order:user123:order456"
    }

    // 生成商品缓存键(带分类)
    public String generateProductKey(String category, String productId) {
        return KEY_JOINER.join("product", category, productId);
        // "product:electronics:prod789"
    }
}

八、最佳实践与注意事项

8.1 Splitter和Joiner复用

Splitter和Joiner是不可变的,应该声明为静态常量复用:

java 复制代码
public class Constants {
    // 推荐:声明为静态常量
    private static final Splitter COMMA_SPLITTER = Splitter.on(',')
        .trimResults()
        .omitEmptyStrings();

    private static final Joiner COMMA_JOINER = Joiner.on(',').skipNulls();

    // 不推荐:每次都创建新实例
    public void badExample(String str) {
        List<String> parts = Splitter.on(',').splitToList(str);  // 每次创建
    }
}

8.2 ImmutableMap的大小限制

ImmutableMap.of()最多支持5个键值对,超过需要使用Builder:

java 复制代码
// 错误:超过5个键值对会编译错误
ImmutableMap<String, Integer> map = ImmutableMap.of(
    "A", 1, "B", 2, "C", 3, "D", 4, "E", 5, "F", 6  // 编译错误
);

// 正确:使用Builder
ImmutableMap<String, Integer> map = ImmutableMap.<String, Integer>builder()
    .put("A", 1)
    .put("B", 2)
    .put("C", 3)
    .put("D", 4)
    .put("E", 5)
    .put("F", 6)
    .build();

8.3 BiMap的值唯一性

BiMap要求值必须唯一,重复会抛异常:

java 复制代码
BiMap<String, Integer> map = HashBiMap.create();
map.put("A", 1);
map.put("B", 1);  // 抛出IllegalArgumentException

// 使用forcePut强制替换
map.forcePut("B", 1);  // A被移除,B映射到1

8.4 Lists.transform()的视图特性

transform()返回的是视图,不是新列表:

java 复制代码
List<String> original = Lists.newArrayList("a", "b", "c");
List<String> transformed = Lists.transform(original, String::toUpperCase);

// 修改原列表会影响视图
original.set(0, "x");
System.out.println(transformed.get(0));  // "X"

// 如果需要独立的列表,应该复制
List<String> independent = new ArrayList<>(transformed);

九、总结

Guava工具库为Java开发提供了强大而优雅的解决方案:

Map工具:

  • ✅ ImmutableMap:线程安全的不可变映射
  • ✅ BiMap:双向查找的映射
  • ✅ Multimap:一键多值的便捷操作
  • ✅ Table:双键映射的强大功能

List工具:

  • ✅ ImmutableList:不可变列表
  • ✅ Lists.partition():批量处理的利器
  • ✅ Lists.transform():函数式转换

Splitter:

  • ✅ 智能处理空白和null
  • ✅ 链式API,代码更简洁
  • ✅ MapSplitter解析键值对

Joiner:

  • ✅ 优雅的字符串连接
  • ✅ 灵活的null处理
  • ✅ Map和集合的统一连接
相关推荐
while(1){yan}2 小时前
JAVA中如何操作文件
java·开发语言·面试
SuperherRo2 小时前
JAVA攻防-FastJson专题&各版本Gadget链&autoType开关&黑名单&依赖包&本地代码
java·fastjson·1.2.24·1.2.47·1.2.62·1.2.80
爬山算法2 小时前
Netty(5)Netty的ByteBuf是什么?它与Java NIO的ByteBuffer有何不同?
java·开发语言·nio
爱笑的眼睛112 小时前
超越SIFT与ORB:深入OpenCV特征检测API的设计哲学与高阶实践
java·人工智能·python·ai
JH30732 小时前
Java 是值传递:深入理解参数传递机制
java·开发语言·windows
CS创新实验室2 小时前
计算机考研408【操作系统】核心知识点总结
java·linux·考研·计算机·操作系统·408
while(1){yan}2 小时前
文件IO的常识
java·开发语言·青少年编程·电脑常识
Light602 小时前
再见,REST API?你好,MCP Server!AI时代后端开发新范式
java·人工智能·rest api·ai agent·spring ai·mcp
逸风尊者2 小时前
开发需掌握的知识:MQTT协议
java·后端