利用 stream() 对队列中的对象/其属性值进行去重处理

294 阅读2分钟

趁热记录下,给未来的自己

1. 前言

在工作中,相信很多开发同学会遇到一个需求:对一个队列进行去重操作。平时注重积累,有沉淀的同学,可能就会很熟练的使用stream().distinct()等等方法; 而其他同学(包括我),此时往往需要面向谷歌编程,施展 ctrl+c & ctrl+v 大法,这次解决了,下次依旧如此,周而复始,生生不息,子子孙孙无穷尽也。。。

额。。。扯远了。言归正传,前面说到对队列去重,可以使用stream().dinstinct()。但是,当想根据队列中对象的某一个属性来进行去重的话,stream().distinct()的局限性就体现出来了。

因此,我封装了一个方法,实现对队列中的对象整体或者对象中的某一个属性值进行去重,并做了一定的单元测试。

方法说明:

  • List<T> toDistinctList:传入需要去重的队列,可以是 ArrayListLinkedListVector,如果传入的队列类型非以上三种,则默认返回 ArrayList;

  • Function<? super T, ?> objectProperty: 接收一个对象,返回一个对象,比如传入: student -> student.getName()或者用 lambda 表达式 Student::getName。当为空时,则表示根据整个对象进行去重;不为空时,则表示根据对象中某一个传入的属性进行去重

2. 上代码

2.1 方法代码:

    /**
     * @MethodName:  distinct
     * @Description: 队列去重,支持对对象整体去重(此时 objectProperty 为空),也支持对对象内部某个属性去重; 
     * 支持对 ArrayList,LinkedList 以及 Vector 队列进行去重操作,默认返回 ArrayList
     * @Param: toDistinctList 待去重队列
     * @Param: objectProperty 队列中对象的属性
     * @Return: java.util.List<T>
     * @Exception:
     * @author: arkMon
     * @date:  2021/2/6 11:31
     */
    public static <T> List<T> distinct(List<T> toDistinctList, Function<? super T, ?> objectProperty) {
        if (CollectionUtils.isEmpty(toDistinctList)) {
            if (toDistinctList instanceof ArrayList) {
                return new ArrayList<>();
            }
            if (toDistinctList instanceof LinkedList) {
                return new LinkedList<>();
            }
            if (toDistinctList instanceof Vector) {
                return new Vector<>();
            }
        }
        if (toDistinctList instanceof LinkedList) {
            if (objectProperty == null) {
                return toDistinctList.stream().distinct().collect(Collectors.toCollection(LinkedList::new));
            }
            return toDistinctList.stream().filter(distinctByKey(objectProperty)).collect(Collectors.toCollection(LinkedList::new));
        }
        if (toDistinctList instanceof Vector) {
            if (objectProperty == null) {
                return toDistinctList.stream().distinct().collect(Collectors.toCollection(Vector::new));
            }
            return toDistinctList.stream().filter(distinctByKey(objectProperty)).collect(Collectors.toCollection(Vector::new));
        }
        if (objectProperty == null) {
            return toDistinctList.stream().distinct().collect(Collectors.toList());
        }
        return toDistinctList.stream().filter(distinctByKey(objectProperty)).collect(Collectors.toList());
    }

    public static <T> List<T> distinct(List<T> toDistinctList) {
        return distinct(toDistinctList, null);
    }

    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> objectProperty) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(objectProperty.apply(t));
    }

2.2 单元测试:

public class ListUtilTest {
    List<Student> students = new ArrayList<>();
    List<Student> studentsDistinct = new ArrayList<>();
    List<Student> studentsDistinctByName = new ArrayList<>();
    List<String> former = new ArrayList<>();
    List<String> formerOnly = new ArrayList<>();
    List<String> latter = new ArrayList<>();
    List<String> latterOnly = new ArrayList<>();
    List<String> common = new ArrayList<>();

    List<String> sampleinkedList = new LinkedList<>();
    List<String> expectLinkedList = new LinkedList<>();
    List<String> sampleVector = new Vector<>();
    List<String> expectVector = new Vector<>();


