中國建設教育協(xié)會官方網(wǎng)站查百度搜索指數(shù)入口
? ? ? ?
目錄
1、接口說明
2、鍵值生成規(guī)則
3、組件創(chuàng)建規(guī)則
3.1、首次渲染
3.2、非首次渲染
4、使用場景
4.1、數(shù)據(jù)源不變
4.2、數(shù)據(jù)源組項發(fā)生變化
?4.3、數(shù)據(jù)源數(shù)組項子屬性變化
5、反例?
5.1、渲染結(jié)果非預期
5.2、渲染性能降低
Android開發(fā)中我們有ListView組件、GridView組件、RecyclerView組件,這些組件可以為我們創(chuàng)建一個列表;在鴻蒙開發(fā)中,則不一樣,它沒有類似Android中的組件,但是卻提供了循環(huán)渲染機制ForEach接口幫助我們渲染一個列表,本節(jié)主要介紹該主題。
????????ForEach接口基于數(shù)組類型數(shù)據(jù)來進行循環(huán)渲染,需要與容器組件配合使用,且接口返回的組件應當是允許包含在ForEach父容器組件中的子組件。例如,ListItem組件要求ForEach的父容器組件必須為List組件。
1、接口說明
? ? ? ? ForEach接口定義如下:
ForEach(arr: Array,itemGenerator: (item: any, index?: number) => void,keyGenerator?: (item: any, index?: number): string => string
)
- arr?
數(shù)據(jù)源,為Array類型的數(shù)組。
說明:
- 可以設置為空數(shù)組,此時不會創(chuàng)建子組件。
- 可以設置返回值為數(shù)組類型的函數(shù),例如arr.slice(1, 3),但設置的函數(shù)不應改變包括數(shù)組本身在內(nèi)的任何狀態(tài)變量,例如不應使用Array.splice(),Array.sort()或Array.reverse()這些會改變原數(shù)組的函數(shù)。
- itemGenerator
組件生成函數(shù)。
- 為數(shù)組中的每個元素創(chuàng)建對應的組件。
- item參數(shù):arr數(shù)組中的數(shù)據(jù)項。
- index參數(shù)(可選):arr數(shù)組中的數(shù)據(jù)項索引。
說明:
- 組件的類型必須是ForEach的父容器所允許的。例如,ListItem組件要求ForEach的父容器組件必須為List組件。
- ForEach的itemGenerator函數(shù)可以包含if/else條件渲染邏輯。另外,也可以在if/else條件渲染語句中使用ForEach組件。
- 在初始化渲染時,ForEach會加載數(shù)據(jù)源的所有數(shù)據(jù),并為每個數(shù)據(jù)項創(chuàng)建對應的組件,然后將其掛載到渲染樹上。如果數(shù)據(jù)源非常大或有特定的性能需求,建議使用LazyForEach組件。
2、鍵值生成規(guī)則
????????在ForEach循環(huán)渲染過程中,系統(tǒng)會為每個數(shù)組元素生成一個唯一且持久的鍵值,用于標識對應的組件。當這個鍵值變化時,ArkUI框架將視為該數(shù)組元素已被替換或修改,并會基于新的鍵值創(chuàng)建一個新的組件。
????????ForEach提供了一個名為keyGenerator的參數(shù),這是一個函數(shù),開發(fā)者可以通過它自定義鍵值的生成規(guī)則。如果開發(fā)者沒有定義keyGenerator函數(shù),則ArkUI框架會使用默認的鍵值生成函數(shù),即(item: any, index: number) => { return index + '__' + JSON.stringify(item); }。
????????ArkUI框架對于ForEach的鍵值生成有一套特定的判斷規(guī)則,這主要與itemGenerator函數(shù)的第二個參數(shù)index以及keyGenerator函數(shù)的返回值有關??偟膩碚f,只有當開發(fā)者在itemGenerator函數(shù)中聲明了index參數(shù),并且自定義的keyGenerator函數(shù)返回值中不包含index參數(shù)時,ArkUI框架才會在開發(fā)者自定義的keyGenerator函數(shù)返回值前添加index參數(shù),作為最終的鍵值。在其他情況下,系統(tǒng)將直接使用開發(fā)者自定義的keyGenerator函數(shù)返回值作為最終的鍵值。如果keyGenerator函數(shù)未定義,系統(tǒng)將使用上述默認的鍵值生成函數(shù)。具體的鍵值生成規(guī)則判斷邏輯如下圖所示。
ArkUI框架會對重復的鍵值發(fā)出警告。在UI更新的場景下,如果出現(xiàn)重復的鍵值,框架可能無法正常工作,具體請參見渲染結(jié)果非預期?
3、組件創(chuàng)建規(guī)則
????????在確定鍵值生成規(guī)則后,ForEach的第二個參數(shù)itemGenerator函數(shù)會根據(jù)鍵值生成規(guī)則為數(shù)據(jù)源的每個數(shù)組項創(chuàng)建組件。組件的創(chuàng)建包括兩種情況:Foreach首次渲染和Foreach非首次渲染。
3.1、首次渲染
????????在ForEach首次渲染時,會根據(jù)前述鍵值生成規(guī)則為數(shù)據(jù)源的每個數(shù)組項生成唯一鍵值,并創(chuàng)建相應的組件。
@Entry
@Component
struct ForeachRenderDemo1Page {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Row() {Column() {ForEach(this.simpleList, (item: string) => {ForeachDemo1ChildItem({ item: item })}, (item: string) => item)}.width('100%').height('100%')}.height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ForeachDemo1ChildItem {@Prop item: string;build() {Text(this.item).fontSize(50)}
}
? ? ? ? 運行結(jié)果如下:

ForEach數(shù)據(jù)源不存在相同值案例首次渲染運行效果圖
????????在上述代碼中,鍵值生成規(guī)則是keyGenerator函數(shù)的返回值item。在ForEach渲染循環(huán)時,為數(shù)據(jù)源數(shù)組項依次生成鍵值one、two和three,并創(chuàng)建對應的ChildItem組件渲染到界面上。
????????當不同數(shù)組項按照鍵值生成規(guī)則生成的鍵值相同時,框架的行為是未定義的。例如,在以下代碼中,ForEach渲染相同的數(shù)據(jù)項two時,只創(chuàng)建了一個ChildItem組件,而沒有創(chuàng)建多個具有相同鍵值的組件。
@Entry
@Component
struct ForeachRenderDemo2Page {@State simpleList: Array<string> = ['one', 'two', 'two', 'three'];build() {Row() {Column() {ForEach(this.simpleList, (item: string) => {ForeachRenderDemo2ChildItem({ item: item })}, (item: string) => item)}.width('100%').height('100%')}.height('100%')}
}@Component
struct ForeachRenderDemo2ChildItem {@Prop item: string;build() {Text(this.item).fontSize(50)}
}
? ? ? ? 運行結(jié)果如下:

????????在該示例中,最終鍵值生成規(guī)則為item。當ForEach遍歷數(shù)據(jù)源simpleList,遍歷到索引為1的two時,按照最終鍵值生成規(guī)則生成鍵值為two的組件并進行標記。當遍歷到索引為2的two時,按照最終鍵值生成規(guī)則當前項的鍵值也為two,此時不再創(chuàng)建新的組件。
3.2、非首次渲染
????????在ForEach組件進行非首次渲染時,它會檢查新生成的鍵值是否在上次渲染中已經(jīng)存在。如果鍵值不存在,則會創(chuàng)建一個新的組件;如果鍵值存在,則不會創(chuàng)建新的組件,而是直接渲染該鍵值所對應的組件。例如,在以下的代碼示例中,通過點擊事件修改了數(shù)組的第三項值為"new three",這將觸發(fā)ForEach組件進行非首次渲染。?
@Entry
@Component
struct ForeachRenderDemo3Page {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Row() {Column() {Text('點擊修改第3個數(shù)組項的值').fontSize(24).fontColor(Color.Red).onClick(() => {this.simpleList[2] = 'new three';})ForEach(this.simpleList, (item: string) => {ForeachRenderDemo3ChildItem({ item: item }).margin({ top: 20 })}, (item: string) => item)}.justifyContent(FlexAlign.Center).width('100%').height('100%')}.height('100%')}
}@Component
struct ForeachRenderDemo3ChildItem {@Prop item: string;build() {Text(this.item).fontSize(30)}
}
????????運行效果如下圖:
????????從本例可以看出@State 能夠監(jiān)聽到簡單數(shù)據(jù)類型數(shù)組數(shù)據(jù)源 simpleList 數(shù)組項的變化。
- 當 simpleList 數(shù)組項發(fā)生變化時,會觸發(fā) ForEach 進行重新渲染。
- ForEach 遍歷新的數(shù)據(jù)源 ['one', 'two', 'new three'],并生成對應的鍵值one、two和new three。
- 其中,鍵值one和two在上次渲染中已經(jīng)存在,所以 ForEach 復用了對應的組件并進行了渲染。對于第三個數(shù)組項 "new three",由于其通過鍵值生成規(guī)則 item 生成的鍵值new three在上次渲染中不存在,因此 ForEach 為該數(shù)組項創(chuàng)建了一個新的組件。
4、使用場景
????????ForEach組件在開發(fā)過程中的主要應用場景包括:數(shù)據(jù)源不變、數(shù)據(jù)源數(shù)組項發(fā)生變化(如插入、刪除操作)、數(shù)據(jù)源數(shù)組項子屬性變化。
4.1、數(shù)據(jù)源不變
????????在數(shù)據(jù)源保持不變的場景中,數(shù)據(jù)源可以直接采用基本數(shù)據(jù)類型。例如,在頁面加載狀態(tài)時,可以使用骨架屏列表進行渲染展示。
@Entry
@Component
struct ForeachRenderDemo4Page {@State simpleList: Array<number> = [1, 2, 3, 4, 5];build() {Column() {ForEach(this.simpleList, (item: string) => {ArticleSkeletonView().margin({ top: 20 })}, (item: string) => item)}.padding(20).width('100%').height('100%')}
}@Builder
function textArea(width: number | Resource | string = '100%', height: number | Resource | string = '100%') {Row().width(width).height(height).backgroundColor('#FFF2F3F4')
}@Component
struct ArticleSkeletonView {build() {Row() {Column() {textArea(80, 80)}.margin({ right: 20 })Column() {textArea('60%', 20)textArea('50%', 20)}.alignItems(HorizontalAlign.Start).justifyContent(FlexAlign.SpaceAround).height('100%')}.padding(20).borderRadius(12).backgroundColor('#FFECECEC').height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)}
}
運行結(jié)果如下:
????????在本示例中,采用數(shù)據(jù)項item作為鍵值生成規(guī)則,由于數(shù)據(jù)源simpleList的數(shù)組項各不相同,因此能夠保證鍵值的唯一性。?
4.2、數(shù)據(jù)源組項發(fā)生變化
????????在數(shù)據(jù)源數(shù)組項發(fā)生變化的場景下,例如進行數(shù)組插入、刪除操作或者數(shù)組項索引位置發(fā)生交換時,數(shù)據(jù)源應為對象數(shù)組類型,并使用對象的唯一ID作為最終鍵值。例如,當在頁面上通過手勢上滑加載下一頁數(shù)據(jù)時,會在數(shù)據(jù)源數(shù)組尾部新增新獲取的數(shù)據(jù)項,從而使得數(shù)據(jù)源數(shù)組長度增大。
import { Article } from './bean/Article';@Entry
@Component
struct ForeachRenderDemo5Page {@State isListReachEnd: boolean = false;@State articleList: Array<Article> = [new Article('001', '第1篇文章', '文章簡介內(nèi)容'),new Article('002', '第2篇文章', '文章簡介內(nèi)容'),new Article('003', '第3篇文章', '文章簡介內(nèi)容'),new Article('004', '第4篇文章', '文章簡介內(nèi)容'),new Article('005', '第5篇文章', '文章簡介內(nèi)容'),new Article('006', '第6篇文章', '文章簡介內(nèi)容'),new Article('007', '第7篇文章', '文章簡介內(nèi)容'),new Article('008', '第8篇文章', '文章簡介內(nèi)容'),new Article('009', '第9篇文章', '文章簡介內(nèi)容'),new Article('010', '第10篇文章', '文章簡介內(nèi)容')]private count: number = 11;loadMoreArticles() {console.log('loadMoreArticles')this.articleList.push(new Article(`0${++this.count}`, `加載的第${this.count}篇新文章`, `第${this.count}篇文章簡介內(nèi)容`));}build() {Column({ space: 5 }) {List() {ForEach(this.articleList, (item: Article) => {ListItem() {ForeachRenderDemo5ArticleCard({ article: item }).margin({ top: 20 })}}, (item: Article) => item.id)}.onReachEnd(() => {console.log('onReachEnd')this.isListReachEnd = true;}).parallelGesture(PanGesture({ direction: PanDirection.Up, distance: 80 }).onActionStart(() => {console.log('onActionStart')if (this.isListReachEnd) {this.loadMoreArticles();this.isListReachEnd = false;}})).padding(20).scrollBar(BarState.Off).height('100%').height('100%')}.width('100%').height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ForeachRenderDemo5ArticleCard {@Prop article: Article;build() {Row() {Image($r('app.media.icon')).width(80).height(80).margin({ right: 20 })Column() {Text(this.article.title).fontSize(20).margin({ bottom: 8 })Text(this.article.brief).fontSize(16).fontColor(Color.Gray).margin({ bottom: 8 })}.alignItems(HorizontalAlign.Start).width('80%').height('100%')}.padding(20).borderRadius(12).backgroundColor('#FFECECEC').height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)}
}
運行結(jié)果如下:
????????在本示例中,ArticleCard組件作為ArticleListView組件的子組件,通過@Prop裝飾器接收一個Article對象,用于渲染文章卡片。
- 當列表滾動到底部時,如果手勢滑動距離超過指定的80,將觸發(fā)loadMoreArticle()函數(shù)。此函數(shù)會在articleList數(shù)據(jù)源的尾部添加一個新的數(shù)據(jù)項,從而增加數(shù)據(jù)源的長度。
- 數(shù)據(jù)源被@State裝飾器修飾,ArkUI框架能夠感知到數(shù)據(jù)源長度的變化,并觸發(fā)ForEach進行重新渲染
?4.3、數(shù)據(jù)源數(shù)組項子屬性變化
????????當數(shù)據(jù)源的數(shù)組項為對象數(shù)據(jù)類型,并且只修改某個數(shù)組項的屬性值時,由于數(shù)據(jù)源為復雜數(shù)據(jù)類型,ArkUI框架無法監(jiān)聽到@State裝飾器修飾的數(shù)據(jù)源數(shù)組項的屬性變化,從而無法觸發(fā)ForEach的重新渲染。為實現(xiàn)ForEach重新渲染,需要結(jié)合@Observed和@ObjectLink裝飾器使用。例如,在文章列表卡片上點擊“點贊”按鈕,從而修改文章的點贊數(shù)量。
import { Article } from './bean/Article';@Entry
@Component
struct ForeachRenderDemo6Page {@State articleList: Array<Article> = [new Article('001', '第0篇文章', '文章簡介內(nèi)容'),new Article('002', '第1篇文章', '文章簡介內(nèi)容'),new Article('003', '第2篇文章', '文章簡介內(nèi)容'),new Article('004', '第4篇文章', '文章簡介內(nèi)容'),new Article('005', '第5篇文章', '文章簡介內(nèi)容'),new Article('006', '第6篇文章', '文章簡介內(nèi)容'),];build() {List() {ForEach(this.articleList, (item: Article) => {ListItem() {ForeachRenderDemo6ArticleCard({article: item}).margin({ top: 20 })}}, (item: Article) => item.id)}.padding(20).scrollBar(BarState.Off).backgroundColor(0xF1F3F5)}
}@Component
struct ForeachRenderDemo6ArticleCard {@ObjectLink article: Article;handleLiked() {this.article.isLiked = !this.article.isLiked;this.article.likesCount = this.article.isLiked ? this.article.likesCount + 1 : this.article.likesCount - 1;}build() {Row() {Image($r('app.media.icon')).width(80).height(80).margin({ right: 20 })Column() {Text(this.article.title).fontSize(20).margin({ bottom: 8 })Text(this.article.brief).fontSize(16).fontColor(Color.Gray).margin({ bottom: 8 })Row() {Image(this.article.isLiked ? $r('app.media.icon_approve_checked') : $r('app.media.icon_approve_normal')).width(24).height(24).margin({ right: 8 })Text(this.article.likesCount.toString()).fontSize(16)}.onClick(() => this.handleLiked()).justifyContent(FlexAlign.Center)}.alignItems(HorizontalAlign.Start).width('80%').height('100%')}.padding(20).borderRadius(12).backgroundColor('#FFECECEC').height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)}
}
運行結(jié)果如下:
????????在本示例中,Article類被@Observed裝飾器修飾。父組件ArticleListView傳入Article對象實例給子組件ArticleCard,子組件使用@ObjectLink裝飾器接收該實例。
- 當點擊第1個文章卡片上的點贊圖標時,會觸發(fā)ArticleCard組件的handleLiked函數(shù)。該函數(shù)修改第1個卡片對應組件里article實例的isLiked和likesCount屬性值。
- 由于子組件ArticleCard中的article使用了@ObjectLink裝飾器,父子組件共享同一份article數(shù)據(jù)。因此,父組件中articleList的第1個數(shù)組項的isLiked和likedCounts數(shù)值也會同步修改。
- 當父組件監(jiān)聽到數(shù)據(jù)源數(shù)組項屬性值變化時,會觸發(fā)ForEach重新渲染。
- 在此處,ForEach鍵值生成規(guī)則為數(shù)組項的id屬性值。當ForEach遍歷新數(shù)據(jù)源時,數(shù)組項的id均沒有變化,不會新建組件。
- 渲染第1個數(shù)組項對應的ArticleCard組件時,讀取到的isLiked和likesCount為修改后的新值。
- 盡量避免在最終的鍵值生成規(guī)則中包含數(shù)據(jù)項索引index,以防止出現(xiàn)渲染結(jié)果非預期和渲染性能降低。如果業(yè)務確實需要使用index,例如列表需要通過index進行條件渲染,開發(fā)者需要接受ForEach在改變數(shù)據(jù)源后重新創(chuàng)建組件所帶來的性能損耗。
- 為滿足鍵值的唯一性,對于對象數(shù)據(jù)類型,建議使用對象數(shù)據(jù)中的唯一id作為鍵值。
- 基本數(shù)據(jù)類型的數(shù)據(jù)項沒有唯一ID屬性。如果使用基本數(shù)據(jù)類型本身作為鍵值,必須確保數(shù)組項無重復。因此,對于數(shù)據(jù)源會發(fā)生變化的場景,建議將基本數(shù)據(jù)類型數(shù)組轉(zhuǎn)化為具備唯一ID屬性的對象數(shù)據(jù)類型數(shù)組,再使用ID屬性作為鍵值生成規(guī)則。
5、反例?
????????開發(fā)者在使用ForEach的過程中,若對于鍵值生成規(guī)則的理解不夠充分,可能會出現(xiàn)錯誤的使用方式。錯誤使用一方面會導致功能層面問題,例如渲染結(jié)果非預期,另一方面會導致性能層面問題,例如渲染性能降低。
5.1、渲染結(jié)果非預期
????????在本示例中,通過設置ForEach的第三個參數(shù)KeyGenerator函數(shù),自定義鍵值生成規(guī)則為數(shù)據(jù)源的索引index的字符串類型值。當點擊父組件Parent中“在第1項后插入新項”文本組件后,界面會出現(xiàn)非預期的結(jié)果。
@Entry
@Component
struct ForeachRenderDemo7Page {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Column() {Button() {Text('在第1項后插入新項').fontSize(30)}.onClick(() => {this.simpleList.splice(1, 0, 'new item');})ForEach(this.simpleList, (item: string) => {ChildItem({ item: item })}, (item: string, index: number) => index.toString())}.justifyContent(FlexAlign.Center).width('100%').height('100%')}
}@Component
struct ChildItem {@Prop item: string;build() {Text(this.item).fontSize(30)}
}
運行結(jié)果如下:
????????ForEach在首次渲染時,創(chuàng)建的鍵值依次為"0"、"1"、"2"。
????????插入新項后,數(shù)據(jù)源simpleList變?yōu)閇'one', 'new item', 'two', 'three'],框架監(jiān)聽到@State裝飾的數(shù)據(jù)源長度變化觸發(fā)ForEach重新渲染。
????????ForEach依次遍歷新數(shù)據(jù)源,遍歷數(shù)據(jù)項"one"時生成鍵值"0",存在相同鍵值,因此不創(chuàng)建新組件。繼續(xù)遍歷數(shù)據(jù)項"new item"時生成鍵值"1",存在相同鍵值,因此不創(chuàng)建新組件。繼續(xù)遍歷數(shù)據(jù)項"two"生成鍵值"2",存在相同鍵值,因此不創(chuàng)建新組件。最后遍歷數(shù)據(jù)項"three"時生成鍵值"3",不存在相同鍵值,創(chuàng)建內(nèi)容為"three"的新組件并渲染。
????????從以上可以看出,當最終鍵值生成規(guī)則包含index時,期望的界面渲染結(jié)果為['one', 'new item', 'two', 'three'],而實際的渲染結(jié)果為['one', 'two', 'three', 'three'],渲染結(jié)果不符合開發(fā)者預期。因此,開發(fā)者在使用ForEach時應盡量避免最終鍵值生成規(guī)則中包含index。
5.2、渲染性能降低
在本示例中,ForEach的第三個參數(shù)KeyGenerator函數(shù)處于缺省狀態(tài)。根據(jù)上述鍵值生成規(guī)則,此例使用框架默認的鍵值生成規(guī)則,即最終鍵值為字符串index + '__' + JSON.stringify(item)。當點擊“在第1項后插入新項”文本組件后,ForEach將需要為第2個數(shù)組項以及其后的所有項重新創(chuàng)建組件。
@Entry
@Component
struct ForeachRenderDemo8Page {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Column() {Button() {Text('在第1項后插入新項').fontSize(30)}.onClick(() => {this.simpleList.splice(1, 0, 'new item');console.log(`[onClick]: simpleList is ${JSON.stringify(this.simpleList)}`);})ForEach(this.simpleList, (item: string) => {ForeachRenderDemo8ChildItem({ item: item })})}.justifyContent(FlexAlign.Center).width('100%').height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ForeachRenderDemo8ChildItem {@Prop item: string;aboutToAppear() {console.log(`[aboutToAppear]: item is ${this.item}`);}build() {Text(this.item).fontSize(50)}
}
? ? ? ? ?運行結(jié)果如下:
? ? ? ? ?點擊插入新項,ide打印如下日志:
????????插入新項后,ForEach為new item、 two、 three三個數(shù)組項創(chuàng)建了對應的組件ChildItem,并執(zhí)行了組件的aboutToAppear()生命周期函數(shù)。這是因為:
- 在ForEach首次渲染時,創(chuàng)建的鍵值依次為0__one、1__two、2__three。
- 插入新項后,數(shù)據(jù)源simpleList變?yōu)閇'one', 'new item', 'two', 'three'],ArkUI框架監(jiān)聽到@State裝飾的數(shù)據(jù)源長度變化觸發(fā)ForEach重新渲染。
- ForEach依次遍歷新數(shù)據(jù)源,遍歷數(shù)據(jù)項one時生成鍵值0__one,鍵值已存在,因此不創(chuàng)建新組件。繼續(xù)遍歷數(shù)據(jù)項new item時生成鍵值1__new item,不存在相同鍵值,創(chuàng)建內(nèi)容為new item的新組件并渲染。繼續(xù)遍歷數(shù)據(jù)項two生成鍵值2__two,不存在相同鍵值,創(chuàng)建內(nèi)容為two的新組件并渲染。最后遍歷數(shù)據(jù)項three時生成鍵值3__three,不存在相同鍵值,創(chuàng)建內(nèi)容為three的新組件并渲染。
????????盡管此示例中界面渲染的結(jié)果符合預期,但每次插入一條新數(shù)組項時,ForEach都會為從該數(shù)組項起后面的所有數(shù)組項全部重新創(chuàng)建組件。當數(shù)據(jù)源數(shù)據(jù)量較大或組件結(jié)構復雜時,由于組件無法得到復用,將導致性能體驗不佳。因此,除非必要,否則不推薦將第三個參數(shù)KeyGenerator函數(shù)處于缺省狀態(tài),以及在鍵值生成規(guī)則中包含數(shù)據(jù)項索引index。