jsonobject转list集合_怎样优雅的操作集合,CollectionUtils工具类正确使用姿势
點(diǎn)擊上方"碼之初"關(guān)注,···選擇"設(shè)為星標(biāo)"
與精品技術(shù)文章不期而遇
來源:cnblogs.com/qdhxhz/p/10787130.html
這篇講的CollectionUtils工具類是在apache下的, 而不是springframework下的CollectionUtils。
個人覺得CollectionUtils在真實(shí)項(xiàng)目中,可以使你的代碼更加簡潔和安全。
所以需要倒入相關(guān)jar包,目前從maven找到最新jar包如下:
<dependency><groupId>org.apache.commonsgroupId><artifactId>commons-collections4artifactId><version>4.3version>dependency>一、API常用方法
/** * 1、除非元素為null,否則向集合添加元素 */ CollectionUtils.addIgnoreNull(personList,null); /** * 2、將兩個已排序的集合a和b合并為一個已排序的列表,以便保留元素的自然順序 */ CollectionUtils.collate(Iterable extends O> a, Iterable extends O> b) /** * 3、將兩個已排序的集合a和b合并到一個已排序的列表中,以便保留根據(jù)Comparator c的元素順序。 */ CollectionUtils.collate(Iterable extends O> a, Iterable extends O> b, Comparator super O> c) /** * 4、返回該個集合中是否含有至少有一個元素 */ CollectionUtils.containsAny(Collection> coll1, T... coll2) /** * 5、如果參數(shù)是null,則返回不可變的空集合,否則返回參數(shù)本身。(很實(shí)用 ,最終返回List EMPTY_LIST = new EmptyList<>()) */ CollectionUtils.emptyIfNull(Collection collection) /** * 6、空安全檢查指定的集合是否為空 */ CollectionUtils.isEmpty(Collection> coll) /** * 7、 空安全檢查指定的集合是否為空。 */ CollectionUtils.isNotEmpty(Collection> coll) /** * 8、反轉(zhuǎn)給定數(shù)組的順序。 */ CollectionUtils.reverseArray(Object[] array); /** * 9、差集 */ CollectionUtils.subtract(Iterable extends O> a, Iterable extends O> b) /** * 10、并集 */ CollectionUtils.union(Iterable extends O> a, Iterable extends O> b) /** * 11、交集 */ CollectionUtils.intersection(Collection a, Collection b) /** *12、 交集的補(bǔ)集(析取) */ CollectionUtils.disjunction(Collection a, Collection b)二、非對象集合交、并、差處理
對于集合取交集、并集的處理其實(shí)有很多種方式,這里就介紹3種
第一種 是CollectionUtils工具類
第二種 是List自帶方法
第三種 是JDK1.8 stream 新特性
1、CollectionUtils工具類
下面對于基本數(shù)據(jù)(包擴(kuò)String)類型中的集合進(jìn)行demo示例。
public static void main(String[] args) { String[] arrayA = new String[] { "1", "2", "3", "4"}; String[] arrayB = new String[] { "3", "4", "5", "6" }; List<String> listA = Arrays.asList(arrayA); List<String> listB = Arrays.asList(arrayB); //1、并集 union System.out.println(CollectionUtils.union(listA, listB)); //輸出: [1, 2, 3, 4, 5, 6] //2、交集 intersection System.out.println(CollectionUtils.intersection(listA, listB)); //輸出:[3, 4] //3、交集的補(bǔ)集(析取)disjunction System.out.println(CollectionUtils.disjunction(listA, listB)); //輸出:[1, 2, 5, 6] //4、差集(扣除) System.out.println(CollectionUtils.subtract(listA, listB)); //輸出:[1, 2] }2、List自帶方法
public static void main(String[] args) { String[] arrayA = new String[] { "1", "2", "3", "4"}; String[] arrayB = new String[] { "3", "4", "5", "6" }; List<String> listA = Arrays.asList(arrayA); List<String> listB = Arrays.asList(arrayB); //1、交集 List<String> jiaoList = new ArrayList<>(listA); jiaoList.retainAll(listB); System.out.println(jiaoList); //輸出:[3, 4] //2、差集 List<String> chaList = new ArrayList<>(listA); chaList.removeAll(listB); System.out.println(chaList); //輸出:[1, 2] //3、并集 (先做差集再做添加所有) List<String> bingList = new ArrayList<>(listA); bingList.removeAll(listB); // bingList為 [1, 2] bingList.addAll(listB); //添加[3,4,5,6] System.out.println(bingList); //輸出:[1, 2, 3, 4, 5, 6] }注意?:?intersection和retainAll的差別
要注意的是它們的返回類型是不一樣的,intersection返回的是一個新的List集合,而retainAll返回是Bollean類型那就說明retainAll方法是對原有集合進(jìn)行處理再返回原有集合,會改變原有集合中的內(nèi)容。
個人觀點(diǎn):1、從性能角度來考慮的話,List自帶會高點(diǎn),因?yàn)樗挥迷賱?chuàng)建新的集合。2、需要注意的是:因?yàn)閞etainAll因?yàn)闀淖冊屑?所以該集合需要多次使用就不適合用retainAll。
注意: Arrays.asList將數(shù)組轉(zhuǎn)集合不能進(jìn)行add和remove操作。
原因:調(diào)用Arrays.asList()生產(chǎn)的List的add、remove方法時報異常,這是由Arrays.asList() 返回的市Arrays的內(nèi)部類ArrayList, 而不是java.util.ArrayList。Arrays的內(nèi)部類ArrayList和java.util.ArrayList都是繼承AbstractList,remove、add等方法AbstractList中是默認(rèn)throw UnsupportedOperationException而且不作任何操作。java.util.ArrayList重新了這些方法而Arrays的內(nèi)部類ArrayList沒有重新,所以會拋出異常。
所以正確做法如下
String[] array = {"1","2","3","4","5"};List list = Arrays.asList(array);
List arrList = new ArrayList(list);
arrList.add("6");
3、JDK1.8 stream 新特性
public static void main(String[] args) { String[] arrayA = new String[] { "1", "2", "3", "4"}; String[] arrayB = new String[] { "3", "4", "5", "6" }; List<String> listA = Arrays.asList(arrayA); List<String> listB = Arrays.asList(arrayB); // 交集 List<String> intersection = listA.stream().filter(item -> listB.contains(item)).collect(toList()); System.out.println(intersection); //輸出:[3, 4] // 差集 (list1 - list2) List<String> reduceList = listA.stream().filter(item -> !listB.contains(item)).collect(toList()); System.out.println(reduceList); //輸出:[1, 2] // 并集 (新建集合:1、是因?yàn)椴挥绊懺技稀?、Arrays.asList不能add和remove操作。 List<String> listAll = listA.parallelStream().collect(toList()); List<String> listAll2 = listB.parallelStream().collect(toList()); listAll.addAll(listAll2); System.out.println(listAll); //輸出:[1, 2, 3, 4, 3, 4, 5, 6] // 去重并集 List<String> list =new ArrayList<>(listA); list.addAll(listB); List<String> listAllDistinct = list.stream().distinct().collect(toList()); System.out.println(listAllDistinct); //輸出:[1, 2, 3, 4, 5, 6] }總結(jié)?:這三種我還是最喜歡第一種方式,因?yàn)榈诙N還需要確定該集合是否被多次調(diào)用。第三種可讀性不高。
三、對象集合交、并、差處理
因?yàn)閷ο蟮膃quels比較是比較兩個對象的內(nèi)存地址,所以除非是同一對象,否則equel返回永遠(yuǎn)是false。
但我們實(shí)際開發(fā)中 在我們的業(yè)務(wù)系統(tǒng)中判斷對象時有時候需要的不是一種嚴(yán)格意義上的相等,而是一種業(yè)務(wù)上的對象相等。在這種情況下,原生的equals方法就不能滿足我們的需求了,所以這個時候我們需要重寫equals方法。
說明?:String為什么可以使用equels方法為什么只要字符串相等就為true,那是因?yàn)镾tring類重寫了equal和hashCode方法,比較的是值。
1、Person對象
public class Person { private String name; private Integer age; public Person(String name, Integer age) { this.name = name; this.age = age; } /** * 為什么重寫equals方法一定要重寫hashCode方法下面也會講 */ @Override public int hashCode() { String result = name + age; return result.hashCode(); } /** * 重寫 equals 方法 根據(jù)name和age都相同那么對象就默認(rèn)相同 */ @Override public boolean equals(Object obj) { Person u = (Person) obj; return this.getName().equals(u.getName()) && (this.age.equals(u.getAge())); } /** * 重寫 toString 方法 */ @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }2、測試
這里根據(jù)name和age都相同那么就默認(rèn)相同對象。
public static void main(String[] args) { List personList = Lists.newArrayList(); Person person1 = new Person("小小",3); Person person2 = new Person("中中",4); personList.add(person1); personList.add(person2); List person1List = Lists.newArrayList(); Person person3 = new Person("中中",4); Person person4 = new Person("大大",5); person1List.add(person3); person1List.add(person4); /** * 1、差集 */ System.out.println(CollectionUtils.subtract(personList, person1List)); //輸出:[Person{name='小小', age=3}] /** * 2、并集 */ System.out.println(CollectionUtils.union(personList, person1List)); //輸出:[Person{name='小小', age=3}, Person{name='中中', age=4}, Person{name='大大', age=5}] /** * 3、交集 */ System.out.println(CollectionUtils.intersection(personList, person1List)); //輸出:[Person{name='中中', age=4}] /** * 4、交集的補(bǔ)集(析取) */ System.out.println(CollectionUtils.disjunction(personList, person1List)); //輸出:[Person{name='小小', age=3}, Person{name='大大', age=5}] }其它兩種方式就不在測了,因?yàn)槎家粯印?/p>
四、為什么重寫equels方法一定要重寫hashCode方法
1、源碼
其實(shí)上面的Person類我可以只重寫equels方法而不寫hashCode方法,一樣能達(dá)到上面的效果。但為什么還是建議寫上呢?官方的說法是:對象的equals方法被重寫,那么對象的hashCode()也盡量重寫。
重寫equals()方法就必須重寫hashCode()方法的原因,從源頭Object類講起就更好理解了。
先來看Object關(guān)于hashCode()和equals()的源碼:
public native int hashCode();public boolean equals(Object obj) {return (this == obj);}
光從代碼中我們可以知道,hashCode()方法是一個本地native方法,返回的是對象引用中存儲的對象的內(nèi)存地址。而equals方法是利用==來比較的也是對象的內(nèi)存地址。從上邊我們可以看出,hashCode方法和equals方法是一致的。還有最關(guān)鍵的一點(diǎn),我們來看Object類中關(guān)于hashCode()方法的注釋:
在?Java?應(yīng)用程序執(zhí)行期間,在對同一對象多次調(diào)用?hashCode?方法時,必須一致地返回相同的整數(shù),前提是將對象進(jìn)行?equals?比較時所用的信息沒有被修改。
如果根據(jù)?equals(Object)?方法,兩個對象是相等的,那么對這兩個對象中的每個對象調(diào)用?hashCode?方法都必須生成相同的整數(shù)結(jié)果。
如果根據(jù)?equals(java.lang.Object)?方法,兩個對象不相等,那么對這兩個對象中的任一對象上調(diào)用?hashCode?方法不?要求一定生成不同的整數(shù)結(jié)果。 但是,程序員應(yīng)該意識到,為不相等的對象生成不同整數(shù)結(jié)果可以提高哈希表的性能。
整理?: hashCode()和equals()保持一致,如果equals方法返回true,那么兩個對象的hasCode()返回值必須一樣。如果equals方法返回false,hashcode可以不一樣,但是這樣不利于哈希表的性能,一般我們也不要這樣做。
假設(shè)兩個對象,重寫了其equals方法,其相等條件是某屬性相等,就返回true。如果不重寫hashcode方法,其返回的依然是兩個對象的內(nèi)存地址值,必然不相等。這就出現(xiàn)了equals方法相等,但是hashcode不相等的情況。這不符合hashcode的規(guī)則。
2、HashSet和Map集合類型
重寫equals()方法就必須重寫hashCode()方法主要是針對HashSet和Map集合類型,而對于List集合倒沒什么影響。
原因:在向HashSet集合中存入一個元素時,HashSet會調(diào)用該對象(存入對象)的hashCode()方法來得到該對象的hashCode()值,然后根據(jù)該hashCode值決定該對象在HashSet中存儲的位置。簡單的說:HashSet集合判斷兩個元素相等的標(biāo)準(zhǔn)是:兩個對象通過equals()方法比較相等,并且兩個對象的HashCode()方法返回值也相等。如果兩個元素通過equals()方法比較返回true,但是它們的hashCode()方法返回值不同,HashSet會把它們存儲在不同的位置,依然可以添加成功。
這就是問題所在:就是如果你只重寫equals()方法,而不重寫hashCode(),如果equals()為true,而它們的hashCode()方法返回值肯定不一樣,因?yàn)樗鼈兌疾皇峭粚ο笏詢?nèi)存地址肯定不一樣,所以它還是添加成功了,那么其實(shí)你寫的equals()方法根本沒啥軟用。
3、代碼示例
1、People類
重寫equals方法,但并沒有hashCode方法。
public class People { private String name; private Integer age; public People(String name, Integer age) { this.name = name; this.age = age; } /** * 重寫 equals 方法 */ @Override public boolean equals(Object obj) { People u = (People) obj; return this.getName().equals(u.getName()) && (this.age.equals(u.getAge())); } /** * 重寫 toString 方法 */ @Override public String toString() { return "People{" + "name='" + name + '\'' + ", age=" + age + '}'; }}2、實(shí)現(xiàn)類
public static void main(String[] args) { HashSet hashSet = Sets.newHashSet(); People people1 = new People("小小",3); People people2 = new People("中中",4); People people3 = new People("中中",4); People people4 = new People("大大",5); hashSet.add(people1); hashSet.add(people2); hashSet.add(people3); hashSet.add(people4); System.out.println(hashSet); //輸出:[People{name='小小', age=3}, People{name='中中', age=4}, People{name='大大', age=5}, People{name='中中', age=4}] }很明顯,我重寫了equals方法,那么people2和people3的equals應(yīng)該相同,所以不能放入HashSet,但它們的hashCode()方法返回不同,所以導(dǎo)致同樣能放入HashSet。
重點(diǎn):對于Set集合必須要同時重寫這兩個方法,要不然Set的特性就被破壞了。
好文,點(diǎn)個在看吧
總結(jié)
以上是生活随笔為你收集整理的jsonobject转list集合_怎样优雅的操作集合,CollectionUtils工具类正确使用姿势的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java工程师占比_Java工资怎么样?
- 下一篇: flex 下对齐_Flex 布局示例