Streams در Java
از لیست با stream() یک خط لوله باز کنید، عنصرها را نگه دارید یا عوض کنید، و در پایان چاپ کنید. در Pipe.java کلاس عمومی Pipe را نگه دارید، import java.util.ArrayList; را بیاورید، "oak" و "pine" را ذخیره کنید، و names.stream().filter(n -> n.startsWith("o")).forEach(n -> System.out.println(n)); را صدا بزنید. با javac Pipe.java ترجمه کنید و java Pipe را اجرا کنید. صفحه باید oak را نشان دهد. دموی دوم از map است تا صفحه OAK و بعد PINE را نشان دهد. Records اختیاری را برای صفحهٔ بعد بگذارید. این درس خط لولهٔ stream است، نه forEach ساده روی لیست و نه دموی Generics با get(0).
filter — نگهداشتن یک کلمهٔ منطبق
Pipe.java را باز کنید. نام کلاس عمومی را Pipe نگه دارید. دموهای باقیماندهٔ lambda فقط با Cue، چاپهای باقیماندهٔ Generics با Bin، اجراهای باقیماندهٔ program-arguments با Flag، و پرسوجوهای باقیماندهٔ Scanner در Box را پاک کنید اگر داستان Streams را میپوشانند. برنامه نباید منتظر تایپ شما بماند و نباید کلمهٔ launch لازم داشته باشد.
import را بالای فایل بگذارید:
import java.util.ArrayList;
داخل Pipe.main یک لیست تایپشده با دو کلمه بسازید، بعد streamای شروع کنید که کلماتی که با o شروع میشوند را نگه میدارد:
ArrayList<String> names = new ArrayList<>();
names.add("oak");
names.add("pine");
names.stream().filter(n -> n.startsWith("o")).forEach(n -> System.out.println(n));
stream() خط لوله را باز میکند. filter عنصرهایی را نگه میدارد که lambda برایشان true برمیگرداند. forEach هر عنصر نگهداشتهشده را چاپ میکند. "oak" با o شروع میشود. "pine" نه. صفحه oak را نشان میدهد.
import java.util.ArrayList;
public class Pipe {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("oak");
names.add("pine");
names.stream().filter(n -> n.startsWith("o")).forEach(n -> System.out.println(n));
}
}
از پوشهای که Pipe.java در آن است javac Pipe.java را اجرا کنید. وقتی آکولادها و سمیکالنها درست باشند، javac خط جداگانهای چاپ نمیکند. بعد java Pipe را بزنید — نه java Pipe.java. یک کلاس عمومی نگه دارید تا نام با Pipe یکی بماند.
یکبار اجرا را قدمبهقدم ببینید. Java از Pipe.main شروع میکند. لیست "oak" و "pine" را نگه میدارد. stream() شروع میشود. filter فقط "oak" را نگه میدارد. forEach مقدار oak را چاپ میکند. هیچچیز هر دو کلمه را با هم چاپ نمیکند. هیچچیز فقط names.forEach بدون stream() را صدا نمیزند. هیچچیز args[0] را نمیخواند.
همانطور که صفحه را نگاه میکنید قانون مبتدی را بگویید: stream() لوله را باز میکند؛ filter انتخاب میکند؛ forEach با چاپ جانبی تمام میشود. Records را روی این صفحه نسازید. Records منتظر درس اختیاری بعدی است. stream() را حذف نکنید و انتظار نداشته باشید filter مستقیماً روی خود لیست در این شکل آموزشی بماند.
اگر هنوز از فایل باقیماندهٔ Cue مقدار oak و بعد pine را با forEach بدون filter میبینید، به Pipe بروید و مرحلهٔ filter را نگه دارید. اگر javac stream را رد کرد، نوع لیست ArrayList باشد و فراخوانی names.stream() باشد.
map — بزرگکردن هر کلمه
همان کلاس عمومی Pipe را نگه دارید. خط لوله را عوض کنید تا هر کلمه را بهجای فیلتر کردن، تبدیل کند:
names.stream().map(n -> n.toUpperCase()).forEach(n -> System.out.println(n));
هر دو "oak" و "pine" را در لیست نگه دارید. دوباره با javac Pipe.java ترجمه کنید و java Pipe را اجرا کنید. صفحه OAK و بعد PINE را نشان میدهد. map برای هر عنصر مقدار جدید برمیگرداند. forEach آن مقادیر را بهترتیب چاپ میکند.
import java.util.ArrayList;
public class Pipe {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("oak");
names.add("pine");
names.stream().map(n -> n.toUpperCase()).forEach(n -> System.out.println(n));
}
}
یکبار اجرا را قدمبهقدم ببینید. اولین مقدار mapشده OAK است. دومین مقدار mapشده PINE است. دو دمو را دو شکل آموزشی جدا نگه دارید. اول ثابت کنید filter یک کلمه را نگه میدارد. بعد ثابت کنید map هر کلمه را عوض میکند. هر دو شکل import، لیست تایپشده، stream()، و forEach پایانی را مشترک دارند.
اگر بعداً در آزمایش خودتان filter و map را زنجیر کنید، ترتیب مهم است. این صفحه در هر دمو فقط یک مرحلهٔ میانی نگه میدارد تا صفحه خوانا بماند.
عادتهای خط لوله
همانطور که تمرین میکنید مراحل را بهترتیب نگه دارید.
📊 عادتهای stream برای Pipe
| مرحله | فراخوانی | چک مبتدی |
|---|---|---|
| شروع | names.stream() |
خط لوله را از لیست باز میکند |
| نگهداشتن بعضی | filter(n -> ...) |
lambda برای نگهداشتن true برمیگرداند |
| عوضکردن هر کدام | map(n -> ...) |
lambda مقدار جدید را برمیگرداند |
| پایان چاپ | forEach(n -> System.out.println(n)) |
مرحلهٔ پایانی که چاپ میکند |
رد کردن stream() |
لیست در این شکل filter ندارد |
قبل از filter یا map، stream() بگذارید |
Streams نه فقط Lambda و نه Records
درس Lambda مستقیماً forEach روی لیست را آموزش داد. Streams ابتدا stream() را میگذارد تا قبل از forEach پایانی بتوانید filter یا map بزنید. Records در صفحهٔ اختیاری بعدی نوع دادهٔ فشرده معرفی میکند. امروز این سه نقش را در یک فایل مبتدی قاطی نکنید.
oak که filter نگه میدارد هنوز عنصر لیستی است که در خط لوله جریان دارد. نه args[0] از Flag. وقتی فایل باقیماندهٔ Cue همهٔ عنصرها را بدون filter چاپ میکند، آن را تاریخچه بگذارید و خط stream().filter در Pipe را نگه دارید.
بدون stream()، فراخوانیهای filter و map این صفحه شکل آموزشی درست نیست. بدون forEach پایانی، خط لوله چیزی چاپ نمیکند. هر دو سر لوله را با هم نگه دارید. سینتکس Records را تا آن درس از این صفحه دور نگه دارید، حتی اگر سرخط فشردهٔ داده را جای دیگر دیده باشید.
بررسی پوشه قبل از Records
بعد از کامپایل موفق پوشه را لیست کنید. باید Pipe.java و Pipe.class را با هم ببینید. سورس را ویرایش کنید، ذخیره کنید، javac Pipe.java را بزنید، بعد java Pipe را اجرا کنید. اگر بعد از عوض کردن به map دوباره کامپایل نکنید، .class قدیمی ممکن است صفحهٔ filter قدیمی نشان دهد.
اگر javac از کلاس عمومی تکراری شکایت کرد، فقط Pipe عمومی بماند. اگر روی دموی filter صفحه هم oak و هم pine را نشان داد، احتمالاً چک startsWith("o") نیست — lambdaٔ filter را برگردانید. اگر چیزی چاپ نشد، قبل از stream()، add واقعاً اجرا شده باشد.
forEach فقطلیستی Cue را جایگزین کل خط لوله روی این صفحه نچسبانید. get(0) از Bin را داخل Pipe نچسبانید. کار اختیاری Streams همان stream بهعلاوهٔ یک مرحلهٔ میانی بهعلاوهٔ forEach است.
قبل از Records اختیاری
میتوانید کلاس عمومی Pipe، import ArrayList، add از "oak" و "pine"، names.stream().filter(n -> n.startsWith("o")).forEach(...)، دیدن oak، بعد names.stream().map(n -> n.toUpperCase()).forEach(...)، دیدن OAK و بعد PINE را نگه دارید. با javac Pipe.java ترجمه کنید و java Pipe را اجرا کنید. جدول شروع، filter، map و پایان را از هم جدا میکند. صفحهٔ اختیاری بعدی Records است.
دموهای Pipe را برای جفت واضح Streams نگه دارید. فایلهای lambda با Cue را هنگام تمرین خط لوله از این صفحه دور نگه دارید. فایلهای Generics با Bin را هنگام تمرین خط لوله از این صفحه دور نگه دارید. کار Records را تا آن درس از این صفحه دور نگه دارید. این عادتها نقطهٔ عبور قبل از ادامهٔ مسیر اختیاری هستند. وقتی صفحهٔ filter مقدار oak یا صفحهٔ map مقدار OAK و بعد PINE را نشان میدهد، Streams کار این درس را کرده و اگر مسیر اختیاری را ادامه دهید برای Records آمادهاید.
یک نوبت آخر روی پوشه: یک Pipe عمومی، import حاضر، ArrayList<String> تایپشده، stream() قبل از filter یا map، forEach پایانی، بدون انتظار Scanner، بدون کلمهٔ launch. یکبار دیگر javac Pipe.java و java Pipe را روی دمویی که باز نگه داشتهاید بزنید. اگر صفحه هنوز oak یا OAK و بعد PINE را نشان میدهد، شکل Streams محکم است و دوره میتواند به Records اختیاری در صفحهٔ بعد برود. برای هر خواندن یک عادت روشن خط لوله نگه دارید تا هر بار همان نقشه را یاد بگیرید.
🧠 دانش خود را بیازمایید
دانش خود را بیازمایید
خود را با این آزمون تعاملی به چالش بکشید و ببینید موضوع را چقدر خوب درک کردهاید
📝 دستورالعملها
- هر سوال را با دقت بخوانید
- بهترین پاسخ را برای هر سوال انتخاب کنید
- میتوانید آزمون را هر چند بار که میخواهید تکرار کنید
- پیشرفت شما در بالا نمایش داده میشود