    @Before
    public void before() {
        Student student0 = Student.builder().age(10).clazz(4).name("tom").build();
        Student student1 = Student.builder().age(10).clazz(4).name("tom").build();
        Student student2 = Student.builder().age(11).clazz(5).name("tom").build();
        Student student3 = Student.builder().age(11).clazz(6).name("jerry").build();
        students.add(student0);
        students.add(student1);
        students.add(student2);
        students.add(student3);
        studentsDistinct.add(student0);
        studentsDistinct.add(student2);
        studentsDistinct.add(student3);
        studentsDistinctByName.add(student0);
        studentsDistinctByName.add(student3);
        former = Arrays.asList("a","b","c");
        formerOnly = Arrays.asList("a", "b");
        latter = Arrays.asList("c","d","e");
        latterOnly = Arrays.asList("d", "e");
        common = Arrays.asList("c");
        sampleinkedList.add("a");
        sampleinkedList.add("b");
        sampleinkedList.add("c");
        sampleinkedList.add("c");
        sampleinkedList.add("d");
        sampleinkedList.add("e");
        sampleinkedList.add("c");
        expectLinkedList.add("a");
        expectLinkedList.add("b");
        expectLinkedList.add("c");
        expectLinkedList.add("d");
        expectLinkedList.add("e");

        sampleVector.add("a");
        sampleVector.add("b");
        sampleVector.add("c");
        sampleVector.add("c");
        sampleVector.add("d");
        sampleVector.add("e");
        sampleVector.add("c");
        expectVector.add("a");
        expectVector.add("b");
        expectVector.add("c");
        expectVector.add("d");
        expectVector.add("e");
    }
    @Test
    public void distinct() {
        List<String> list0 = Arrays.asList("a", "b", "c", "c", "b", "a");
        List<String> actual0 = ListUtil.distinct(list0);
        List<String> expect0 = Arrays.asList("a", "b", "c");
        assertEquals(expect0, actual0);

        List<Integer> list1 = Arrays.asList(1, 2, 3, 3, 2, 1);
        List<Integer> actual1 = ListUtil.distinct(list1);
        List<Integer> expect1 = Arrays.asList(1, 2, 3);
        assertEquals(expect1, actual1);

        List<Double> list2 = Arrays.asList(1.0d, 2.0d, 3.0d, 3.0d, 2.0d, 1.0d);
        List<Double> actual2 = ListUtil.distinct(list2);
        List<Double> expect2 = Arrays.asList(1.0d, 2.0d, 3.0d);
        assertEquals(expect2, actual2);

        List<Float> list3 = Arrays.asList(1.0f, 2.0f, 3.0f, 3.0f, 2.0f, 1.0f);
        List<Float> actual3 = ListUtil.distinct(list3);
        List<Float> expect3 = Arrays.asList(1.0f, 2.0f, 3.0f);
        assertEquals(expect3, actual3);

        ArrayList<Object> list4 = new ArrayList<>();
        List<Object> actual4 = ListUtil.distinct(list4);
        List<Object> expect4 = new ArrayList<>();
        assertEquals(expect4.getClass(), actual4.getClass());

        LinkedList<Object> list5 = new LinkedList<>();
        List<Object> actual5 = ListUtil.distinct(list5);
        List<Object> expect5 = new LinkedList<>();
        assertEquals(expect5.getClass(), actual5.getClass());

        Vector<Object> list6 = new Vector<>();
        List<Object> actual6 = ListUtil.distinct(list6);
        List<Object> expect6 = new Vector<>();
        assertEquals(expect6.getClass(), actual6.getClass());

        List<Student> actual7 = ListUtil.distinct(students);
        assertEquals(studentsDistinct, actual7);

        List<Student> actual8 = ListUtil.distinct(students, Student::getName);
        assertEquals(studentsDistinctByName, actual8);

        List<String> actual9 = ListUtil.distinct(sampleinkedList);
        assertEquals(expectLinkedList, actual9);
        assertEquals(expectLinkedList.getClass(), actual9.getClass());

        List<String> actual10 = ListUtil.distinct(sampleVector);
        assertEquals(expectVector, actual10);
        assertEquals(expectVector.getClass(), actual10.getClass());

    }
}

3. TODO项

  • 根据对象的任意个属性值进行去重处理