jedis3.0.0java
在使用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時拋出了異常。redis
通過debug發現這跟調用"scan(cursor,params)"時傳的"cursor"的類型有關。
如上兩圖所示:ide
Jedis類是BinaryJedis的子類
debug
接下來看下二者的scan方法——
Jedis.scan(final String cursor, final ScanParams params):code
@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):blog
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類型返回。ip
一開始沒意識到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[]。get
在開發中,必定必定必定要注意變量類型,尤爲是集合中的泛型。有必要的話,在類型轉換前或者在集合類的操做中對變量進行類型檢查。編譯器