From 243eecb61a0e6e7cb0e698f3682c4c6d11d9cb94 Mon Sep 17 00:00:00 2001 From: feilong Date: Fri, 17 Jan 2020 02:33:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20CollectionsUtil.find(Itera?= =?UTF-8?q?ble,=20Map)=20=E6=96=B9=E6=B3=95=20fix=20#813?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完善 DefaultRuntimeException(String, Object...) 注释 fix #812 list 根据多个属性去重 fix #808 --- README.md | 2 +- .../feilong/core/DefaultRuntimeException.java | 16 ++ .../feilong/core/util/CollectionsUtil.java | 237 ++++++++++++++++++ .../FeiLongCollectionsUtilSuiteTests.java | 3 + .../collectionsutiltest/FindWithMapTest.java | 87 +++++++ .../FindWithPredicateTest.java | 4 +- .../RemoveDuplicateOnePropertyNameTest.java | 86 +++++++ .../RemoveDuplicatePropertyNamesTest.java | 104 ++++++++ 8 files changed, 536 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/feilong/core/util/collectionsutiltest/FindWithMapTest.java create mode 100644 src/test/java/com/feilong/core/util/collectionsutiltest/RemoveDuplicateOnePropertyNameTest.java create mode 100644 src/test/java/com/feilong/core/util/collectionsutiltest/RemoveDuplicatePropertyNamesTest.java diff --git a/README.md b/README.md index b2aff01e..693f6605 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ feilong core 让Java开发更简便的工具包 ![JDK 1.7](https://img.shields.io/badge/JDK-1.7-green.svg "JDK 1.7") [![jar size 110K](https://img.shields.io/badge/size-110K-green.svg "size 110K")](https://github.com/venusdrogon/feilong-platform/tree/repository/com/feilong/platform/feilong-core/1.14.0) [![javadoc 83%](http://progressed.io/bar/83?title=javadoc "javadoc 83%")](http://venusdrogon.github.io/feilong-platform/javadocs/feilong-core/) -[![tests 2228](https://img.shields.io/badge/tests-2228%20%2F%202228-green.svg "tests 2228")](https://github.com/venusdrogon/feilong-core/tree/master/src/test/java/com/feilong/core) +[![tests 2248](https://img.shields.io/badge/tests-2248%20%2F%202248-green.svg "tests 2248")](https://github.com/venusdrogon/feilong-core/tree/master/src/test/java/com/feilong/core) ![Coverage 91%](http://progressed.io/bar/91?title=Coverage "Coverage 91%") ![sonar](http://venusdrogon.github.io/feilong-platform/mysource/sonar/feilong-core-summary2.jpg) diff --git a/src/main/java/com/feilong/core/DefaultRuntimeException.java b/src/main/java/com/feilong/core/DefaultRuntimeException.java index c682eedf..624a7c6c 100644 --- a/src/main/java/com/feilong/core/DefaultRuntimeException.java +++ b/src/main/java/com/feilong/core/DefaultRuntimeException.java @@ -178,6 +178,22 @@ public DefaultRuntimeException(String message){ /** * Instantiates a new abstract runtime exception. + * + *

示例:

