رابطهی Map متد forEach() دارد که مشابه متد forEach() رابطهی Iterable عمل میکند. تفاوت این است که بهجای Consumer ساده، یک BiConsumer دریافت میکند.
اگر میخواهید عملیات نقشه را تمرین کنید، مستقیماً به انتهای این صفحه بروید: تمرین عملیات Map
بیایید یک نقشهی ساده ایجاد کنیم و محتوایش را چاپ کنیم:
خروجی:
1 :: one
2 :: two
3 :: three
رابطهی Map سه متد برای جایگزینی مقدار متصل به یک کلید ارائه میدهد.
اولی replace(key, value) است که مقدار موجود را کورکورانه جایگزین میکند. معادل یک عملیات put-if-present است. این متد مقداری که از نقشه حذف شده را برمیگرداند.
اگر کنترل دقیقتری نیاز دارید، از نسخهی overloaded آن استفاده کنید که مقدار قدیمی را بهعنوان آرگومان دریافت میکند: replace(key, oldValue, newValue). در این حالت، مقدار فعلی فقط در صورتی با newValue جایگزین میشود که با oldValue مطابقت داشته باشد. این متد اگر جایگزینی انجام شده باشد true برمیگرداند.
رابطهی Map متدی هم برای جایگزینی تمام مقادیر با استفاده از یک BiFunction دارد. این BiFunction یک تابع remapping است که کلید و مقدار را دریافت و مقدار جدیدی برمیگرداند.
خروجی:
1 :: ONE
2 :: TWO
3 :: THREE
رابطهی Map یک الگوی سوم برای اضافه کردن جفتهای کلید-مقدار یا تغییر مقادیر موجود ارائه میدهد: متدهای compute()، computeIfPresent() و computeIfAbsent().
این سه متد آرگومانهای زیر را دریافت میکنند:
BiFunction که بهعنوان تابع remapping عمل میکند (یا mapping function در مورد computeIfAbsent())در مورد compute() و computeIfPresent() این bifunction کلید و مقدار فعلی متصل به آن را دریافت میکند.
برای compute()، تابع remapping با دو آرگومان فراخوانی میشود: کلید و مقدار موجود (یا null اگر وجود نداشته باشد).
برای computeIfPresent()، تابع remapping فقط وقتی فراخوانی میشود که مقدار غیر-null به کلید متصل باشد.
برای computeIfAbsent()، چون مقداری متصل به کلید نیست، تابع remapping در واقع یک Function ساده است که فقط کلید را دریافت میکند. این تابع وقتی فراخوانی میشود که کلید در نقشه وجود نداشته باشد یا به مقدار null متصل باشد.
در همهی موارد، اگر bifunction (یا function) مقدار null برگرداند، کلید از نقشه حذف میشود. هیچ جفت کلید-مقدار با مقدار null از طریق این سه متد اضافه نمیشود.
مهم است بدانید که مقدار برگشتی از این متدها مقدار جدید متصل به کلید است (یا null اگر تابع remapping null برگرداند). این با متدهای put() متفاوت است که مقدار قبلی را برمیگردانند.
یکی از کاربردهای جالب computeIfAbsent() ایجاد نقشههایی با مقادیر لیستی است. فرض کنید لیست رشتههای [one two three four five six seven] را دارید. نیاز به نقشهای دارید که کلیدها طول کلمات و مقادیر لیست کلمات همان طول باشند:
3 :: [one, two, six]
4 :: [four, five]
5 :: [three, seven]
بدون متدهای compute() احتمالاً این کد را مینوشتید:
خروجی مورد انتظار:
3 :: [one, two, six]
4 :: [four, five]
5 :: [three, seven]
میتوانید با putIfAbsent() این حلقه را سادهتر کنید:
خروجی این کد هم همانطور است:
3 :: [one, two, six]
4 :: [four, five]
5 :: [three, seven]
اما computeIfAbsent() کد را بهتر هم میکند:
خروجی:
3 :: [one, two, six]
4 :: [four, five]
5 :: [three, seven]
این کد چگونه کار میکند؟
computeIfAbsent() برگردانده میشود و کد word را به آن اضافه میکند.word را به آن اضافه کنید.این کد بسیار کارآمدتر از نسخهی
putIfAbsent()است. لیست خالی فقط در صورت نیاز ساخته میشود. اگر شیءای که به نقشه اضافه میکنید باید on-demand ساخته شود،computeIfAbsent()برputIfAbsent()ارجحیت دارد.
الگوی computeIfAbsent() زمانی خوب عمل میکند که مقادیر نقشه ادغامهایی از مقادیر دیگر باشند. اما یک محدودیت وجود دارد: ساختار پشتیبان باید mutable باشد (مثل ArrayList).
فرض کنید بهجای لیست کلمات، به ادغام رشتهای کلمات نیاز دارید. String اینجا بهعنوان ادغام رشتههای دیگر دیده میشود اما یک container mutable نیست.
دقیقاً همینجاست که متد merge() به کمک میآید. این متد سه آرگومان دریافت میکند:
BiFunction remappingاگر کلید در نقشه نباشد یا به null متصل باشد، مقدار مستقیماً به کلید متصل میشود.
اگر کلید به مقدار غیرnull متصل باشد، تابع remapping با مقدار موجود و مقدار جدید فراخوانی میشود. اگر تابع remapping null برگرداند، کلید حذف میشود. در غیر این صورت مقدار تولیدشده به کلید متصل میشود.
خروجی:
3 :: one, two, six
4 :: four, five
5 :: three, seven
در هر دو الگو (
computeIfAbsent()وmerge())، ممکن است سوال پیش بیاید چرا lambda آرگومانی میگیرد که در context آن موجود است و میتوانست capture شود. پاسخ: برای دلایل عملکردی، prefer کردن non-capturing lambdas نسبت به capturingها بهتر است.
خروجی:
Original Scores:
Carol: 92
Alice: 95
Bob: 87
David: 78
خروجی:
After specific replacements:
David: 78
Carol: 92
Bob: 90
Alice: 97
After adding 5 bonus points to everyone:
David: 83
Carol: 97
Bob: 95
Alice: 102
خروجی:
Initial inventory:
apples: 50
bananas: 30
oranges: 25
After compute operations:
apples: 70
bananas: 25
grapes: 15
oranges: 25
Final inventory:
bananas: 25
oranges: 25
pears: 12
apples: 70
grapes: 15
خروجی:
Words grouped by length:
2 letters: [go]
3 letters: [c++, css]
4 letters: [java, rust, html]
5 letters: [swift]
6 letters: [python, kotlin]
در مثال دیگر، میتوانید دانشجویان را بر اساس نمره گروهبندی کنید:
خروجی:
Students grouped by grade:
Grade A: [Alice, Carol, Frank]
Grade B: [Bob, Eve]
Grade C: [David]
خروجی:
Character frequencies:
'a': 2
's': 1
'd': 1
'e': 2
'u': 1
'v': 2
'j': 1
'k': 1
'l': 1
'o': 1
میتوانید فراوانی کلمات متن را هم بشمارید:
خروجی:
Word frequencies:
'over': 1
'the': 2
'quick': 1
'lazy': 1
'jumps': 1
'brown': 1
'dog': 1
'fox': 1
همچنین میتوانید از Map.merge() برای ادغام نقشههای کامل استفاده کنید.
خروجی:
Combined sales:
Product A: 100
Product B: 225
Product C: 200
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/