環境
jedis3.0.0
背景
在使用jedis的"scan"操作獲取redis中某些key時,發現總是出現類型轉換的異常——"java.lang.ClassCastException: java.lang.String cannot be cast to [B"
其中,redis中存儲的key是byte[]類型,用"scan"操作獲取的所有key是封裝到一個List<T>中,獲取結果后直接通過Set.addAll()存到一個HashSet<byte[]>中,就在用forEach遍歷該HashSet時拋出了異常。
Debug
Why
經過debug發現這跟調用"scan(cursor,params)"時傳的"cursor"的類型有關。
如上兩圖所示:
- 當cursor為String類型時,調用的是Jedis類中的scan方法;
- 當cursor為byte[]類型時,調用的則是BinaryJedis中的scan方法。
Jedis類是BinaryJedis的子類
What
接下來看下兩者的scan方法——
Jedis.scan(final String cursor, final ScanParams params):
@Override
public ScanResult<String> scan(final String cursor, final ScanParams params) {
checkIsInMultiOrPipeline();
client.scan(cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
String newcursor = new String((byte[]) result.get(0));
List<String> results = new ArrayList<String>();
List<byte[]> rawResults = (List<byte[]>) result.get(1);
for (byte[] bs : rawResults) {
results.add(SafeEncoder.encode(bs));
}
return new ScanResult<String>(newcursor, results);
}
BinaryJedis.scan(final byte[] cursor, final ScanParams params):
public ScanResult<byte[]> scan(final byte[] cursor, final ScanParams params) {
checkIsInMultiOrPipeline();
client.scan(cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
byte[] newcursor = (byte[]) result.get(0);
List<byte[]> rawResults = (List<byte[]>) result.get(1);
return new ScanResult<byte[]>(newcursor, rawResults);
}
可以發現,兩者都是通過調用BinaryClient類的scan方法來獲取數據,這些數據是一樣的,只是兩者在封裝返回結果時的操作不同而已。BinaryJedis把byte[]類型的原始數據原封不動地返回,而Jedis則是用SafeEncode把原始數據encode成String類型返回。
How
一開始沒意識到scan("0",params)
和scan("0".getBytes(),params)
返回結果不同,直接用了前者,結果前者返回的是List<String>類型的數據,直接用addAll(ScanResult.getResult())方法放到HashSet<byte[]>中,而編譯器這時是沒有提示的,所以自然而然,在遍歷HashSet時就拋出了異常。
注:ScanResult提供兩個方法獲取游標,分別是getCursor()
和getCursorAsBytes()
,前者是String類型,后者是byte[]類型,使用時需要注意。
拓展
此時又產生了新的疑惑,會不會在ScanParams中也存在類似的問題?於是進ScanParams類查看
發現這里對match方法進行了重載(Overload),傳入byte[]和String類型的參數結果是一樣的。所以ScanParams的pattern可以用String或者byte[]。
啟發
在開發中,一定一定一定要注意變量類型,尤其是集合中的泛型。有必要的話,在類型轉換前或者在集合類的操作中對變量進行類型檢查。