+ * + *
+ * + *
+     * 
+     * throw new DefaultRuntimeException(
+     *                 "code not 00 is[{}],gatewayResponse:[{}],chinaumsQueryResultCommand:[{}]",
+     *                 code,
+     *                 gatewayResponse,
+     *                 JsonUtil.format(chinaumsQueryResultCommand));
+     * 
+     * 
+ * + *
* * @param messagePattern * the message pattern diff --git a/src/main/java/com/feilong/core/util/CollectionsUtil.java b/src/main/java/com/feilong/core/util/CollectionsUtil.java index 34c7b611..d4e7921d 100644 --- a/src/main/java/com/feilong/core/util/CollectionsUtil.java +++ b/src/main/java/com/feilong/core/util/CollectionsUtil.java @@ -34,6 +34,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; @@ -763,6 +764,182 @@ public static List removeDuplicate(Collection objectCollection){ return isNullOrEmpty(objectCollection) ? Collections. emptyList() : toList(new LinkedHashSet(objectCollection)); } + /** + * 去重,返回指定属性 propertyName的值没有重复元素的新list (原集合对象不变). + * + *

示例:

+ *
+ * + *
+     * User user1 = new User(1L);
+     * User user2 = new User(1L);
+     * List{@code } list = toList(user1, user2);
+     * 
+     * List{@code } removeDuplicate = CollectionsUtil.removeDuplicate(list, "id");
+     * 
+     * assertThat(removeDuplicate, contains(user1));
+     * assertSame(1, removeDuplicate.size());
+     * 
+ * + *
+ * + *

注意:

+ *
+ *
    + *
  1. 如果原 objectCollection 是有序的,那么返回的结果参照原 objectCollection元素顺序
  2. + *
  3. objectCollection不变
  4. + *
+ *
+ * + * @param + * the generic type + * @param objectCollection + * the object collection + * @param propertyName + * 包含的属性数组名字数组,(can be nested/indexed/mapped/combo),
+ * 如果是null或者empty,那么直接调用 {@link #removeDuplicate(Collection)}
+ * @return 如果 propertyNames 是null或者empty,那么直接调用 {@link #removeDuplicate(Collection)}
+ * 如果 objectCollection 是null或者empty,返回 {@link Collections#emptyList()}
+ * @see LinkedHashSet#LinkedHashSet(Collection) + * @see com.feilong.core.bean.ConvertUtil#toList(Collection) + * @see org.apache.commons.collections4.IterableUtils#uniqueIterable(Iterable) + * @see http://www.oschina.net/code/snippet_117714_2991?p=2#comments + * + * @since 2.0.3 + */ + public static List removeDuplicate(Collection objectCollection,String propertyName){ + if (isNullOrEmpty(propertyName)){ + return removeDuplicate(objectCollection); + } + if (isNullOrEmpty(objectCollection)){ + return Collections. emptyList(); + } + + //--------------------------------------------------------------- + Map map = groupOne(objectCollection, propertyName); + return toList(map.values()); + } + + /** + * 去重,返回指定属性 propertyNames 组合的值都不重复元素的新list (原集合对象不变). + * + *

示例:

+ *
+ * + *
+     * User user1 = new User(1L);
+     * user1.setUserInfo(new UserInfo(15));
+     * 
+     * User user2 = new User(1L);
+     * user2.setUserInfo(new UserInfo(16));
+     * 
+     * User user3 = new User(1L);
+     * user3.setUserInfo(new UserInfo(15));
+     * 
+     * List{@code } list = toList(user1, user2, user3);
+     * 
+     * List{@code } removeDuplicate = CollectionsUtil.removeDuplicate(list, "id", "userInfo.age");
+     * 
+     * assertThat(removeDuplicate, contains(user1, user2));
+     * assertSame(2, removeDuplicate.size());
+     * 
+ * + * + *
+ * + *

注意:

+ *
+ *
    + *
  1. 如果原 objectCollection 是有序的,那么返回的结果参照原 objectCollection元素顺序
  2. + *
  3. objectCollection不变
  4. + *
+ *
+ * + * @param + * the generic type + * @param objectCollection + * the object collection + * @param propertyNames + * 包含的属性数组名字数组,(can be nested/indexed/mapped/combo),
+ * 如果是null或者empty,那么直接调用 {@link #removeDuplicate(Collection)}
+ * @return 如果 propertyNames 是null或者empty,那么直接调用 {@link #removeDuplicate(Collection)}
+ * 如果 objectCollection 是null或者empty,返回 {@link Collections#emptyList()}
+ * @see LinkedHashSet#LinkedHashSet(Collection) + * @see com.feilong.core.bean.ConvertUtil#toList(Collection) + * @see org.apache.commons.collections4.IterableUtils#uniqueIterable(Iterable) + * @see http://www.oschina.net/code/snippet_117714_2991?p=2#comments + * + * @since 2.0.3 + */ + public static List removeDuplicate(Collection objectCollection,String...propertyNames){ + if (isNullOrEmpty(propertyNames)){ + return removeDuplicate(objectCollection); + } + if (isNullOrEmpty(objectCollection)){ + return Collections. emptyList(); + } + + //--------------------------------------------------------------- + //用来识别是否重复 + List> mapList = newArrayList(); + + //用来存放返回list + List returnList = new ArrayList<>(IterableUtils.size(objectCollection)); + for (O o : objectCollection){ + Map propertyNameAndValueMap = PropertyUtil.describe(o, propertyNames); + boolean isNotExist = !isExist(mapList, propertyNameAndValueMap, propertyNames); + if (isNotExist){ + returnList.add(o); + mapList.add(propertyNameAndValueMap); + } + } + return returnList; + } + + /** + * 判断mapList 中,是否含有 指定 key-value 的map. + * + * @param mapList + * the map list + * @param propertyNameAndValueMap + * the property name and value map + * @param keys + * the keys + * @return 存在,返回true + * @since 2.0.3 + */ + private static boolean isExist(List> mapList,Map propertyNameAndValueMap,String...keys){ + for (Map map : mapList){ + if (eqauls(map, propertyNameAndValueMap, keys)){ + return true; + } + } + return false; + } + + /** + * 判断两个map ,提取每个属性 keys 值, 看看是否一致, 如果有不一致的返回false; 如果都一致那么返回true. + * + * @param map + * the map + * @param propertyNameAndValueMap + * the property name and value map + * @param keys + * the property names + * @return true, if successful + * @since 2.0.3 + */ + private static boolean eqauls(Map map,Map propertyNameAndValueMap,String...keys){ + for (String propertyName : keys){ + if (!Objects.equals(map.get(propertyName), propertyNameAndValueMap.get(propertyName))){ + return false; + } + } + return true; + } + //----------------------获得 属性值----------------------------------------- /** @@ -1174,6 +1351,66 @@ public static O find(Iterable beanIterable,String propertyName,V prope return null == beanIterable ? null : find(beanIterable, BeanPredicateUtil. equalPredicate(propertyName, propertyValue)); } + /** + * 找到 iterable中,第一个 propertyName属性名称和值是 propertyValue是 propertyNameAndPropertyValueMap 的对应元素. + * + *

示例:

+ *
+ * + *

+ * 场景: 从list中查找name是 关羽,且年龄是24 的User对象 + *

+ * + *
+     * List{@code } list = new ArrayList{@code <>}();
+     * list.add(new User("张飞", 23));
+     * list.add(new User("关羽", 24));
+     * list.add(new User("刘备", 25));
+     * list.add(new User("关羽", 50));
+     * 
+     * Map{@code } map = toMap("name", "关羽", "age", 24);
+     * LOGGER.info(JsonUtil.format(CollectionsUtil.find(list, map)));
+     * 
+ * + * 返回: + * + *
+     * {
+     * "age": 24,
+     * "name": "关羽"
+     * }
+     * 
+ * + *
+ * + *

说明:

+ *
+ *
    + *
  1. 返回第一个匹配对象
  2. + *
+ *
+ * + * @param + * the generic type + * @param beanIterable + * bean Iterable,诸如List{@code },Set{@code }等 + * @param propertyNameAndPropertyValueMap + * 属性和指定属性值对应的map,其中key是泛型T对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 + * propertyName + * @return 如果 iterable是null, 返回null
+ * 如果 propertyNameAndPropertyValueMap 是null,抛出 {@link NullPointerException}
+ * 如果 propertyNameAndPropertyValueMap 是empty,抛出{@link IllegalArgumentException}
+ * 如果 propertyNameAndPropertyValueMap 中有key是null,抛出{@link NullPointerException}
+ * 如果 propertyNameAndPropertyValueMap 中有key是blank,抛出{@link IllegalArgumentException}
+ * 如果 iterable中没有相关元素的属性propertyName 值是propertyValue,返回null + * @see #find(Iterable, Predicate) + * @see com.feilong.core.util.predicate.BeanPredicateUtil#equalPredicate(String, Object) + * @since 2.0.3 + */ + public static O find(Iterable beanIterable,Map propertyNameAndPropertyValueMap){ + return null == beanIterable ? null : find(beanIterable, BeanPredicateUtil. equalPredicate(propertyNameAndPropertyValueMap)); + } + /** * 迭代查找匹配predicate 的第一个元素并返回. * diff --git a/src/test/java/com/feilong/core/util/collectionsutiltest/FeiLongCollectionsUtilSuiteTests.java b/src/test/java/com/feilong/core/util/collectionsutiltest/FeiLongCollectionsUtilSuiteTests.java index b6e23004..3e0a8550 100644 --- a/src/test/java/com/feilong/core/util/collectionsutiltest/FeiLongCollectionsUtilSuiteTests.java +++ b/src/test/java/com/feilong/core/util/collectionsutiltest/FeiLongCollectionsUtilSuiteTests.java @@ -39,6 +39,7 @@ CollectIteratorTest.class, FindTest.class, + FindWithMapTest.class, FindWithPredicateTest.class, GetPropertyValueListTest.class, @@ -63,6 +64,8 @@ SelectRejectedPredicateTest.class, RemoveDuplicateTest.class, + RemoveDuplicateOnePropertyNameTest.class, + RemoveDuplicatePropertyNamesTest.class, RemoveElementTest.class, RemoveAllNullTest.class, RemoveAllCollectionTest.class, diff --git a/src/test/java/com/feilong/core/util/collectionsutiltest/FindWithMapTest.java b/src/test/java/com/feilong/core/util/collectionsutiltest/FindWithMapTest.java new file mode 100644 index 00000000..37f6d0d1 --- /dev/null +++ b/src/test/java/com/feilong/core/util/collectionsutiltest/FindWithMapTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 feilong + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.feilong.core.util.collectionsutiltest; + +import static com.feilong.core.bean.ConvertUtil.toList; +import static com.feilong.core.bean.ConvertUtil.toMap; +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import com.feilong.core.util.CollectionsUtil; +import com.feilong.store.member.User; + +/** + * The Class CollectionsUtilFindWithPredicateTest. + * + * @author feilong + */ +public class FindWithMapTest{ + + /** + * Test find2. + */ + @Test + @SuppressWarnings("static-method") + public void testFind2(){ + User guanyu30 = new User("关羽", 30); + + List list = toList(// + new User("张飞", 23), + new User("关羽", 24), + new User("刘备", 25), + guanyu30); + + Map map = toMap("name", "关羽", "age", 30); + assertEquals(guanyu30, CollectionsUtil.find(list, map)); + } + + //--------------------------------------------------------------- + + /** + * Test find null predicate. + */ + @Test(expected = NullPointerException.class) + public void testFindNullPredicate(){ + List list = toList(new User("张飞", 23)); + CollectionsUtil.find(list, (Map) null); + } + + @Test + public void testFindNullPredicate1(){ + assertEquals(null, CollectionsUtil.find(null, (Map) null)); + } + + /** + * Test find null iterable. + */ + @Test + public void testFindNullIterable(){ + assertEquals(null, CollectionsUtil.find(null, toMap("name", "关羽"))); + } + + /** + * Test find not find. + */ + @Test + public void testFindNotFind(){ + List list = toList(new User("张飞", 23)); + assertEquals(null, CollectionsUtil.find(list, toMap("name", "关羽"))); + } +} diff --git a/src/test/java/com/feilong/core/util/collectionsutiltest/FindWithPredicateTest.java b/src/test/java/com/feilong/core/util/collectionsutiltest/FindWithPredicateTest.java index 4cc947f3..6db5db51 100644 --- a/src/test/java/com/feilong/core/util/collectionsutiltest/FindWithPredicateTest.java +++ b/src/test/java/com/feilong/core/util/collectionsutiltest/FindWithPredicateTest.java @@ -61,7 +61,7 @@ public void testFind2(){ @Test(expected = NullPointerException.class) public void testFindNullPredicate(){ List list = toList(new User("张飞", 23)); - CollectionsUtil.find(list, null); + CollectionsUtil.find(list, (Predicate) null); } /** @@ -69,7 +69,7 @@ public void testFindNullPredicate(){ */ @Test(expected = NullPointerException.class) public void testFindNullPredicate1(){ - CollectionsUtil.find(null, null); + CollectionsUtil.find(null, (Predicate) null); } /** diff --git a/src/test/java/com/feilong/core/util/collectionsutiltest/RemoveDuplicateOnePropertyNameTest.java b/src/test/java/com/feilong/core/util/collectionsutiltest/RemoveDuplicateOnePropertyNameTest.java new file mode 100644 index 00000000..d2432888 --- /dev/null +++ b/src/test/java/com/feilong/core/util/collectionsutiltest/RemoveDuplicateOnePropertyNameTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008 feilong + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.feilong.core.util.collectionsutiltest; + +import static com.feilong.core.bean.ConvertUtil.toList; +import static java.util.Collections.emptyList; +import static org.hamcrest.Matchers.contains; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import com.feilong.core.util.CollectionsUtil; +import com.feilong.store.member.User; + +public class RemoveDuplicateOnePropertyNameTest{ + + @Test + public void testRemoveDuplicate(){ + User user1 = new User(1L); + User user2 = new User(1L); + List list = toList(user1, user2); + + List removeDuplicate = CollectionsUtil.removeDuplicate(list, "id"); + + assertThat(removeDuplicate, contains(user1)); + assertSame(1, removeDuplicate.size()); + } + + //--------------------------------------------------------------- + + /** + * Test remove duplicate null collection. + */ + @Test + public void testRemoveDuplicateNullCollection(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(null, (String) null)); + } + + @Test + public void testRemoveDuplicateNullCollection1(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(null, "")); + } + + //--------------------------------------------------------------- + + @Test + public void testRemoveDuplicateEmptyCollection(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(new ArrayList<>(), (String) null)); + } + + @Test + public void testRemoveDuplicateEmptyCollection22(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(new ArrayList<>(), "")); + } + + //--------------------------------------------------------------- + + @Test + public void testRemoveDuplicateEmptyCollection1(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(toList(), (String) null)); + } + + @Test + public void testRemoveDuplicateEmptyCollection1222(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(toList(), "")); + } + +} diff --git a/src/test/java/com/feilong/core/util/collectionsutiltest/RemoveDuplicatePropertyNamesTest.java b/src/test/java/com/feilong/core/util/collectionsutiltest/RemoveDuplicatePropertyNamesTest.java new file mode 100644 index 00000000..2d49ca5d --- /dev/null +++ b/src/test/java/com/feilong/core/util/collectionsutiltest/RemoveDuplicatePropertyNamesTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2008 feilong + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.feilong.core.util.collectionsutiltest; + +import static com.feilong.core.bean.ConvertUtil.toArray; +import static com.feilong.core.bean.ConvertUtil.toList; +import static java.util.Collections.emptyList; +import static org.hamcrest.Matchers.contains; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import com.feilong.core.util.CollectionsUtil; +import com.feilong.store.member.User; +import com.feilong.store.member.UserInfo; + +public class RemoveDuplicatePropertyNamesTest{ + + @Test + public void testRemoveDuplicate(){ + User user1 = new User(1L, 15); + User user2 = new User(1L, 16); + User user3 = new User(1L, 15); + List list = toList(user1, user2, user3); + + List removeDuplicate = CollectionsUtil.removeDuplicate(list, "id", "age"); + + assertThat(removeDuplicate, contains(user1, user2)); + assertSame(2, removeDuplicate.size()); + } + + @Test + public void testRemoveDuplicate1(){ + User user1 = new User(1L); + user1.setUserInfo(new UserInfo(15)); + + User user2 = new User(1L); + user2.setUserInfo(new UserInfo(16)); + + User user3 = new User(1L); + user3.setUserInfo(new UserInfo(15)); + + List list = toList(user1, user2, user3); + + List removeDuplicate = CollectionsUtil.removeDuplicate(list, "id", "userInfo.age"); + + assertThat(removeDuplicate, contains(user1, user2)); + assertSame(2, removeDuplicate.size()); + } + + //--------------------------------------------------------------- + + @Test + public void testRemoveDuplicateNullCollection(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(null, (String[]) null)); + } + + @Test + public void testRemoveDuplicateNullCollection12(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(null, toArray(""))); + } + + //--------------------------------------------------------------- + + @Test + public void testRemoveDuplicateEmptyCollection(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(new ArrayList<>(), (String[]) null)); + } + + @Test + public void testRemoveDuplicateEmptyCollection333(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(new ArrayList<>(), toArray(""))); + } + + //--------------------------------------------------------------- + + @Test + public void testRemoveDuplicateEmptyCollection1(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(toList(), (String[]) null)); + } + + @Test + public void testRemoveDuplicateEmptyCollection1333(){ + assertEquals(emptyList(), CollectionsUtil.removeDuplicate(toList(), toArray(""))); + } +}