CollectionUtils扩展方法(注:去重方法中有线程安全问题)

一.技术点:

1.使用ProbeFactory.getProbe().getObject()根据属性名称获取属性值:

依赖:

<!-- https://mvnrepository.com/artifact/com.ibatis/ibatis2-common -->
<dependency>
    <groupId>com.ibatis</groupId>
    <artifactId>ibatis2-common</artifactId>
    <version>2.1.7.597</version>
</dependency>

2.去重list集合中的null值,使用NullCollection,代码如下:

import java.io.Serializable;  
import java.util.AbstractList;  
import java.util.RandomAccess;  
  
public class NullCollection extends AbstractList<Object>  
implements RandomAccess, Serializable  {  
  
    private static final long serialVersionUID = 5206887786441397812L;  
  
    @Override  
    public Object get(int index) {  
        return null;  
    }  
  
    @Override  
    public int size() {  
        return 1;  
    }  
      
    public boolean contains(Object obj) {  
        return null == obj;  
    }  
      
    private Object readResolve() {  
        return null;  
    }  
}  

3.去重过程中遇到线程安全问题

3.1 使用parallelStream并行流对list集合进行读写操作,list是线程不安全,导致出现问题:

解决:1.parallelStream并行流改成stream串行流

            2.保证list集合线程安全

谈谈并行流parallelStream_SunAlwaysOnline的博客-CSDN博客_parallelstream

3.2 list线程安全

   Java 中最常用的集合为:ArrayList 和 LinkedList,但这两个线程并非是线程安全的,在多线程情况就需要考虑线程安全的 List:

   1.Vector 是在 JDK 1.0 中加入的,历史悠久;
      底层原理和 ArrayList 几乎一致,区别在于 Vector 每个公开的方法上都加入          了 synchronized 保证并发安全,但性能非常低下,不推荐使用;

   2.Collections.synchronizedList()

      Collections 集合工具类提供了一个方法可以将 List 转为线程安全的 SynchronizedList

      public static <T> List<T> synchronizedList(List<T> list)

    原理仅是在每个方法上加上了 synchronized 来保证线程安全,相比于 Vector 扩展性,灵活性更高;

    3.CopyOnWriteArrayList & CopyOnWriteArraySet

     利用写时复制(COW)实现线程安全的集合,优点是有现成进行修改的时候,仍有其他线程可以读取,缺点是浪费空间,每次添加删除元素就需要复制一份新数组。

4.Collections.emptyList() 方法的使用

4.1 emptyList()
作用:返回一个空的List(使用前提是不会再对返回的list进行增加和删除操作);
好处:
1. new ArrayList()创建时有初始大小,占用内存,emptyList()不用创建一个新的对象,可以减少内存开销;
2. 方法返回一个emptyList()时,不会报空指针异常,如果直接返回Null,没有进行非空判断就会报空指针异常;
注意:此List与常用的List不同,它是Collections类里的静态内部类,在继承AbstractList后并没有实现add()、remove()等方法,所以返回的List不能进行增加和删除元素操作。

4.2 如果需要对collections.emptyList()进行增删操作的话,就需要将collections.emptyList()转换成ArrayList()进行操作。

二.代码示例:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
 
import com.ibatis.common.beans.Probe;
import com.ibatis.common.beans.ProbeFactory;

public class CollectionUtilsExtends {
    
    private CollectionUtilsExtends (){}
    //1.根据属性名称获取属性值,前面详解

    private static final Probe PROBE = ProbeFactory.getProbe();

  //2.去重list集合中的null值,前面详解
    @SuppressWarnings("rawtypes")
    public static final Collection NULL_COLLECTION = new NullCollection();
      
    @SuppressWarnings("unchecked")
    public static final <T> Collection<T> nullCollection() {
        return (List<T>) NULL_COLLECTION;
    }
    
    /**
     * <pre>
     * 批量获取map中的值
     * </pre>
     *
     * @param <K>
     * @param <V>
     * @param keys
     * @param source
     * @return
     */
    public static <K,V> List<V> getAllFormMap(List<K> keys,Map<K,V> source) {
        List<V> values = Collections.emptyList();
        if (keys != null && !keys.isEmpty() && source != null && !source.isEmpty()) {
            values = new ArrayList<V>();
            for (K k : keys) {
                values.add(source.get(k));
            }
        }
        return values;
    }
    
    /**
     * 
     * <pre>
     * 从List中获取valueProp组成一个新的list
     * </pre>
     *
     * @param <E>
     * @param list
     * @param valueProp
     * @return
     */
    public static <E,K> List<K> getValueList(List<E> list, String valueProp) {
        List<K> valueList = Collections.emptyList();
        if (CollectionUtils.isNotEmpty(list)) {
            list.removeAll(nullCollection());
            valueList = new ArrayList<K>(list.size());
            for (E e : list) {
                @SuppressWarnings("unchecked")
                K value = (K)PROBE.getObject(e, valueProp);
                valueList.add(value);
            }
        } 
        return valueList;
    }
    
    /**
     * 
     * <pre>
     * 用list生成一个map,keyProp 为指定的key,valueProp 为指定是value
     * </pre>
     *
     * @param <K>
     * @param <V>
     * @param <E>
     * @param list
     * @param keyProp
     * @param valueProp
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <K,V,E> Map<K,V> listforMap(List<E> list, String keyProp, String valueProp) {
        Map<K,V> map = Collections.emptyMap();
        if (CollectionUtils.isNotEmpty(list)) {
            list.removeAll(nullCollection());
            map = new HashMap<K, V>(list.size());
            for (E object : list) {
                K key = (K)PROBE.getObject(object, keyProp);
                Object value = null;
                if (StringUtils.isEmpty(valueProp)) {
                    value = object;
                } else {
                    value = PROBE.getObject(object, valueProp);
                }
                map.put(key, (V)value);
            }
        }
        return map;
    }
    
    /**
     * 
     * <pre>
     * list 生成一个Map<K,List<V>>
     * </pre>
     *
     * @param <K>
     * @param <V>
     * @param <E>
     * @param list
     * @param keyProp
     * @param valueProp
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <K,V,E> Map<K,List<V>> listforListMap(List<E> list, String keyProp,
            String valueProp) {
        Map<K, List<V>> map = Collections.emptyMap();
        if (CollectionUtils.isNotEmpty(list)) {
            list.removeAll(nullCollection());
            map = new HashMap<K, List<V>>(list.size());
            V value = null;
            for (E object : list) {
                K key = (K)PROBE.getObject(object, keyProp);
                if (StringUtils.isEmpty(valueProp)) {
                    value = (V)object;
                } else {
                    value = (V)PROBE.getObject(object, valueProp);
                }
                List<V> values = map.get(key);
                if (values == null) {
                    values = new ArrayList<V>();
                }
                values.add(value);
                map.put(key, values);
            }
        }
        return map;
    }

 /**
     * <pre>
     * 根据对象集合中的valueProp值进行去重
     * </pre>
     * @param <K>
     * @param <V>
     * @param list
     * @param valueProp
     * @return
     */

//3.涉及到线程安全问题,前面详解

public static <E> List<E> distinctByKey(List<E> list, String valueProp) {

List<E> resultList = Collections.synchronizedList(new ArrayList<>());

if (list.isEmpty() || StringUtils.isEmpty(valueProp)) {

return null;

}

list.parallelStream().filter(distinctByKey(p -> PROBE.getObject(p, valueProp))).forEach(resultList ::add);
}

/**

*distinctByKey 按照集合对象属性去重 

*/

public static <T>  Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {

  Map<Object, Boolean> seen = new ConcurrentHashMap<>();

  return t->seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值