1、Bytes
Guava 中的 Bytes(属于 com.google.common.primitives 包)是针对原生 byte 类型以及 byte[] 数组操作的静态工具类。
由于 Java 标准库中的 java.util.Arrays 对原生数组的支持较为基础,Bytes 补充了大量的查找、拼接、转换与判定功能。
1.1、核心API
Bytes 的所有 API 均为静态方法,主要分为以下五大类:
| 分类 | 核心 API 方法 | 说明 |
|---|---|---|
| 查找与判定 | contains, indexOf, lastIndexOf | 查找单个字节或子数组(byte[])的位置 |
| 数组拼接 | concat | 将多个 byte[] 数组合并为一个新数组 |
| 大小与扩容 | ensureCapacity | 确保数组具备最小长度,不足时自动扩容填充 0 |
| 类型与集合转换 | asList, toArray | 原生 byte[] 与包装对象列表 List<Byte> 的双向转换 |
| 比较 | lexicographicalComparator | 获取字节数组的字典序比较器(Lexicographical Comparator) |
1.2、使用示例
1.2.1、元素与子数组查找
除了查找单个 byte,Bytes 极具特色的一点是直接支持查找连续的子字节数组(Target Subarray)。
import com.google.common.primitives.Bytes;
public class BytesSearchDemo {
public static void main(String[] args) {
byte[] array = {0x01, 0x02, 0x03, 0x04, 0x02, 0x03};
// 1. 查找单个 byte
boolean hasThree = Bytes.contains(array, (byte) 0x03); // true
int firstIdx = Bytes.indexOf(array, (byte) 0x02); // 1
int lastIdx = Bytes.lastIndexOf(array, (byte) 0x02); // 4
// 2. 查找子数组 (Target Subarray) 在原数组中的匹配起始位置
byte[] target = {0x02, 0x03};
int targetIdx = Bytes.indexOf(array, target); // 1
System.out.println("包含 0x03: " + hasThree);
System.out.println("子数组 {0x02, 0x03} 匹配索引: " + targetIdx);
}
}
包含 0x03: true
子数组 {0x02, 0x03} 匹配索引: 1
1.2.2、数组合并
将多个独立的 byte[] 组合成一个新的单一 byte[],避免手动创建新数组和多次调用 System.arraycopy。
import com.google.common.primitives.Bytes;
public class BytesConcatDemo {
public static void main(String[] args) {
byte[] header = {0x10, 0x20};
byte[] body = {0x30, 0x40, 0x50};
byte[] footer = {0x60};
// 拼接任意数量的 byte[]
byte[] packet = Bytes.concat(header, body, footer);
// 输出长度为 6 的数组: [16, 32, 48, 64, 80, 96]
System.out.println("合并后长度: " + packet.length);
}
}
合并后长度: 6
1.2.3、数组动态扩容
类似 ArrayList 的扩容机制,保证 byte[] 满足最小长度条件。如果原始数组长度不足,会重新分配并补零填充。
import com.google.common.primitives.Bytes;
public class BytesCapacityDemo {
public static void main(String[] args) {
byte[] buffer = {0x01, 0x02};
// ensureCapacity(array, minLength, padding)
// 如果 buffer.length < 5,则返回长度为 5 + 2 = 7 的新数组,原元素会被复制过去
byte[] expanded = Bytes.ensureCapacity(buffer, 5, 2);
System.out.println("扩容后新数组长度: " + expanded.length); // 7
}
}
扩容后新数组长度: 7
1.2.4、原生数组与集合的双向转换
- asList(byte… backingArray):返回一个由原数组作为底层支撑(Backing Array)的 List 视图。
- toArray(Collection<? extends Number> collection):将包装类集合安全转换为原生 byte[]。
注意:Bytes.asList() 返回的 List 是固定大小的(写操作如 set() 会直接改变原数组,但无法 add() 或 remove())。
import com.google.common.primitives.Bytes;
import java.util.Arrays;
import java.util.List;
public class BytesConvertDemo {
public static void main(String[] args) {
// 1. byte[] 转 List<Byte>
byte[] origin = {1, 2, 3};
List<Byte> byteList = Bytes.asList(origin);
// 修改 List 中的值会直接联动影响原始 byte[] 数组
byteList.set(0, (byte) 99);
System.out.println("原数组第 0 位被修改为: " + origin[0]); // 99
// 2. 集合转 byte[]
List<Integer> numberList = Arrays.asList(10, 20, 30);
byte[] byteArray = Bytes.toArray(numberList); // 自动进行 Number.byteValue() 转换
System.out.println("转换后的 byte[] 长度: " + byteArray.length); // 3
}
}
原数组第 0 位被修改为: 99
转换后的 byte[] 长度: 3
1.2.5、字典序比较
用于对比两个 byte[] 在字典序上的大小关系(逐个字节按无符号/有符号对比),常用于存储引擎或网络协议的 Key 比较。
import com.google.common.primitives.Bytes;
import java.util.Comparator;
public class BytesCompareDemo {
public static void main(String[] args) {
byte[] a = {1, 2, 3};
byte[] b = {1, 2, 4};
Comparator<byte[]> comparator = Bytes.lexicographicalComparator();
int result = comparator.compare(a, b);
if (result < 0) {
System.out.println("数组 a 字典序小于 数组 b");
}
}
}
2、Shorts
Guava 中的 Shorts(属于 com.google.common.primitives 包)是专门针对原生 short 类型以及 short[] 数组操作的静态工具类。
它补足了 JDK 对 short 类型支持较弱的短板,提供了高频使用的查找、转换、比较、位操作与数组处理功能。
2.1、核心API
| 分类 | 核心 API | 说明 |
|---|---|---|
| 数值安全与界限 | saturatingCast, checkedCast | 将 long 类型安全地强转为 short |
| 数值比较与限制 | min, max, constrainToRange, compare | 最值求解、区间截断限制、数值比较 |
| 数组查找与判定 | contains, indexOf, lastIndexOf | 查找单个 short 或子数组(short[])的匹配索引 |
| 数组操作与拼接 | concat, ensureCapacity, reverse | 数组合并、自动扩容、原位反转 |
| 字节/二进制序列化 | toByteArray, fromByteArray, fromBytes | short 与 byte[](大端序/Big-Endian)互转 |
| 集合与字符串转换 | asList, toArray, join, stringConverter | 原生数组与 List<Short> 互转,字符串拼接与解析转换 |
2.2、使用示例
2.2.1、类型转换与安全强转
将范围较大的整数类型(如 long 或 int)转为 short 时,标准 Java 的直接强转会导致高位截断溢出。Shorts 提供了两种安全策略:
import com.google.common.primitives.Shorts;
public class ShortsCastDemo {
public static void main(String[] args) {
long normalValue = 1000L;
long overflowValue = 50000L; // 超过 short 最大值 (32767)
// 1. checkedCast:溢出时直接抛出 IllegalArgumentException 异常
short safeValue = Shorts.checkedCast(normalValue);
System.out.println("checkedCast: " + safeValue); // 1000
// 2. saturatingCast:饱和转换(溢出时自动截断为 Short.MAX_VALUE 或 Short.MIN_VALUE)
short clampedValue = Shorts.saturatingCast(overflowValue);
System.out.println("saturatingCast 溢出截断: " + clampedValue); // 32767
}
}
2.2.2、最值、范围约束与比较
import com.google.common.primitives.Shorts;
public class ShortsMathDemo {
public static void main(String[] args) {
short a = 10, b = 50, c = 30;
// 1. 获取最值(支持变长参数)
System.out.println("最大值: " + Shorts.max(a, b, c)); // 50
System.out.println("最小值: " + Shorts.min(a, b, c)); // 10
// 2. 区间截断限制 (constrainToRange)
// 将输入值限制在 [min, max] 区间内:小于 min 返回 min,大于 max 返回 max
short val1 = Shorts.constrainToRange((short) 5, (short) 10, (short) 20); // 返回 10
short val2 = Shorts.constrainToRange((short) 15, (short) 10, (short) 20); // 返回 15
short val3 = Shorts.constrainToRange((short) 25, (short) 10, (short) 20); // 返回 20
System.out.println("范围限制结果: " + val1 + ", " + val2 + ", " + val3);
// 3. 数值比较
int cmp = Shorts.compare(a, b); // 返回负数,表明 a < b
}
}
最大值: 50
最小值: 10
范围限制结果: 10, 15, 20
2.2.3、字节序列化转换
在网络协议编解码或二进制处理中,经常需要将 short(2 字节)与 byte[] 互相转换。Shorts 默认采用 大端序(Big-Endian / Network Byte Order)。
import com.google.common.primitives.Shorts;
public class ShortsByteDemo {
public static void main(String[] args) {
short value = 0x1234; // 对应十进制 4660
// 1. short -> byte[] (2 字节)
byte[] bytes = Shorts.toByteArray(value);
// bytes[0] = 0x12, bytes[1] = 0x34
// 2. byte[] -> short
short restoredValue = Shorts.fromByteArray(bytes);
System.out.println("还原后的 short: " + restoredValue); // 4660
// 3. 从任意字节数组指定位置读取 2 字节并转换为 short
byte[] buffer = {0x00, 0x10, 0x20, 0x00};
short extracted = Shorts.fromBytes(buffer[1], buffer[2]); // 读取 0x10 和 0x20
System.out.println("提取的 short: " + extracted); // 4128
}
}
还原后的 short: 4660
提取的 short: 4128
2.2.4、数组查找、反转与拼接
import com.google.common.primitives.Shorts;
public class ShortsArrayDemo {
public static void main(String[] args) {
short[] array = {1, 2, 3, 4, 2, 3};
// 1. 查找子数组匹配索引
short[] target = {2, 3};
int index = Shorts.indexOf(array, target);
System.out.println("子数组首次匹配索引: " + index); // 1
// 2. 原位数组反转 (Reverse)
Shorts.reverse(array);
// array 变为 [3, 2, 4, 3, 2, 1]
// 3. 数组合并 (Concat)
short[] extra = {9, 10};
short[] combined = Shorts.concat(array, extra);
System.out.println("合并后数组长度: " + combined.length); // 8
}
}
子数组首次匹配索引: 1
合并后数组长度: 8
2.2.5、集合适配与字符串处理
import com.google.common.primitives.Shorts;
import java.util.List;
public class ShortsConvertDemo {
public static void main(String[] args) {
short[] numbers = {10, 20, 30};
// 1. short[] 转 List<Short> 视图(改动 List 会联动改动原数组)
List<Short> shortList = Shorts.asList(numbers);
shortList.set(0, (short) 99);
System.out.println("原数组第 0 位被更新: " + numbers[0]); // 99
// 2. 数组快速连接为分隔符字符串
String joined = Shorts.join(", ", numbers);
System.out.println("连接字符串: " + joined); // "99, 20, 30"
// 3. StringConverter 转换器(双向转换)
com.google.common.base.Converter<String, Short> converter = Shorts.stringConverter();
short parsed = converter.convert("123");
String strValue = converter.reverse().convert((short) 456);
System.out.println("解析与反转: " + parsed + " / " + strValue);
}
}
原数组第 0 位被更新: 99
连接字符串: 99, 20, 30
解析与反转: 123 / 456
3、Ints
Guava 中的 Ints(属于 com.google.common.primitives 包)是针对原生 int 类型及 int[] 数组操作的静态工具类。
它补足了 JDK 标准库在处理原生整型数组时的不足,提供了极为丰富的安全强转、范围约束、字节序列化、数组高阶操作与集合适配功能。
3.1、核心API
| 分类 | 核心 API 方法 | 说明 |
|---|---|---|
| 安全强转与界限 | checkedCast, saturatingCast | 将 long 安全转换为 int(提供溢出检查或饱和截断) |
| 数值计算与范围 | min, max, constrainToRange, compare | 求最值、区间范围限制截断、数值比较 |
| 字节/二进制序列化 | toByteArray, fromByteArray, fromBytes | int 与 byte[](大端序/Big-Endian)双向转换 |
| 数组查找与查找子数组 | contains, indexOf, lastIndexOf | 查找单个 int 或匹配整个 int[] 子数组 |
| 数组修改与拼接 | concat, ensureCapacity, reverse, sortDescending | 合并、扩容、原位反转、降序排序 |
| 集合与类型转换 | asList, toArray, join, stringConverter | 原生数组与 List<Integer> 适配、字符串拼接/双向解析 |
3.2、使用示例
3.2.1、安全类型转换
在 Java 中,直接将 long 强转为 int(如 (int) longVal)会导致高位直接截断,产生意料之外的负数或错误数值。Ints 提供了两种安全的处理策略:
import com.google.common.primitives.Ints;
public class IntsCastDemo {
public static void main(String[] args) {
long normalValue = 1000L;
long overflowValue = 3_000_000_000L; // 超过 Integer.MAX_VALUE (约 21.47 亿)
// 1. checkedCast:数值安全时正常返回,超出 int 范围则直接抛出 IllegalArgumentException
int value1 = Ints.checkedCast(normalValue);
System.out.println("checkedCast: " + value1); // 1000
// 2. saturatingCast:饱和转换(溢出时不会报错,而是自动截断为 Integer.MAX_VALUE 或 Integer.MIN_VALUE)
int value2 = Ints.saturatingCast(overflowValue);
System.out.println("saturatingCast 截断值: " + value2); // 2147483647
}
}
3.2.2、最值、范围约束与比较
import com.google.common.primitives.Ints;
public class IntsMathDemo {
public static void main(String[] args) {
// 1. 查找最值(支持变长参数)
int maxVal = Ints.max(10, 50, 30, 90, 20); // 90
int minVal = Ints.min(10, 50, 30, 90, 20); // 10
// 2. 区间限制截断 (constrainToRange)
// 将输入值限制在指定的 [min, max] 闭区间内
int low = Ints.constrainToRange(5, 10, 20); // 小于下限,返回 10
int mid = Ints.constrainToRange(15, 10, 20); // 在范围内,返回 15
int high = Ints.constrainToRange(25, 10, 20); // 大于上限,返回 20
System.out.println("限制后数值: " + low + ", " + mid + ", " + high);
// 3. 原生数值比较(Java 7+ 可直接用 Integer.compare,这里行为一致)
int cmp = Ints.compare(10, 20); // 返回负数 (-1)
}
}
限制后数值: 10, 15, 20
3.2.3、字节序列化
在网络编程(如 Netty、Socket)或二进制协议解析中,需要频繁将 32 位 int(4 字节)与 byte[] 互转。Ints 采用标准 网络字节序(大端序 / Big-Endian)。
import com.google.common.primitives.Ints;
public class IntsByteDemo {
public static void main(String[] args) {
int number = 0x12345678;
// 1. int -> byte[] (长度为 4 的字节数组)
byte[] bytes = Ints.toByteArray(number);
// bytes 为 [0x12, 0x34, 0x56, 0x78]
// 2. byte[] -> int
int restored = Ints.fromByteArray(bytes);
System.out.println("还原后的数值: 0x" + Integer.toHexString(restored)); // 0x12345678
// 3. 从 4 个独立 byte 构造 int
int customInt = Ints.fromBytes((byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00);
System.out.println("解析出的数值: " + customInt); // 256
}
}
还原后的数值: 0x12345678
解析出的数值: 256
3.2.4、数组高阶操作
除了查找单个元素,Ints 还提供了子数组查找与降序排序等便捷功能:
import com.google.common.primitives.Ints;
import java.util.Arrays;
public class IntsArrayDemo {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5, 2, 3};
// 1. 查找连续匹配的子数组 (Target Subarray) 起始位置
int[] target = {2, 3};
int subIdx = Ints.indexOf(array, target);
System.out.println("子数组首次匹配索引: " + subIdx); // 1
// 2. 原位反转数组 (Reverse)
Ints.reverse(array);
System.out.println("反转后首个元素: " + array[0]); // 3
// 3. 原位降序排序 (Sort Descending)
Ints.sortDescending(array);
System.out.println("降序排序后: " + Arrays.toString(array)); // [5, 4, 3, 3, 2, 2, 1]
// 4. 数组拼接 (Concat)
int[] extra = {100, 200};
int[] combined = Ints.concat(array, extra);
System.out.println("拼接后长度: " + combined.length); // 9
}
}
子数组首次匹配索引: 1
反转后首个元素: 3
降序排序后: [5, 4, 3, 3, 2, 2, 1]
拼接后长度: 9
3.2.5、集合适配与字符串处理
- asList(int… backingArray):将 int[] 包装为 List<Integer>。需要注意,返回的 List 底层仍然由原 int[] 支撑,修改 List 会同步改动原数组。
- stringConverter():提供 Converter<String, Integer>,方便在双向映射框架中作为参数传递。
import com.google.common.base.Converter;
import com.google.common.primitives.Ints;
import java.util.List;
public class IntsConvertDemo {
public static void main(String[] args) {
int[] numbers = {10, 20, 30};
// 1. 原生数组包装为 List 视图(无需装箱复制,高性能)
List<Integer> intList = Ints.asList(numbers);
intList.set(0, 99);
System.out.println("原数组第 0 位联动更新为: " + numbers[0]); // 99
// 2. 数组元素快速用分隔符拼接为字符串
String joined = Ints.join(" - ", numbers);
System.out.println("拼接字符串: " + joined); // "99 - 20 - 30"
// 3. StringConverter 转换器
Converter<String, Integer> converter = Ints.stringConverter();
Integer num = converter.convert("123"); // String -> Integer
String str = converter.reverse().convert(456); // Integer -> String
System.out.println("解析结果: " + num + ", 正反向转换: " + str);
}
}
原数组第 0 位联动更新为: 99
拼接字符串: 99 - 20 - 30
解析结果: 123, 正反向转换: 456
4、Longs
Guava 中的 Longs(属于 com.google.common.primitives 包)是专门用于操作原生 long 类型以及 long[] 数组的静态工具类。
它补足了 JDK 标准库对原生 long 数组支持的不足,提供了字节序列化、数值比较与范围约束、子数组查找、原位数组操作以及与集合的无缝适配等功能。
4.1、核心API
| 分类 | 核心 API 方法 | 说明 |
|---|---|---|
| 数值计算与范围 | min, max, constrainToRange, compare | 求最值(支持变长参数)、区间限制截断、数值比较 |
| 字节/二进制序列化 | toByteArray, fromByteArray, fromBytes | long(8字节)与 byte[](大端序/Big-Endian)双向转换 |
| 数组查找与匹配 | contains, indexOf, lastIndexOf | 查找单个 long 或匹配整个 long[] 子数组的索引 |
| 数组修改与拼接 | concat, ensureCapacity, reverse, sortDescending | 合并、动态扩容、原位反转、降序排序 |
| 集合与类型转换 | asList, toArray, join, stringConverter | 原生数组与 List<Long> 视图转换、分隔符拼接、字符串双向转换器 |
4.2、使用示例
4.2.1、最值、范围约束与数值比较
import com.google.common.primitives.Longs;
public class LongsMathDemo {
public static void main(String[] args) {
// 1. 查找最值(支持变长参数)
long maxVal = Longs.max(100L, 500L, 300L, 900L, 200L); // 900
long minVal = Longs.min(100L, 500L, 300L, 900L, 200L); // 100
// 2. 区间限制截断 (constrainToRange)
// 将输入值限制在指定的 [min, max] 闭区间内
long low = Longs.constrainToRange(50L, 100L, 200L); // 小于下限,返回 100
long mid = Longs.constrainToRange(150L, 100L, 200L); // 在范围内,返回 150
long high = Longs.constrainToRange(250L, 100L, 200L); // 大于上限,返回 200
System.out.println("限制后数值: " + low + ", " + mid + ", " + high);
// 3. 数值比较
int cmp = Longs.compare(100L, 200L); // 返回负数 (-1)
}
}
限制后数值: 100, 150, 200
4.2.2、字节序列化
在分布式系统、RPC 框架(如 Thrift/Protobuf 底层)或二进制存储(如 RocksDB Key 序列化)中,经常需要将 64 位 long(8 字节)与 byte[] 进行互转。Longs 默认采用 网络字节序(大端序 / Big-Endian)。
import com.google.common.primitives.Longs;
public class LongsByteDemo {
public static void main(String[] args) {
long value = 0x123456789ABCDEF0L;
// 1. long -> byte[] (长度为 8 的字节数组)
byte[] bytes = Longs.toByteArray(value);
// bytes[0] = 0x12, bytes[1] = 0x34 ... bytes[7] = 0xF0
// 2. byte[] -> long
long restored = Longs.fromByteArray(bytes);
System.out.println("还原后的数值: 0x" + Long.toHexString(restored).toUpperCase()); // 0x123456789ABCDEF0
// 3. 从 8 个独立 byte 构造 long
long customLong = Longs.fromBytes(
(byte) 0, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 1, (byte) 0
);
System.out.println("解析出的数值: " + customLong); // 256
}
}
还原后的数值: 0x123456789ABCDEF0
解析出的数值: 256
4.2.3、数组高阶操作(
除了基础查找,Longs 还支持连续子数组匹配、降序排序以及原位反转:
import com.google.common.primitives.Longs;
import java.util.Arrays;
public class LongsArrayDemo {
public static void main(String[] args) {
long[] array = {10L, 20L, 30L, 40L, 50L, 20L, 30L};
// 1. 查找连续匹配的子数组 (Target Subarray) 起始位置
long[] target = {20L, 30L};
int subIdx = Longs.indexOf(array, target);
System.out.println("子数组首次匹配索引: " + subIdx); // 1
// 2. 原位反转数组 (Reverse)
Longs.reverse(array);
System.out.println("反转后首个元素: " + array[0]); // 30L
// 3. 原位降序排序 (Sort Descending)
Longs.sortDescending(array);
System.out.println("降序排序后: " + Arrays.toString(array)); // [50, 40, 30, 30, 20, 20, 10]
// 4. 数组拼接 (Concat)
long[] extra = {100L, 200L};
long[] combined = Longs.concat(array, extra);
System.out.println("拼接后长度: " + combined.length); // 9
}
}
子数组首次匹配索引: 1
反转后首个元素: 30
降序排序后: [50, 40, 30, 30, 20, 20, 10]
拼接后长度: 9
4.2.4、集合适配与转换
- asList(long… backingArray):将 long[] 包装为 List。修改 List 视图会同步改变原始数组(由原数组直接支撑,不产生多余的对象拷贝)。
- stringConverter():返回 Converter<String, Long> 实例,便于与 Guava 的其他函数式 API 配合使用。
import com.google.common.base.Converter;
import com.google.common.primitives.Longs;
import java.util.List;
public class LongsConvertDemo {
public static void main(String[] args) {
long[] numbers = {100L, 200L, 300L};
// 1. 原生数组包装为 List 视图(零拷贝,高性能)
List<Long> longList = Longs.asList(numbers);
longList.set(0, 999L);
System.out.println("原数组第 0 位同步更新为: " + numbers[0]); // 999
// 2. 数组元素快速用分隔符拼接为字符串
String joined = Longs.join(" | ", numbers);
System.out.println("拼接字符串: " + joined); // "999 | 200 | 300"
// 3. StringConverter 转换器
Converter<String, Long> converter = Longs.stringConverter();
Long parsed = converter.convert("123456789"); // String -> Long
String str = converter.reverse().convert(987654321L); // Long -> String
System.out.println("转换结果: " + parsed + " / " + str);
}
}
原数组第 0 位同步更新为: 999
拼接字符串: 999 | 200 | 300
转换结果: 123456789 / 987654321
&spm=1001.2101.3001.5002&articleId=164306003&d=1&t=3&u=a12cc78f811d4710bc04f16597166406)
1716

被折叠的 条评论
为什么被折叠?



