在 Java 中,遍歷對象的方式主要取決于對象的類型和數據結構。以下是幾種常見的遍歷方式,以及它們的效率比較:
-
普通的 for 循環:
- 效率:高。使用普通的 for 循環可以直接根據索引來訪問元素,適用于數組和實現了
RandomAccess
接口的列表,例如ArrayList
。 - 適用對象: 數組、
ArrayList
等支持隨機訪問的列表。
ArrayList<String> list = new ArrayList<>(); // 添加元素到 list 中 for (int i = 0; i < list.size(); i++) {String element = list.get(i);// 處理元素 }
- 效率:高。使用普通的 for 循環可以直接根據索引來訪問元素,適用于數組和實現了
-
增強型 for 循環(foreach 循環):
- 效率:一般。增強型 for 循環適用于所有實現了
Iterable
接口的集合類,它會通過迭代器(iterator)遍歷集合元素。 - 適用對象: 所有實現了
Iterable
接口的集合類。
ArrayList<String> list = new ArrayList<>(); // 添加元素到 list 中 for (String element : list) {// 處理元素 }
- 效率:一般。增強型 for 循環適用于所有實現了
-
迭代器(Iterator):
- 效率:一般。使用
Iterator
顯式地控制遍歷過程,適合所有實現了Iterable
接口的集合類。 - 適用對象: 所有實現了
Iterable
接口的集合類。
ArrayList<String> list = new ArrayList<>(); // 添加元素到 list 中 Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) {String element = iterator.next();// 處理元素 }
- 效率:一般。使用
-
Java 8 中的 Stream API:
- 效率:高(對于并行流,效率更高)。Stream API 提供了豐富的函數式操作,可以處理大量數據,并支持并行處理。
- 適用對象: 所有實現了
Iterable
接口的集合類。
ArrayList<String> list = new ArrayList<>(); // 添加元素到 list 中 list.stream().forEach(element -> {// 處理元素 });
-
Java 8 中的并行流:
- 效率:非常高。對于大數據集合,在多核處理器上并行處理能顯著提高性能。
- 適用對象: 所有實現了
Iterable
接口的集合類。
ArrayList<String> list = new ArrayList<>(); // 添加元素到 list 中 list.parallelStream().forEach(element -> {// 處理元素 });
綜上所述,選擇合適的遍歷方式應該基于具體的數據結構和操作需求。對于小型數據集合,普通的 for 循環可能是最高效的選擇;對于大數據集合或需要并行處理的情況,使用 Stream API 或并行流則更合適。
上述內容我是從ai里面查出來的,但是我頭鐵我不信,我要自己試試,然后我開始了嘗試。
import com.test.testmq.service.TestService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.annotation.Resource;@Controller
public class TestController {@ResourceTestService testService;@RequestMapping("/helloword")@ResponseBodypublic String hello() {return "Hello Word";}@RequestMapping("/testinsert")@ResponseBodypublic String testinsert() {testService.testinsert();return "Hello Word";}@RequestMapping("/testfor")@ResponseBodypublic String testfor() {testService.testfor();return "Hello Word";}@RequestMapping("/testforeach")@ResponseBodypublic String testforeach() {testService.testforeach();return "Hello Word";}@RequestMapping("/testIterator")@ResponseBodypublic String testIterator() {testService.testIterator();return "Hello Word";}@RequestMapping("/testStream")@ResponseBodypublic String testStream() {testService.testStream();return "Hello Word";}@RequestMapping("/testparallelStream")@ResponseBodypublic String testparallelStream() {testService.testparallelStream();return "Hello Word";}}
這是對應的controller層
public interface TestService {public void testfor();public void testinsert();public void testforeach();public void testIterator();public void testStream();public void testparallelStream();}
這是service層
import com.test.testmq.entity.LeaderList;
import com.test.testmq.mapper.TestMapper;
import com.test.testmq.service.TestService;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;@Slf4j
@Service
public class TestServiceImpl implements TestService {@ResourceTestMapper testMapper;@Overridepublic void testinsert() {long start = System.currentTimeMillis();List<LeaderList> list = new ArrayList<>();for (int i = 0; i < 90000; i++) {LeaderList leaderList = new LeaderList();leaderList.setLeaderNo(i+"");leaderList.setLeaderName("張三");list.add(leaderList);}testMapper.insert(list);long end = System.currentTimeMillis();log.error(String.valueOf(end-start));}@Overridepublic void testforeach() {long start = System.currentTimeMillis();List<LeaderList> list = testMapper.list();List<LeaderList> listret = new ArrayList<>();for (LeaderList leaderList : list) {String leaderNo = leaderList.getLeaderNo();if((Integer.valueOf(leaderNo))%2 == 1){listret.add(leaderList);}}long end = System.currentTimeMillis();log.error(String.valueOf(end-start)+"end");log.error(listret.size()+"size");}@Overridepublic void testIterator() {long start = System.currentTimeMillis();List<LeaderList> list = testMapper.list();List<LeaderList> listret = new ArrayList<>();Iterator<LeaderList> iterator = list.iterator();while (iterator.hasNext()){LeaderList next = iterator.next();String leaderNo = next.getLeaderNo();if((Integer.valueOf(leaderNo))%2 == 1){listret.add(next);}}long end = System.currentTimeMillis();log.error(String.valueOf(end-start)+"end");log.error(listret.size()+"size");}@Overridepublic void testStream() {long start = System.currentTimeMillis();List<LeaderList> list = testMapper.list();List<LeaderList> listret = new ArrayList<>();list.stream().forEach(element -> {String leaderNo = element.getLeaderNo();if((Integer.valueOf(leaderNo))%2 == 1){listret.add(element);}// 處理元素});long end = System.currentTimeMillis();log.error(String.valueOf(end-start)+"end");log.error(listret.size()+"size");}@Overridepublic void testparallelStream() {long start = System.currentTimeMillis();List<LeaderList> list = testMapper.list();List<LeaderList> listret = new ArrayList<>();list.parallelStream().forEach(element -> {String leaderNo = element.getLeaderNo();if((Integer.valueOf(leaderNo))%2 == 1){listret.add(element);}// 處理元素});long end = System.currentTimeMillis();log.error(String.valueOf(end-start)+"end");log.error(listret.size()+"size");}/*** 用處就是將所有的偶數查詢出來*/@Overridepublic void testfor() {long start = System.currentTimeMillis();List<LeaderList> list = testMapper.list();List<LeaderList> listret = new ArrayList<>();for (int i = 0; i < list.size(); i++) {LeaderList leaderList = list.get(i);String leaderNo = leaderList.getLeaderNo();if((Integer.valueOf(leaderNo))%2 == 1){listret.add(leaderList);}}long end = System.currentTimeMillis();log.error(String.valueOf(end-start)+"end");log.error(listret.size()+"size");}
}
大概就是一個插入的接口,還有就是幾種的對比方法,分別是for,foreach,Iterator,Stream,parallelStream
然后插入的數據量大概是9730000
大概是千萬不到,插入的時候我插入的是兩個字段,實體應該是10多個字段,然后我就一遍一遍的執行看結果,我這邊的出來的結果。
1,for 425615end
2,foreach 403837end
3,Iterator 363512end
4,Stream 331943end
5,parallelStream 直接報錯了
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1d45091]
19:31:51.865 ERROR --- [http-nio-4399-exec-4] o.a.c.c.C.[.[localhost].[/].[dispatcherServlet] :Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ArrayIndexOutOfBoundsException] with root cause
java.lang.ArrayIndexOutOfBoundsException: 31618at java.util.ArrayList.add(ArrayList.java:465)at com.test.testmq.service.impl.TestServiceImpl.lambda$testparallelStream$1(TestServiceImpl.java:100)at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1067)at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1703)at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:172)
雖然這個報錯我我沒去查,但是我認為,是數據量超過了parallelStream 底層的限制,盲猜底層應該是通過數組來控制,當然期間我在mysql也遇到了,批量插入的時候mysql提示我數據量太大了,然后我降到了90000條插入一次,因為mysql 的包有一個大小限制,報錯信息沒有粘出來,因為報錯太明顯了,不需要粘出來,基本上一看就懂了,根據我的推測大概是在不考慮位數的情況下,Stream 在數據量大的時候確實是最快的,其次就是Iterator ,其次就是foreach ,最后就是for ,但是尷尬的是,如果你需要找到第幾個的情況下,還是需要for,因為他確實可以找到第幾個,當然Stream 應該也可以吧,parallelStream 的效率我盲猜應該是比Stream 快,但是數據量太大的情況下可能會收到了影響。