环境
jedis3.0.0
背景
在使用jedis的"scan"操作获取redis中某些key时,发现总是出现类型转换的异常——"java.lang.ClassCastException: java.lang.String cannot be cast to [B"
其中,redis中存储的key是byte[]类型,用"scan"操作获取的所有key是封装到一个List
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 scan(final String cursor, final ScanParams params) {
checkIsInMultiOrPipeline();
client.scan(cursor, params);
List
BinaryJedis.scan(final byte[] cursor, final ScanParams params):
public ScanResult scan(final byte[] cursor, final ScanParams params) {
checkIsInMultiOrPipeline();
client.scan(cursor, params);
List
可以发现,两者都是通过调用BinaryClient类的scan方法来获取数据,这些数据是一样的,只是两者在封装返回结果时的操作不同而已。BinaryJedis把byte[]类型的原始数据原封不动地返回,而Jedis则是用SafeEncode把原始数据encode成String类型返回。
How
一开始没意识到scan("0",params)
和scan("0".getBytes(),params)
返回结果不同,直接用了前者,结果前者返回的是List
注:ScanResult提供两个方法获取游标,分别是getCursor()
和getCursorAsBytes()
,前者是String类型,后者是byte[]类型,使用时需要注意。
拓展
此时又产生了新的疑惑,会不会在ScanParams中也存在类似的问题?于是进ScanParams类查看
发现这里对match方法进行了重载(Overload),传入byte[]和String类型的参数结果是一样的。所以ScanParams的pattern可以用String或者byte[]。
启发
在开发中,一定一定一定要注意变量类型,尤其是集合中的泛型。有必要的话,在类型转换前或者在集合类的操作中对变量进行类型检查。