Java中List集合數(shù)據(jù)修改方式
Java中List集合數(shù)據(jù)修改
先說(shuō)寫這篇文章的原因
我被提供了一個(gè)需求,Excel表格數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫(kù),按照常理而言是很簡(jiǎn)單的,但是這個(gè)需求不那么簡(jiǎn)單,Excel表格里面的字段和數(shù)據(jù)庫(kù)不統(tǒng)一,甚至多與實(shí)體類的屬性數(shù)量,而且要實(shí)現(xiàn)用戶自由選擇Excel表格某列對(duì)應(yīng)數(shù)據(jù)庫(kù)某個(gè)字段,聽到這個(gè)需求我真的是被整懵逼了!??!
先說(shuō)一下我的思路,首先,我個(gè)人感覺不可能將Excel表格全部讀出來(lái)(數(shù)據(jù)類型無(wú)法統(tǒng)一;不知道列數(shù)量;選擇的列比較少的話,效率慢死;)所以我的想法是按照列讀取數(shù)據(jù)(我認(rèn)為Excel數(shù)據(jù)讀取都是要遍歷一遍二維數(shù)組,按行按列于操作Excel效率沒什么區(qū)別)
為了方便,我寫的讀取Excel的工具類返回的是Map類型數(shù)據(jù),map里面放入List集合,通過返回的List集合獲取數(shù)據(jù),這樣我就可以獲取很多類型的數(shù)據(jù)而不必局限于返回值類型
這里是我循環(huán)賦值的語(yǔ)句
public Map<String, Object> importSQL(@RequestBody String c, HttpServletRequest request) throws Exception { ? ? java.util.Map<String, Object> map = new HashMap<>(); ? ? java.util.Map<String, Object> poiMap = new HashMap<>(); ? ? // 對(duì)Excel表格操作的工具類 ? ? PoiExcel poiExcel = new PoiExcel(); ? ? // 保存從Excel讀取出來(lái)信息 ? ? List<Attendance> attList = new ArrayList<Attendance>(); ? ? List<String> string = new ArrayList<String>(); ? ? Attendance att = new Attendance(); ? ? try { ? ? ? ? List<Relation> relationList = new ArrayList<Relation>(); ? ? ? ? JSONObject strj = new JSONObject(c); ? ? ? ? // 獲取讀取Excel表格開始行數(shù) ? ? ? ? int startRow = strj.getInt("start"); ? ? ? ? // 獲取用戶自定義匹配數(shù)據(jù) ? ? ? ? String json = strj.getJSONArray("matchData").toString(); ? ? ? ? // 獲取用戶上傳excel表格保存路徑 ? ? ? ? String filePath = strj.getString("filePath"); ? ? ? ? filePath = "1230.xls"; ? ? ? ? // 將用戶自定義匹配數(shù)據(jù)放入relationList中,便于取值 ? ? ? ? relationList = com.alibaba.fastjson.JSONArray.parseArray(json, Relation.class); ? ? ? ? /** ? ? ? ? ?* 測(cè)試使用 ? ? ? ? ?*/ ? ? ? ? for (int i = 0; i < relationList.size(); i++) { ? ? ? ? ? ? System.out.println("第"+i+"次執(zhí)行"); ? ? ? ? ? ? /** ? ? ? ? ? ? ?* 匹配查詢 filePath:文件名字 startRow:開始查詢行數(shù) ? ? ? ? ? ? ?* relationList.get(i).getColumnNum():查詢列值 ? ? ? ? ? ? ?* 返回map類型數(shù)據(jù),數(shù)據(jù)類型多樣,統(tǒng)一返回值 返回值是List類型數(shù)據(jù),工具類中暫時(shí)只有一個(gè)String類型,測(cè)試使用 ? ? ? ? ? ? ?*/ ? ? ? ? ? ? string = (List<String>) poiExcel.ExcelRead(filePath, startRow, relationList.get(i).getColumnNum()) ? ? ? ? ? ? ? ? ? ? .get("list"); ? ? ? ? ? ? // 初始化集合 ? ? ? ? ? ? if (i == 0) { ? ? ? ? ? ? ? ? for (int a = 0; a < string.size(); a++) { ? ? ? ? ? ? ? ? ? ? attList.add(att); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? if (relationList.get(i).getDescribe().equals("學(xué)號(hào)")) { ? ? ? ? ? ? ? ? System.out.println("學(xué)號(hào)"); ? ? ? ? ? ? ? ? // 循環(huán)賦值 ? ? ? ? ? ? ? ? for (int j = 0; j < string.size(); j++) { ? ? ? ? ? ? ? ? ? ? attList.get(j).setStuid(string.get(j)); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } else if (relationList.get(i).getDescribe().equals("姓名")) { ? ? ? ? ? ? ? ? System.out.println("姓名"); ? ? ? ? ? ? ? ? // 循環(huán)賦值 ? ? ? ? ? ? ? ? for (int j = 0; j < string.size(); j++) { ? ? ? ? ? ? ? ? ? ? attList.get(j).setName(string.get(j)); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? System.out.println("分?jǐn)?shù)"); ? ? ? ? ? ? ? ? for (int j = 0; j < string.size(); j++) { ? ? ? ? ? ? ? ? ? ? attList.get(j).setScore(Integer.parseInt(string.get(j))); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? } catch (Exception e) { ? ? ? ? System.out.println(e); ? ? } ? ? /** ? ? ?* 以上為for循環(huán)遍歷Excel表格數(shù)據(jù),以下為測(cè)試輸出,遍歷是否正確 ? ? ?*/ ? ? for (int x = 0; x < attList.size(); x++) { ? ? ? ? System.out.println("讀取Excel表格信息為:" + attList.get(x).toString()); ? ? } ? ? return map; }
我的想法是先初始化集合,確定集合size和集合屬性,但是突然出現(xiàn)一個(gè)問題就是我遍歷出來(lái)的數(shù)據(jù)在循環(huán)賦值的時(shí)候attList里面的屬性全部變成最新一次的屬性,然后我就debug調(diào)試,發(fā)現(xiàn)每次賦值前面對(duì)應(yīng)的值也都會(huì)更改,當(dāng)時(shí)腦子里面就冒出了一個(gè)念頭:值類型和引用類型傳遞?。?!于是,我做了如下更改:
? ? if (i == 0) { ? ? ? ? for (int a = 0; a < string.size(); a++) { ? ? ? ? ? ? Attendance att = new Attendance(); ? ? ? ? ? ? attList.add(att); ? ? ? ? } ? ? }
將new 對(duì)象這句話放到for循環(huán)里面
運(yùn)行之后值就對(duì)了,唉,開發(fā)經(jīng)驗(yàn)太少,竟然被這種問題困擾了一天
下面是我百度的值類型和引用類型區(qū)別:
引用類型表示你操作的數(shù)據(jù)是同一個(gè),也就是說(shuō)當(dāng)你傳一個(gè)參數(shù)給另一個(gè)方法時(shí),你在另一個(gè)方法中改變這個(gè)變量的值,那么調(diào)用這個(gè)方法是傳入的變量的值也將改變.
值類型表示復(fù)制一個(gè)當(dāng)前變量傳給方法,當(dāng)你在這個(gè)方法中改變這個(gè)變量的值時(shí),最初生命的變量的值不會(huì)變.
引用傳遞:傳的是地址,就是將實(shí)參的地址傳遞給形參,形參改變了,實(shí)參當(dāng)然被改變了,因?yàn)樗麄冎赶蛳嗤牡刂贰?/p>
最后,一定要記住,當(dāng)引用一個(gè)集合的時(shí)候,集合里面有n個(gè)對(duì)象,這個(gè)時(shí)候肯定要new n對(duì)象,否則,這些對(duì)象是引用的同一個(gè)?。。?!
Java中List集合的介紹
List 是什么
JavaList集合是指由JavaList接口以及List接口的所有實(shí)現(xiàn)類組成的集合。
List集合中的元素允許重復(fù),各元素的順序放是對(duì)象插入的順序. 類似Java中的數(shù)組,用戶可通過使用索引(元素在集合中的位置)來(lái)訪問集合中的元素.
1.Java集合介紹
Java集合就像一個(gè)容器,可以存儲(chǔ)任何類型的數(shù)據(jù),也可以結(jié)合泛型來(lái)存儲(chǔ)具體的類型對(duì)象。在程序運(yùn)行時(shí),Java集合可以動(dòng)態(tài)的進(jìn)行擴(kuò)展,隨著元素的增加而擴(kuò)大。在Java中,集合類通常存在于java.util包中。
Java集合主要由2大體系構(gòu)成,分別是Collection體系和Map體系,其中Collection和Map分別是2大體系中的頂層接口。
Collection主要有三個(gè)子接口,分別為L(zhǎng)ist(列表)、Set(集)、Queue(隊(duì)列)。其中,List、Queue中的元素有序可重復(fù),而Set中的元素?zé)o序不可重復(fù)。
List中主要有ArrayList、LinkedList兩個(gè)實(shí)現(xiàn)類;Set中則是有HashSet實(shí)現(xiàn)類;而Queue是在JDK1.5后才出現(xiàn)的新集合,主要以數(shù)組和鏈表兩種形式存在。
Map同屬于java.util包中,是集合的一部分,但與Collection是相互獨(dú)立的,沒有任何關(guān)系。Map中都是以key-value的形式存在,其中key必須唯一,主要有HashMap、HashTable、treeMap三個(gè)實(shí)現(xiàn)類。
2.List介紹
在Collection
中,List集合是有序的,可對(duì)其中每個(gè)元素的插入位置進(jìn)行精確地控制,可以通過索引來(lái)訪問元素,遍歷元素。
在List集合中,我們常用到ArrayList
和LinkedList
這兩個(gè)類
2.1 ArrayList集合
- ArrayList底層通過數(shù)組實(shí)現(xiàn),隨著元素的增加而動(dòng)態(tài)擴(kuò)容。
- ArrayList是Java集合框架中使用最多的一個(gè)類,是一個(gè)數(shù)組隊(duì)列,線程不安全集合。它繼承于AbstractList,實(shí)現(xiàn)了List, RandomAccess, Cloneable, Serializable接口。
- ArrayList實(shí)現(xiàn)List,得到了List集合框架基礎(chǔ)功能;
- ArrayList實(shí)現(xiàn)RandomAccess,獲得了快速隨機(jī)訪問存儲(chǔ)元素的功能,RandomAccess是一個(gè)標(biāo)記接口,沒有任何方法;
- ArrayList實(shí)現(xiàn)Cloneable,得到了clone()方法,可以實(shí)現(xiàn)克隆功能;
- ArrayList實(shí)現(xiàn)Serializable,表示可以被序列化,通過序列化去傳輸,典型的應(yīng)用就是hessian協(xié)議。
ArrayList集合的特點(diǎn):
- 容量不固定,隨著容量的增加而動(dòng)態(tài)擴(kuò)容(閾值基本不會(huì)達(dá)到)
- 有序集合(插入的順序==輸出的順序)
- 插入的元素可以為null
- 增刪改查效率更高(相對(duì)于LinkedList來(lái)說(shuō))
- 線程不安全
ArrayList的底層數(shù)據(jù)結(jié)構(gòu):
2.2 LinkedList集合
- LinkedList底層通過鏈表來(lái)實(shí)現(xiàn),隨著元素的增加不斷向鏈表的后端增加節(jié)點(diǎn)。
- LinkedList是一個(gè)雙向鏈表,每一個(gè)節(jié)點(diǎn)都擁有指向前后節(jié)點(diǎn)的引用。相比于ArrayList來(lái)說(shuō),LinkedList的隨機(jī)訪問效率更低。它繼承AbstractSequentialList,實(shí)現(xiàn)了List, Deque, Cloneable, Serializable接口。
- LinkedList實(shí)現(xiàn)List,得到了List集合框架基礎(chǔ)功能;
- LinkedList實(shí)現(xiàn)Deque,Deque 是一個(gè)雙向隊(duì)列,也就是既可以先入先出,又可以先入后出,說(shuō)簡(jiǎn)單點(diǎn)就是既可以在頭部添加元素,也可以在尾部添加元素;
- LinkedList實(shí)現(xiàn)Cloneable,得到了clone()方法,可以實(shí)現(xiàn)克隆功能;
- LinkedList實(shí)現(xiàn)Serializable,表示可以被序列化,通過序列化去傳輸,典型的應(yīng)用就是hessian協(xié)議。
LinkedList集合的底層數(shù)據(jù)結(jié)構(gòu):
3.List常用方法
A:添加功能 boolean add(E e):向集合中添加一個(gè)元素 void add(int index, E element):在指定位置添加元素 boolean addAll(Collection<? extends E> c):向集合中添加一個(gè)集合的元素。 B:刪除功能 void clear():刪除集合中的所有元素 E remove(int index):根據(jù)指定索引刪除元素,并把刪除的元素返回 boolean remove(Object o):從集合中刪除指定的元素 boolean removeAll(Collection<?> c):從集合中刪除一個(gè)指定的集合元素。 C:修改功能 E set(int index, E element):把指定索引位置的元素修改為指定的值,返回修改前的值。 D:獲取功能 E get(int index):獲取指定位置的元素 Iterator iterator():就是用來(lái)獲取集合中每一個(gè)元素。 E:判斷功能 boolean isEmpty():判斷集合是否為空。 boolean contains(Object o):判斷集合中是否存在指定的元素。 boolean containsAll(Collection<?> c):判斷集合中是否存在指定的一個(gè)集合中的元素。 F:長(zhǎng)度功能 int size():獲取集合中的元素個(gè)數(shù) G:把集合轉(zhuǎn)換成數(shù)組 Object[] toArray():把集合變成數(shù)組。
3.1 ArrayList 基本操作
public class ArrayListTest { public static void main(String[] agrs){ //創(chuàng)建ArrayList集合: List<String> list = new ArrayList<String>(); System.out.println("ArrayList集合初始化容量:"+list.size()); // ArrayList集合初始化容量:0 //添加功能: list.add("Hello"); list.add("world"); list.add(2,"!"); System.out.println("ArrayList當(dāng)前容量:"+list.size()); // ArrayList當(dāng)前容量:3 //修改功能: list.set(0,"my"); list.set(1,"name"); System.out.println("ArrayList當(dāng)前內(nèi)容:"+list.toString()); // ArrayList當(dāng)前內(nèi)容:[my, name, !] //獲取功能: String element = list.get(0); System.out.println(element); // my //迭代器遍歷集合:(ArrayList實(shí)際的跌倒器是Itr對(duì)象) Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ String next = iterator.next(); System.out.println(next); } /** my name ! */ //for循環(huán)迭代集合: for(String str:list){ System.out.println(str); } /** my name ! */ //判斷功能: boolean isEmpty = list.isEmpty(); boolean isContain = list.contains("my"); //長(zhǎng)度功能: int size = list.size(); //把集合轉(zhuǎn)換成數(shù)組: String[] strArray = list.toArray(new String[]{}); //刪除功能: list.remove(0); list.remove("world"); list.clear(); System.out.println("ArrayList當(dāng)前容量:"+list.size()); // ArrayList當(dāng)前容量:0 } }
3.2 LinkedList 基本操作
public class LinkedListTest { public static void main(String[] agrs){ List<String> linkedList = new LinkedList<String>(); System.out.println("LinkedList初始容量:"+linkedList.size()); // LinkedList初始容量:0 //添加功能: linkedList.add("my"); linkedList.add("name"); linkedList.add("is"); linkedList.add("jiaboyan"); System.out.println("LinkedList當(dāng)前容量:"+ linkedList.size()); // LinkedList當(dāng)前容量:4 //修改功能: linkedList.set(0,"hello"); linkedList.set(1,"world"); System.out.println("LinkedList當(dāng)前內(nèi)容:"+ linkedList.toString()); // LinkedList當(dāng)前內(nèi)容:[hello, world, is, jiaboyan] //獲取功能: String element = linkedList.get(0); System.out.println(element); // hello //遍歷集合:(LinkedList實(shí)際的迭代器是ListItr對(duì)象) Iterator<String> iterator = linkedList.iterator(); while(iterator.hasNext()){ String next = iterator.next(); System.out.println(next); } /** hello world is jiaboyan */ //for循環(huán)迭代集合: for(String str:linkedList){ System.out.println(str); } /** hello world is jiaboyan */ //判斷功能: boolean isEmpty = linkedList.isEmpty(); boolean isContains = linkedList.contains("jiaboyan"); //長(zhǎng)度功能: int size = linkedList.size(); //刪除功能: linkedList.remove(0); linkedList.remove("jiaboyan"); linkedList.clear(); System.out.println("LinkedList當(dāng)前容量:" + linkedList.size()); // LinkedList當(dāng)前容量:0 } }
4.ArrayList和LinkedList比較
元素新增性能比較
網(wǎng)上很多說(shuō)的是,在做新增操作時(shí),ArrayList的效率遠(yuǎn)不如LinkedList,因?yàn)锳rraylist底層時(shí)數(shù)組實(shí)現(xiàn)的,在動(dòng)態(tài)擴(kuò)容時(shí),性能會(huì)有所損耗,而LinkedList不存在數(shù)組擴(kuò)容機(jī)制,所以LinkedList的新增性能較好。究竟時(shí)哪個(gè)好呢,我們用實(shí)踐得到結(jié)果。
public class ListTest{ // 迭代次數(shù) public static int ITERATION_NUM = 100000; public static void main(String[] args) { try{ insertPerformanceCompare(); }catch (Exception e){} } //新增性能比較: public static void insertPerformanceCompare() throws InterruptedException { Thread.sleep(5000); long start = System.nanoTime(); List<Integer> linkedList = new LinkedList<Integer>(); for (int x = 0; x < ITERATION_NUM; x++) { linkedList.add(x); } long end = System.nanoTime(); System.out.println("LinkedList獲取測(cè)試開始 " + (end - start)); start = System.nanoTime(); List<Integer> arrayList = new ArrayList<Integer>(); for (int x = 0; x < ITERATION_NUM; x++) { arrayList.add(x); } end = System.nanoTime(); System.out.println("ArrayList獲取測(cè)試開始 " + (end - start)); } }
測(cè)試結(jié)果:
第一次:
LinkedList新增測(cè)試開始 10873720
ArrayList新增測(cè)試開始 5535277
第二次:
LinkedList新增測(cè)試開始 13097503
ArrayList新增測(cè)試開始 6046139
第三次:
LinkedList新增測(cè)試開始 12004669
ArrayList新增測(cè)試開始 6509783
結(jié)果與預(yù)想的有些不太一樣,ArrayList的新增性能并不低。
原因:
可能是經(jīng)過JDK近幾年的更新發(fā)展,對(duì)于數(shù)組復(fù)制的實(shí)現(xiàn)進(jìn)行了優(yōu)化,以至于ArrayList的性能也得到了提高。
元素獲取比較
由于LinkedList是鏈表結(jié)構(gòu),沒有角標(biāo)的概念,沒有實(shí)現(xiàn)RandomAccess接口,不具備隨機(jī)元素訪問功能,所以在get方面表現(xiàn)的差強(qiáng)人意,ArrayList再一次完勝。
public class ListTest { //迭代次數(shù),集合大?。? public static int ITERATION_NUM = 100000; public static void main(String[] agrs) { try{ getPerformanceCompare(); }catch (Exception e){} } //獲取性能比較: public static void getPerformanceCompare()throws InterruptedException { Thread.sleep(5000); //填充ArrayList集合: List<Integer> arrayList = new ArrayList<Integer>(); for (int x = 0; x < ITERATION_NUM; x++) { arrayList.add(x); } //填充LinkedList集合: List<Integer> linkedList = new LinkedList<Integer>(); for (int x = 0; x < ITERATION_NUM; x++) { linkedList.add(x); } //創(chuàng)建隨機(jī)數(shù)對(duì)象: Random random = new Random(); long start = System.nanoTime(); for (int x = 0; x < ITERATION_NUM; x++) { int j = random.nextInt(x + 1); int k = linkedList.get(j); } long end = System.nanoTime(); System.out.println("LinkedList獲取測(cè)試開始 " + (end - start)); start = System.nanoTime(); for (int x = 0; x < ITERATION_NUM; x++) { int j = random.nextInt(x + 1); int k = arrayList.get(j); } end = System.nanoTime(); System.out.println("ArrayList獲取測(cè)試開始 " + (end - start)); } }
測(cè)試結(jié)果:
第一次:
LinkedList獲取測(cè)試開始 8190063123
ArrayList獲取測(cè)試開始 8590205
第二次:
LinkedList獲取測(cè)試開始 8100623160
ArrayList獲取測(cè)試開始 11948919
第三次:
LinkedList獲取測(cè)試開始 8237722833
ArrayList獲取測(cè)試開始 6333427
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳談@Cacheable不起作用的原因:bean未序列化問題
這篇文章主要介紹了@Cacheable不起作用的原因:bean未序列化問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01簡(jiǎn)單介紹Java網(wǎng)絡(luò)編程中的HTTP請(qǐng)求
這篇文章主要介紹了簡(jiǎn)單介紹Java網(wǎng)絡(luò)編程中的HTTP請(qǐng)求,需要的朋友可以參考下2015-09-09SpringBoot內(nèi)部調(diào)用事務(wù)不起作用問題的解決方案
這篇文章主要介紹了SpringBoot事務(wù)不起作用問題的解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10Java遠(yuǎn)程連接Linux服務(wù)器并執(zhí)行命令及上傳文件功能
這篇文章主要介紹了Java遠(yuǎn)程連接Linux服務(wù)器并執(zhí)行命令及上傳文件功能,本文是小編整理的代碼筆記,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-05-05關(guān)于springcloud集成nacos遇到的問題
這篇文章主要介紹了關(guān)于springcloud集成nacos遇到的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01