java进阶技巧程序员java进阶干货

最近遇到的几个小问题集合

2017-11-30  本文已影响82人  犀利豆

原文地址

最近在写项目的时候遇到了几个小问题,记录下来。希望对大家也有所帮助。

如何获取 T 的 class

在写BaseDao 之类的代码的时候,经常会遇到获取泛型T的class的情况?我们发现并没有T.class这种写法,那怎么办呢?想起之前写的Hibernate 里面有相关的代码。通过反射获取T的class

public class AbstractDao<T>{

    private Class<T> clz;

    public AbstractDao(){
        this.clz = (Class<T>)
                ((ParameterizedType)getClass()
                        .getGenericSuperclass())
                        .getActualTypeArguments()[0];
    }
    ...
}

Spring中的 @Value 加载时间

首先 @Value 注解可以方便的获取配置文件*.properties的参数。

在写代码的时候遇到这样一个问题。为了减少重复代码,我们通常需要写一个抽象类把共有的方法抽象到Abstract 类中。AbstractDao<T> 如果遇到需要向这个class的构造方法注入参数。且这个参数是通过抽象方法获取的。且这个数据是使用 Spring的 @Value 注解获取的。这个描述比较绕,我们直接看代码:

public class AbstractDao<T>{
    private int tableId;
    
    public AbstractDao(){
        this.tableId = setTableId();
    }
    
    protected abstract int setTableId();
}
public class UserDao extends AbstractDao<User>{
    
    @Value("${tableid.user}")
    private int userTableId;

    protected int setTableId() {
        return buserTableId;
    }
}

代码运行起来以后,我们发现 userTableId,并不能取到相应的值,这个时候@Value失效了。实际上这个问题的根源是因为@Value的加载是发生在对象实例化之后。也就是首先调用对象的构造函数,然后再获取配置文件中的数据。

解决的方案是使用注解 @PostConstruct,意思是构造函数执行完以后再�执行注解标记的方法。我们可以吧抽象函数做如下修改:

public class AbstractDao<T>{
    private int tableId;
    
    @PostConstruct
    public init(){
        this.tableId = setTableId();
    }
    
    protected abstract int setTableId();
}

使用 Java 8 的 lambda 和 stream 来 merge List

在使用微服务架构以后。我们经常会遇到 Merge两个List的场景。比如我们从索引里面获取了一个 List<Long> 包含的是对象的ID的 list。由于前端对象展示的元素需要。用这个ID 的list分别从两个服务批量的查询得到 List<A>List<B>,然后将两个List合二为一成为一个List<C>,返回给前端作为列表页展示。

看代码:
首先我们有一个对象 A:

public class A{
    private long id;
    private String aStr;
}

有另一个对象 B:

public class B{
    private long id;
    private String bStr;
}

页面需要的对象C:

public class C{
    private long id;
    private String aStr;
    private String bStr;
}

如何有效的把 List<A>List<B> merge 为一个 List<C>呢?

总体思路,因为两个list从不同服务里面获取。有可能两个服务出于健壮性的考虑会抛弃某些查询不到的对象,所以两个list的长度有可能不一致。所以使用一个Map<Long,B> 作为索引。
如果直接写代码会相当繁琐。如果使用 Java 8 的新特性Lamabdastream api 就能快速写出代码。


private C getCForAAndB(A a,B b){
    C c = new C();
    c.setId(a.getId());
    c.setAstr(a.getAStr())
    c.setBstr(b.getBStr())
    return c; 
}

private List<C> mergeList(List<A> aList,List<B> bList){
    //映射Map
    Map<Long,B> bMap = bList.parallelStream()
        .collect(Collectors.toMap(B::getId,b -> b));
        
    return aList.parallelStream()
            .map(a -> getCForAAndB(a,bMap.get(a.getId)))
            .collect(Collectors.toList());
}

这样merge的代码简洁明了。

如果不明白的同学可以参考我之前的 Java 8 教程。

上一篇 下一篇

猜你喜欢

热点阅读