Skip to content
This repository has been archived by the owner on Aug 20, 2021. It is now read-only.

Commit

Permalink
新增 CollectionsUtil.find(Iterable<O>, Map<String, ?>) 方法 fix #813
Browse files Browse the repository at this point in the history
完善 DefaultRuntimeException(String, Object...) 注释  fix #812

list 根据多个属性去重 fix #808
  • Loading branch information
venusdrogon committed Jan 16, 2020
1 parent 245bfa9 commit 243eecb
Show file tree
Hide file tree
Showing 8 changed files with 536 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/feilong/core/DefaultRuntimeException.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,22 @@ public DefaultRuntimeException(String message){

/**
* Instantiates a new abstract runtime exception.
*
* <h3>示例:</h3>
*
* <blockquote>
*
* <pre class="code">
*
* throw new DefaultRuntimeException(
* "code not 00 is[{}],gatewayResponse:[{}],chinaumsQueryResultCommand:[{}]",
* code,
* gatewayResponse,
* JsonUtil.format(chinaumsQueryResultCommand));
*
* </pre>
*
* </blockquote>
*
* @param messagePattern
* the message pattern
Expand Down
237 changes: 237 additions & 0 deletions src/main/java/com/feilong/core/util/CollectionsUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -763,6 +764,182 @@ public static <O> List<O> removeDuplicate(Collection<O> objectCollection){
return isNullOrEmpty(objectCollection) ? Collections.<O> emptyList() : toList(new LinkedHashSet<O>(objectCollection));
}

/**
* 去重,返回指定属性 propertyName的值没有重复元素的新list <span style="color:red">(原集合对象不变)</span>.
*
* <h3>示例:</h3>
* <blockquote>
*
* <pre class="code">
* User user1 = new User(1L);
* User user2 = new User(1L);
* List{@code <User>} list = toList(user1, user2);
*
* List{@code <User>} removeDuplicate = CollectionsUtil.removeDuplicate(list, "id");
*
* assertThat(removeDuplicate, contains(user1));
* assertSame(1, removeDuplicate.size());
* </pre>
*
* </blockquote>
*
* <h3>注意:</h3>
* <blockquote>
* <ol>
* <li>如果原 <code>objectCollection</code> 是有序的,那么返回的结果参照原 <code>objectCollection</code>元素顺序</li>
* <li>原 <code>objectCollection</code>不变</li>
* </ol>
* </blockquote>
*
* @param <O>
* the generic type
* @param objectCollection
* the object collection
* @param propertyName
* 包含的属性数组名字数组,(can be nested/indexed/mapped/combo),<br>
* 如果是null或者empty,那么直接调用 {@link #removeDuplicate(Collection)}<br>
* @return 如果 <code>propertyNames</code> 是null或者empty,那么直接调用 {@link #removeDuplicate(Collection)}<br>
* 如果 <code>objectCollection</code> 是null或者empty,返回 {@link Collections#emptyList()}<br>
* @see LinkedHashSet#LinkedHashSet(Collection)
* @see com.feilong.core.bean.ConvertUtil#toList(Collection)
* @see org.apache.commons.collections4.IterableUtils#uniqueIterable(Iterable)
* @see <a
* href="http://www.oschina.net/code/snippet_117714_2991?p=2#comments">http://www.oschina.net/code/snippet_117714_2991?p=2#comments
* </a>
* @since 2.0.3
*/
public static <O> List<O> removeDuplicate(Collection<O> objectCollection,String propertyName){
if (isNullOrEmpty(propertyName)){
return removeDuplicate(objectCollection);
}
if (isNullOrEmpty(objectCollection)){
return Collections.<O> emptyList();
}

//---------------------------------------------------------------
Map<Object, O> map = groupOne(objectCollection, propertyName);
return toList(map.values());
}

/**
* 去重,返回指定属性 propertyNames 组合的值都不重复元素的新list <span style="color:red">(原集合对象不变)</span>.
*
* <h3>示例:</h3>
* <blockquote>
*
* <pre class="code">
* 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 <User>} list = toList(user1, user2, user3);
*
* List{@code <User>} removeDuplicate = CollectionsUtil.removeDuplicate(list, "id", "userInfo.age");
*
* assertThat(removeDuplicate, contains(user1, user2));
* assertSame(2, removeDuplicate.size());
* </pre>
*
*
* </blockquote>
*
* <h3>注意:</h3>
* <blockquote>
* <ol>
* <li>如果原 <code>objectCollection</code> 是有序的,那么返回的结果参照原 <code>objectCollection</code>元素顺序</li>
* <li>原 <code>objectCollection</code>不变</li>
* </ol>
* </blockquote>
*
* @param <O>
* the generic type
* @param objectCollection
* the object collection
* @param propertyNames
* 包含的属性数组名字数组,(can be nested/indexed/mapped/combo),<br>
* 如果是null或者empty,那么直接调用 {@link #removeDuplicate(Collection)}<br>
* @return 如果 <code>propertyNames</code> 是null或者empty,那么直接调用 {@link #removeDuplicate(Collection)}<br>
* 如果 <code>objectCollection</code> 是null或者empty,返回 {@link Collections#emptyList()}<br>
* @see LinkedHashSet#LinkedHashSet(Collection)
* @see com.feilong.core.bean.ConvertUtil#toList(Collection)
* @see org.apache.commons.collections4.IterableUtils#uniqueIterable(Iterable)
* @see <a
* href="http://www.oschina.net/code/snippet_117714_2991?p=2#comments">http://www.oschina.net/code/snippet_117714_2991?p=2#comments
* </a>
* @since 2.0.3
*/
public static <O> List<O> removeDuplicate(Collection<O> objectCollection,String...propertyNames){
if (isNullOrEmpty(propertyNames)){
return removeDuplicate(objectCollection);
}
if (isNullOrEmpty(objectCollection)){
return Collections.<O> emptyList();
}

//---------------------------------------------------------------
//用来识别是否重复
List<Map<String, Object>> mapList = newArrayList();

//用来存放返回list
List<O> returnList = new ArrayList<>(IterableUtils.size(objectCollection));
for (O o : objectCollection){
Map<String, Object> propertyNameAndValueMap = PropertyUtil.describe(o, propertyNames);
boolean isNotExist = !isExist(mapList, propertyNameAndValueMap, propertyNames);
if (isNotExist){
returnList.add(o);
mapList.add(propertyNameAndValueMap);
}
}
return returnList;
}

/**
* 判断<code>mapList</code> 中,是否含有 指定 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<Map<String, Object>> mapList,Map<String, Object> propertyNameAndValueMap,String...keys){
for (Map<String, Object> map : mapList){
if (eqauls(map, propertyNameAndValueMap, keys)){
return true;
}
}
return false;
}

/**
* 判断两个map ,提取每个属性 <code>keys</code> 值, 看看是否一致, 如果有不一致的返回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<String, Object> map,Map<String, Object> propertyNameAndValueMap,String...keys){
for (String propertyName : keys){
if (!Objects.equals(map.get(propertyName), propertyNameAndValueMap.get(propertyName))){
return false;
}
}
return true;
}

//----------------------获得 属性值-----------------------------------------

/**
Expand Down Expand Up @@ -1174,6 +1351,66 @@ public static <O, V> O find(Iterable<O> beanIterable,String propertyName,V prope
return null == beanIterable ? null : find(beanIterable, BeanPredicateUtil.<O, V> equalPredicate(propertyName, propertyValue));
}

/**
* 找到 <code>iterable</code>中,第一个 <code>propertyName</code>属性名称和值是 <code>propertyValue</code>是 propertyNameAndPropertyValueMap 的对应元素.
*
* <h3>示例:</h3>
* <blockquote>
*
* <p>
* <b>场景:</b> 从list中查找name是 关羽,且年龄是24 的User对象
* </p>
*
* <pre class="code">
* List{@code <User>} 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 <String, ?>} map = toMap("name", "关羽", "age", 24);
* LOGGER.info(JsonUtil.format(CollectionsUtil.find(list, map)));
* </pre>
*
* <b>返回:</b>
*
* <pre class="code">
* {
* "age": 24,
* "name": "关羽"
* }
* </pre>
*
* </blockquote>
*
* <h3>说明:</h3>
* <blockquote>
* <ol>
* <li>返回第一个匹配对象</li>
* </ol>
* </blockquote>
*
* @param <O>
* the generic type
* @param beanIterable
* bean Iterable,诸如List{@code <User>},Set{@code <User>}等
* @param propertyNameAndPropertyValueMap
* 属性和指定属性值对应的map,其中key是泛型T对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见
* <a href="../../bean/BeanUtil.html#propertyName">propertyName</a>
* @return 如果 <code>iterable</code>是null, 返回null<br>
* 如果 <code>propertyNameAndPropertyValueMap</code> 是null,抛出 {@link NullPointerException}<br>
* 如果 <code>propertyNameAndPropertyValueMap</code> 是empty,抛出{@link IllegalArgumentException}<br>
* 如果 <code>propertyNameAndPropertyValueMap</code> 中有key是null,抛出{@link NullPointerException}<br>
* 如果 <code>propertyNameAndPropertyValueMap</code> 中有key是blank,抛出{@link IllegalArgumentException}<br>
* 如果 <code>iterable</code>中没有相关元素的属性<code>propertyName</code> 值是<code>propertyValue</code>,返回null
* @see #find(Iterable, Predicate)
* @see com.feilong.core.util.predicate.BeanPredicateUtil#equalPredicate(String, Object)
* @since 2.0.3
*/
public static <O> O find(Iterable<O> beanIterable,Map<String, ?> propertyNameAndPropertyValueMap){
return null == beanIterable ? null : find(beanIterable, BeanPredicateUtil.<O> equalPredicate(propertyNameAndPropertyValueMap));
}

/**
* 迭代查找匹配<code>predicate</code> 的第一个元素并返回.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
CollectIteratorTest.class,

FindTest.class,
FindWithMapTest.class,
FindWithPredicateTest.class,

GetPropertyValueListTest.class,
Expand All @@ -63,6 +64,8 @@
SelectRejectedPredicateTest.class,

RemoveDuplicateTest.class,
RemoveDuplicateOnePropertyNameTest.class,
RemoveDuplicatePropertyNamesTest.class,
RemoveElementTest.class,
RemoveAllNullTest.class,
RemoveAllCollectionTest.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <a href="http://feitianbenyue.iteye.com/">feilong</a>
*/
public class FindWithMapTest{

/**
* Test find2.
*/
@Test
@SuppressWarnings("static-method")
public void testFind2(){
User guanyu30 = new User("关羽", 30);

List<User> list = toList(//
new User("张飞", 23),
new User("关羽", 24),
new User("刘备", 25),
guanyu30);

Map<String, ?> map = toMap("name", "关羽", "age", 30);
assertEquals(guanyu30, CollectionsUtil.find(list, map));
}

//---------------------------------------------------------------

/**
* Test find null predicate.
*/
@Test(expected = NullPointerException.class)
public void testFindNullPredicate(){
List<User> list = toList(new User("张飞", 23));
CollectionsUtil.find(list, (Map<String, ?>) null);
}

@Test
public void testFindNullPredicate1(){
assertEquals(null, CollectionsUtil.find(null, (Map<String, ?>) 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<User> list = toList(new User("张飞", 23));
assertEquals(null, CollectionsUtil.find(list, toMap("name", "关羽")));
}
}
Loading

0 comments on commit 243eecb

Please sign in to comment.