Google Guava学习笔记

一、Preconditions使用,里面牵扯到一个问题,是直接抛出异常还是对字段做校验呢,回复中的一段关于适用unchecked Exception还是checked Exception写的非常好,如下:

Preconditions的异常类型问题 牵扯到设计准则,后面的章节‘Throwables’也提到了一点。一般准则认为,违反方法契约(包括方法所使用的对象或外部数据状态)时抛出UncheckedException,其定义方法的可用性范畴;而方法因为不可控原因无法履行契约,则抛出CheckedException。 所以Preconditions就跟它的名字一样,是用来定义方法契约的,这样方法才算完整地自描述和可重用了。
对设计理想的应用来说,Runtimeexception应该绝少触发。当调用这些方法时,你可以根据领域对象的业务含义,在调用方预先作检查,比如bean-validator这样的手段。而详细去看bean-validator的定义时,你就会发现它完全撇清了检查和异常的概念。

二、BiMap是JDK中不存在的一种MAP结构,与MAP不同,BiMap不仅仅提供了【键->值】的映射关系,同时提供了【值->键】的映射关系代码如下:

package cn.outofmemory.guava.collection;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;

public class BiMapDemo {
    public static void main(String[] args) {
        BiMap weekNameMap = HashBiMap.create();
        weekNameMap.put("星期一","Monday");
        weekNameMap.put("星期二","Tuesday");
        weekNameMap.put("星期三","Wednesday");
        weekNameMap.put("星期四","Thursday");
        weekNameMap.put("星期五","Friday");
        weekNameMap.put("星期六","Saturday");
        weekNameMap.put("星期日","Sunday");

        System.out.println("星期日的英文名是" + weekNameMap.get("星期日"));
        System.out.println("Sunday的中文是" + weekNameMap.inverse().get("Sunday"));
    }
}

三、Table是JDK中不存在的另外一种MAP结构,简单的说就是【双键->值 】的映射模式,实际应用代码如下:

@Override
public void changeReportRecordOwner(List<Long> ids, Long accountId, Long memberId) throws BusinessException {
    if (CollectionUtils.isEmpty(ids)) {
        return;
    }

    List<ReportRecord> list = findReportRecord(ids);
    if (CollectionUtils.isEmpty(list)) {
        return;
    }
    Table<Long, String, ReportCategory> table = HashBasedTable.create();
    for (ReportRecord record : list) {
        Long sAccountId = record.getOrgAccountId();
        if (!ObjectUtils.equals(sAccountId, accountId)) {//跨单位
            ReportCategory newCategory = getVReportCategory(record.getReportCategoryId(), accountId, table);
            if (newCategory != null) {
                record.setReportCategoryId(newCategory.getId());
            } else {
                record.setUseFlag(RecordUseFlag.Disable.key);
                record.setReportCategoryId(null);
                LOG.error("报表[id=" + record.getId() + "]记录无报表分类, 设置为停用状态");
            }
            record.setOrgAccountId(accountId);
        }
        record.setCreateMember(memberId);
        record.setUpdateDate(new Date());
    }
    updateReportRecord(list);
    saveReportCategory(Lists.newArrayList(table.values()));
}

private ReportCategory getVReportCategory(Long categoryId, Long accountId, Table<Long, String, ReportCategory> table) throws BusinessException {
    ReportCategory category = getReportCategory(categoryId);
    if (category == null) {
        return null;
    }
    //优先从当前缓存中找
    ReportCategory newCategory = table.get(accountId, category.getName());
    if (newCategory != null) {
        return newCategory;
    }
    //从数据库中找
    List<ReportCategory> nameList = findReportCategoryByName(category.getName(), accountId);
    if (CollectionUtils.isNotEmpty(nameList)) {
        return nameList.get(0);
    } else {
        newCategory = new ReportCategory();
        newCategory.setIdIfNew();
        newCategory.setName(category.getName());
        newCategory.setParentId(ReportCategory.ROOT_ID);
        newCategory.setCreateDate(new Date());
        newCategory.setModifyDate(new Date());
        newCategory.setOrgAccountId(accountId);
        newCategory.setSort(0);
        newCategory.setNodePath("0");
        Long adminId = getAdmin(accountId);
        newCategory.setCreateMember(adminId);
        newCategory.setModifyMember(adminId);
    }
    table.put(accountId, newCategory.getName(), newCategory);
    return newCategory;
}

四、使用ClassPath+ClassInfo用于加载指定包路径下的类非常有用,请看实际代码:

classes = Sets.newHashSet();
ClassPath classPath = ClassPath.from(CTPRestApplication.class.getClassLoader());
// jersey基础类
String basePackage = ServerDetector.isWebSphere() ? "org.codehaus.jackson.jaxrs" : "com.fasterxml.jackson.jaxrs.json";
for (ClassInfo ci : classPath.getTopLevelClasses(basePackage)) {
    classes.add(ci.load());
}
// V5基础类
String seeyonPackage = "com.seeyon.ctp.rest.resources";
for (ClassInfo ci : classPath.getTopLevelClasses(seeyonPackage)) {
    Class clazz = ci.load();
    if (clazz.isAssignableFrom(BaseResource.class)) {
        classes.add(clazz);
    }
}

由于ClassPath是在guava14才执行,在JDK1.7上才做支持,对于垃圾的WAS环境而言又只能使用JDK1.6,现实用spring resource加载来做实现,代码如下:

private static Set> loadTopLevelClasses(String basePackage) throws IOException {
    Set> classes = Sets.newHashSet();
    ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX 
            + ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage)) + "/*.class";
    Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
    if (ArrayUtils.isNotEmpty(resources)) {
        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
        for (Resource resource : resources) {
            if (resource.isReadable()) {
                MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
                String className = metadataReader.getClassMetadata().getClassName();
                if (className.indexOf("$") > -1) {//不加载内部类
                    continue;
                }
                try {
                    Class clazz = Class.forName(className);
                    classes.add(clazz);
                } catch (ClassNotFoundException e) {
                    LOG.error("类加载异常:", e);
                }
            }
        }
    }
    return classes;
}

五、一致性哈希(网友说在分布式上应用比较多,当时没有接触到,不是很理解)

int bucket = Hashing.consistentHash(id, buckets) // bucket 的范围在 0 ~ buckets 之间

六、使用Tables.transpose竟然可以达到转置效果(惊不惊喜,意不意外)!

Table table = HashBasedTable.create();
table.put("a", "javase", 80);
table.put("b", "javaee", 90);
table.put("c", "javame", 100);
table.put("d", "guava", 70);
for (Cell cell : table.cellSet()) {
    System.out.println(cell.getRowKey() + ":" + cell.getColumnKey() + ":" + cell.getValue());
}
System.out.println("=======转置后========");
Table table2 = Tables.transpose(table);
for (Cell cell : table2.cellSet()) {
    System.out.println(cell.getRowKey() + ":" + cell.getColumnKey() + ":" + cell.getValue());
}

参考链接

  • google guava的BiMap:双向Map
  • 利用spring,实现package下的类扫描
  • java guava TreeRangeSet实现插入一个不重复的IP段
  • 一致性哈希算法及其实现(Consistent Hashing)
  • Guava 中的一致性哈希
  • 使用guava 实现java的一致性hash
  • Guava类库学习–Table(双键的Map)

你可能感兴趣的:(Java基础)