范型语法糖

Jackson里面有个转字符串为Java对象的方法,传进去的是

大概像下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void batchInsertRecords(String str){
Map<String,String> record = parseObject(str,Map.class);
String ageStr = record.get("age");
/**
* 这里如果你这样写,如果你传进去的是{name:"Yasir Lin",age:"23"},这样没问题,但是你要是传进去的是{name:"Yasir Lin",age:23}
* 就会报错误,因为范型是个语法糖,你定义了Key为String,结果是String,那没问题,定义了Value为String,实际是Integer,
* 它在取值的时候,就会隐式给你强转为String类型,然后类型是Integer,出来就会报错。Integer cannot be cast to String。
*
*
* 这边以我这边的业务为准的话,这样写是正确的,因为这边确定Key的类型一定为String,Value不确定而已
*/
Map<String,Object> correctRecord = parseObject(str,Map.class);
Integer ageInt = correctRecord.get("age");
}

关于隐式转换,不只是 Java 的拆装箱,范型,在其他地方也有,如SQLselect * from t where id = 1;select * from t where id ='1'完全是两个东西,一个会不走索引,一个走一级(主键)索引

JDK1.5前,范型(Java这里只是个语法糖/伪范型,每个编程语言都会去实现它)没有出来的时候,像ArrayList里面提供的就是Object返回。没有return (E) elementData[index]这里面是没有E的,是Object类型。能够在编译时检查类型错误,利用get()方法取出的对象也不再是Object引用,编译器可以认识此类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    public static void main(String[] args) {
int listSize = 4;
// 这里的foo/bar没有什么深层次意思,就像你打游戏开局打怪是哥布林/史莱姆一样,学其他知识也是这么写(eg.Vue)
// 还有创建容器的时候,最好根据实际量多少,指定容器大小,避免重复1.5倍扩容,也避免过多浪费内存。也算个Java小优化
byte[] bar = {'b','a','r'};
List list = new ArrayList(listSize);
list.add("foo");
// 这里不能直接在add()方法里面写{'b','a','r'},这样编译不通过,数组类型在Java里面比较特殊,它的初始化不像其他类型,
// 它是有专门的array类型去初始化的,不像C++就直接是分配一整块内存,Java为了实现更安全的对数组进行操作,进行了包装数组
// 对象(《深入理解Java虚拟机》里面有讲)
list.add(bar);
list.add(1);
list.add(1L);
// 上面的代码是完全没问题的(我是指编译没问题)
// 当你想下面做的时候
// 进行下面操作的时候,最好将ArrayList的大小提出来,避免重复进行getSize();尽量减少方法调用
for(int i=0,size=listSize;i<size;++i){
String str = (String)list.get(i);
System.out.println(str);
// 执行到这里就会报错,编译不会报错
}
}

// JDK 1.8还是在里面维护了一个Object数组,elementData;
// 然后调用
// Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

很多人可能说,我怎么可会犯这种错误。当你指定类型不明确时,进行强转,就会出现这个问题。

HBase Scan PageFilter

HBase Scan PageFilter 设置的返回数据量和实际返回的数据量不同。低版本的 Scan 没有 setLimit 方法。

1
2
Scan scan = new Scan();
scan.setFilter(new PageFilter(200));

上面很大可能返回大于 200 条记录。

原因

HBase 里 Filter 状态全部都是 Region 内有效的,也就是说,Scan 一旦从一个 Region 切换到另一个 Region,之前那个 Filter 的内部状态就无效了,新 Region 内用的其实是一个全新的 Filter。具体到这个问题,就是 PageFilter 内部计数器从一个 Region 切换到另一个 Region,计数器已经被清 0。——来自《HBase 原理与实践》

解决方法

  1. 手动利用 List#subList 方法,在返回结果前截取对应 pageSize 条数记录。
  2. 升级 HBase 客户端代码,使用 scan#setLimit 方法。