因为在大数据项目中遇到数据都在内存中的情况, 没有办法通过查询语句在载入数据的地方做过滤,所以利用guava 的rangeSet类做了一个自定义比较器.
适用场景:
/**
* 范围比较生成器, 支持自定义比较的数据类型, 自定义数据类型需要实现Comparable 接口
*
* @param gte 大于等于 great than equals
* @param gt 大于
* @param lte 小于等于
* @param lt 小于
* @param range 当范围为空的时候, 默认给的一个范围值
* @param <C>
* @return
*/
private <C extends Comparable<?>> Range<C> getRange(C gte, C gt, C lte, C lt, Range<C> range) {
// 大于等于 >=
if (gt == null && gte != null) {
// 小于 <
if (lte == null && lt != null) {
range = Range.closedOpen(gte, lt);
// 小于等于 <=
} else if (lt == null && lte != null) {
range = Range.closed(gte, lte);
} else {
//大于等于某值 ,小于最大值
range = Range.closedOpen(gte, range.upperEndpoint());
}
// 大于 >
} else if (gte == null && gt != null) {
// 小于 <
if (lte == null && lt != null) {
range = Range.open(gt, lt);
// 小于等于 <=
} else if (lt == null && lte != null) {
range = Range.closedOpen(gt, lte);
} else {
//大于等于某值 ,小于最大值
range = Range.closedOpen(gt, range.upperEndpoint());
}
} else {
// 小于 <
if (lte == null && lt != null) {
range = Range.open(range.lowerEndpoint(), lt);
// 小于等于 <=
} else if (lt == null && lte != null) {
range = Range.closedOpen(range.lowerEndpoint(), lte);
} else {
return range;
}
}
return range;
}
接着就可以用range的 contains方法来判断一个值是否在范围中了. 不仅支持常见的String,Integer,Date, 等数据类型, 还支持自定义类, 只要实现Comparable 接口就可以比较
guava如何处理开闭区间
通过上面的代码, 我们发现判断两边的开闭区间是一件很痛苦的事情,写了很多if…else…,
我们看看google聪明的工程师是如何做的…
//guava Range 源码处理开闭的方法
- Range 类的open, closeOpen等方法传入的参数其实是一个抽象父类Cut, 这个Cut有四个实现类, 分别表示了>,>= ,<,<= ,根据Range调用的方法不同, 最终初始化的子类也不一样, 每个子类都会重写父类Cut的lessThan方法, lessThan方法对比较的边界做了不一样的区分.
//举例: closeOpen 和openClose 虽然传的都是cut类,
//但是cut类有4个内部类,分别代表四种不同的情况,
//等我们调用Range.contains的时候,我们用每一个具体实现类的比较方法
public static <C extends Comparable<?>> Range<C> closedOpen(
C lower, C upper) {
return create(Cut.belowValue(lower), Cut.belowValue(upper));
}
public static <C extends Comparable<?>> Range<C> openClosed(
C lower, C upper) {
return create(Cut.aboveValue(lower), Cut.aboveValue(upper));
}
总结:代码虽然简单, 但是却发现在google聪明的工程师们确实做到了面向对象,四种不同的情况,分成了4个不同的类. 拓宽了我们的思路.