استریم های دیتا در جاوا
15 دقیقه زمان برای خواندن این مطلب نیاز است.
فهرست مطالب
- دستهبندی استریمهای دیتا در جاوا
- ۱. استریمهای I/O سنتی ( java.io )
- ۲. Stream API جاوا (java.util.stream)
- ۳. استریمهای پیشرفته (NIO و فایلها)
- ۴. مثالهای عملی و واقعی
- ۵. اشتباهات رایج و نکات بهینهسازی
- ۶. آینده استریمهای دیتا در جاوا
- ۷. مقایسه استریمهای I/O و Stream API
- نتیجهگیری نهایی
- سوالات متداول (FAQ)
در دنیای برنامهنویسی جاوا، مدیریت و پردازش جریانهای داده (Data Streams) یکی از مهارتهای اساسی و حیاتی برای هر توسعهدهنده حرفهای است. استریم های دیتا در جاوا به دو دسته کلی تقسیم میشوند: استریمهای I/O (ورودی/خروجی) که برای خواندن و نوشتن داده از منابعی مانند فایلها، سوکتهای شبکه و حافظه استفاده میشوند، و استریمهای API (معرفی شده در جاوا ۸) که روی مجموعهها (مانند لیستها و مجموعهها) عملیات زنجیرهای و اعلانی مانند فیلتر، نگاشت و جمعآوری را امکانپذیر میکنند. در این مقاله از دانا پدیا، به صورت کاملاً تخصصی و جامع به بررسی استریم های دیتا در جاوا میپردازیم. اگر شما یک توسعهدهنده جاوا هستید، چه مبتدی و چه حرفهای، این مطلب دقیقاً همان چیزی است که برای درک عمیق استریم های دیتا در جاوا و استفاده مؤثر از آنها در پروژههای واقعی نیاز دارید.
استریم های دیتا در جاوا مفهومی است که به جریان پیوسته داده از مبدأ به مقصد اشاره دارد. در جاوا، این مفهوم توسط کلاسها و رابطهای متعددی در پکیجهای java.io، java.nio و java.util.stream پیادهسازی شده است. استریمهای I/O سنتی (مانند FileInputStream، BufferedReader) امکان خواندن بایتها یا کاراکترها را به صورت ترتیبی فراهم میکنند. در مقابل، Stream API (که از جاوا ۸ به بعد ارائه شده) یک رویکرد تابعی و موازیپذیر برای پردازش مجموعه دادهها ارائه میدهد که کدنویسی را بسیار خواناتر و نگهداری را آسانتر میکند.
اهمیت استریم های دیتا در جاوا زمانی بیشتر آشکار میشود که با حجم بالای داده سروکار دارید یا نیاز به پردازش کارآمد اطلاعات در حافظه دارید. به عنوان مثال، فرض کنید لیستی از میلیونها تراکنش دارید و باید تراکنشهای مشکوک را فیلتر، گروهبندی و سپس روی آنها محاسبات آماری انجام دهید. با استفاده از Stream API میتوانید این کار را با چند خط کد تمیز و با قابلیت استفاده از پردازش موازی (parallel streams) انجام دهید. از سوی دیگر، برای خواندن فایلهای حجیم خط به خط، استریمهای I/O با بافر (مانند BufferedReader) بهترین کارایی را ارائه میدهند.
در این مقاله از دانا پدیـا، ابتدا به دستهبندی کلی استریم های دیتا در جاوا میپردازیم و هر کدام را جداگانه بررسی میکنیم. سپس با استریمهای I/O (بایت و کاراکتر) شروع کرده و کلاسهای مهم مانند InputStream، OutputStream، Reader، Writer، و نسخههای بافر شده آنها را توضیح میدهیم. در ادامه، به سراغ Stream API (جاوا ۸) میرویم و مفاهیمی مانند منبع استریم، عملیات میانی و نهایی، Optional، Collectors، و استریمهای موازی (Parallel Streams) را با مثالهای عملی شرح میدهیم. سپس موضوعات پیشرفتهای مانند استریمهای نامتناهی، سفارشیسازی جمعآوریکنندهها، و یکپارچهسازی با NIO (فایلها و کانالها) را پوشش میدهیم. در بخش انتهایی نیز به بهترین روشها، اشکالات رایج، و سوالات متداول پاسخ خواهیم داد. هدف ما ارائه یک مرجع کامل و سئوشده است که هم برای مبتدیان و هم برای حرفهایها مفید باشد.

دستهبندی استریمهای دیتا در جاوا
قبل از ورود به جزئیات، بهتر است بدانیم استریم های دیتا در جاوا به چند دسته تقسیم میشوند:
| دسته | پکیج | هدف اصلی | مثال |
|---|---|---|---|
| استریمهای بایت (Byte Streams) | java.io | خواندن/نوشتن داده باینری (فایلها، تصاویر، صدا) | FileInputStream, FileOutputStream |
| استریمهای کاراکتر (Character Streams) | java.io | خواندن/نوشتن متن (UTF-8, UTF-16) | FileReader, FileWriter |
| استریمهای بافر شده (Buffered Streams) | java.io | بهبود کارایی با کاهش تعداد تماسهای سیستمی | BufferedInputStream, BufferedReader |
| استریمهای داده (Data Streams) | java.io | خواندن/نوشتن نوعهای اولیه جاوا و رشتهها | DataInputStream, DataOutputStream |
| استریمهای شیء (Object Streams) | java.io | سریالایزیشن و دسریالایزیشن اشیاء | ObjectInputStream, ObjectOutputStream |
| استریمهای API (Functional Streams) | java.util.stream | پردازش تابعی مجموعهها | Stream<T>, IntStream, Collectors |
| استریمهای NIO (Non-blocking I/O) | java.nio | کانالها و بافرهای کارآمد برای I/O با کارایی بالا | FileChannel, ByteBuffer |
در ادامه، هر دسته را به تفصیل بررسی میکنیم.
برنامه نویسی بدون کد (No-Code) در مقابل Low-Code
۱. استریمهای I/O سنتی (java.io)
۱.۱ استریمهای بایت (InputStream و OutputStream)
اساس تمام استریمهای بایت در جاوا، کلاسهای انتزاعی InputStream و OutputStream هستند. این کلاسها متدهای اصلی read() و write() را تعریف میکنند.
مثال خواندن یک فایل باینری:
java
import java.io.*;
public class ByteStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("input.bin");
FileOutputStream fos = new FileOutputStream("output.bin")) {
int byteData;
while ((byteData = fis.read()) != -1) {
fos.write(byteData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
نکات مهم:
- همیشه از
try-with-resources(جاوا ۷ به بعد) برای بستن خودکار استریم استفاده کنید. - متد
read()یک بایت را به صورتintبرمیگرداند و در انتهای فایل-1بازمیگرداند. - برای کارایی بهتر، از
BufferedInputStreamوBufferedOutputStreamاستفاده کنید.
۱.۲ استریمهای کاراکتر (Reader و Writer)
برای کار با دادههای متنی (UTF-8, UTF-16) به جای بایت، از کلاسهای Reader و Writer استفاده میشود. این کلاسها با کاراکترها (چار) سروکار دارند و کدگذاری (encoding) را مدیریت میکنند.
مثال خواندن یک فایل متنی خط به خط:
java
import java.io.*;
public class CharStreamExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
برای نوشتن نیز میتوان از BufferedWriter و PrintWriter استفاده کرد.
۱.۳ استریمهای بافر شده (Buffered Streams)
استریمهای بافر شده با استفاده از یک بافر داخلی، تعداد تماسهای سیستمی را کاهش میدهند و کارایی را به شدت افزایش میدهند. همیشه توصیه میشود که استریمهای فایل را با بافر بپیچید:
java
// نادرست (بدون بافر)
FileInputStream fis = new FileInputStream("file.dat");
// درست
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("file.dat"));
۱.۴ استریمهای داده (DataInputStream و DataOutputStream)
این استریمها امکان خواندن و نوشتن نوعهای اولیه جاوا (مانند int, long, double) و رشتهها را به صورت مستقل از پلتفرم فراهم میکنند.
java
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"))) {
dos.writeInt(123);
dos.writeDouble(45.67);
dos.writeUTF("سلام دنیا");
}
۱.۵ استریمهای شیء (ObjectInputStream و ObjectOutputStream)
برای ذخیره و بازیابی اشیاء کامل جاوا (سریالایزیشن) از این استریمها استفاده میشود. کلاس مورد نظر باید اینترفیس Serializable را پیادهسازی کند.
java
class Person implements Serializable {
private String name;
private int age;
// سازنده، getter، setter
}
// نوشتن شیء
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
oos.writeObject(new Person("علی", 30));
}
۱.۶ بهترین روشها برای استریمهای I/O
- همیشه از
try-with-resourcesاستفاده کنید. - استریمهای فایل را با بافر بپیچید (
BufferedInputStreamو غیره). - برای متن، از
BufferedReader/BufferedWriterاستفاده کنید. - برای دادههای باینری حجیم، از NIO (کانالها) بهره ببرید.
- هرگز از
read()تکی در حلقه برای فایلهای بزرگ استفاده نکنید. ازread(byte[] buffer)استفاده کنید.
۲. Stream API جاوا (java.util.stream)
با معرفی جاوا ۸، انقلابی در پردازش دادههای درون حافظه ایجاد شد. استریم های دیتا در جاوا با رویکرد تابعی، امکان نوشتن کدهای فشرده، موازی و بدون副作用 را فراهم کردند.
۲.۱ مفهوم Stream
Stream<T> یک دنباله از عناصر است که از یک منبع (مانند Collection، آرایه، تابع تولیدکننده) ایجاد میشود و از یک یا چند عملیات میانی (Intermediate) و یک عملیات نهایی (Terminal) تشکیل شده است. ویژگیهای مهم:
- بیحالت (Stateless): استریم منبع داده را تغییر نمیدهد.
- تنبل (Lazy): عملیات میانی فقط زمانی اجرا میشوند که عملیات نهایی فراخوانی شود.
- یکبارمصرف (Consumable): یک استریم فقط یک بار میتواند مصرف شود.
۲.۲ ایجاد Stream
روشهای مختلف ایجاد Stream:
java
// از یک Collection
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> streamFromList = list.stream();
// از یک آرایه
Stream<Integer> streamFromArray = Arrays.stream(new Integer[]{1, 2, 3});
// از مقادیر مستقیم
Stream<String> streamOf = Stream.of("x", "y", "z");
// استریم بینهایت با generate یا iterate
Stream<Double> randoms = Stream.generate(Math::random).limit(10);
Stream<Integer> iterated = Stream.iterate(0, n -> n + 2).limit(5); // 0,2,4,6,8
برای نوعهای اولیه، استریمهای تخصصی IntStream، LongStream و DoubleStream وجود دارند که از باز کردن جعبه (unboxing) خودکار جلوگیری میکنند و کارایی بالاتری دارند.
۲.۳ عملیات میانی (Intermediate Operations)
این عملیات یک استریم جدید بازمیگردانند و تا قبل از عملیات نهایی اجرا نمیشوند. مهمترین آنها:
| عملیات | توضیح | مثال |
|---|---|---|
filter(Predicate<T>) | عناصری که شرط را برآورده کنند نگه میدارد | stream.filter(s -> s.length() > 3) |
map(Function<T,R>) | هر عنصر را به عنصر دیگری تبدیل میکند | stream.map(String::toUpperCase) |
flatMap(Function<T, Stream<R>>) | هر عنصر را به یک استریم تبدیل و صاف میکند | stream.flatMap(line -> Arrays.stream(line.split(" "))) |
distinct() | حذف عناصر تکراری | stream.distinct() |
sorted() | مرتبسازی طبیعی (یا با Comparator) | stream.sorted(Comparator.reverseOrder()) |
peek(Consumer<T>) | برای دیباگ، هر عنصر را دیده اما تغییری نمیدهد | stream.peek(System.out::println) |
limit(long n) | حداکثر n عنصر اول را نگه میدارد | stream.limit(10) |
skip(long n) | n عنصر اول را نادیده میگیرد | stream.skip(5) |
۲.۴ عملیات نهایی (Terminal Operations)
عملیات نهایی باعث اجرای کل pipeline میشوند و پس از آن استریم قابل استفاده نیست.
| عملیات | توضیح | مثال |
|---|---|---|
forEach(Consumer<T>) | روی هر عنصر عملی انجام میدهد | stream.forEach(System.out::println) |
toList() (جاوا ۱۶+) | جمعآوری نتایج در یک List | List<String> result = stream.toList() |
collect(Collector) | جمعآوری نتایج با یک Collector | stream.collect(Collectors.toSet()) |
reduce(BinaryOperator<T>) | ترکیب عناصر به یک مقدار | stream.reduce(0, Integer::sum) |
count() | تعداد عناصر | long cnt = stream.count() |
anyMatch(Predicate) | آیا حداقل یک عنصر شرط را دارد؟ | boolean found = stream.anyMatch(s -> s.startsWith("A")) |
allMatch(Predicate) | آیا همه عناصر شرط را دارند؟ | |
noneMatch(Predicate) | آیا هیچ عنصری شرط را ندارد؟ | |
findFirst() | اولین عنصر (برای استریمهای ترتیبی) | Optional<String> first = stream.findFirst() |
findAny() | هر عنصر (برای موازیسازی کارآمدتر) |
۲.۵ Optional و مدیریت مقادیر تهی
عملیاتی مانند findFirst() و reduce() ممکن است چیزی پیدا نکنند، بنابراین Optional<T> بازمیگردانند که از NullPointerException جلوگیری میکند.
java
Optional<String> maybeFirst = list.stream().filter(s -> s.length() > 10).findFirst();
maybeFirst.ifPresentOrElse(
s -> System.out.println("یافت شد: " + s),
() -> System.out.println("چیزی یافت نشد")
);
۲.۶ Collectors (جمعآوریکنندهها)
کلاس Collectors متدهای کارخانهای زیادی برای سناریوهای رایج دارد:
toList()،toSet()،toCollection(Supplier)joining()برای چسباندن رشتههاgroupingBy(Function)برای گروهبندی بر اساس یک کلیدpartitioningBy(Predicate)برای تقسیم به دو گروهsummarizingInt(...)برای آمار (شامل count, sum, min, avg, max)
مثال گروهبندی:
java
Map<String, List<Person>> peopleByCity = people.stream()
.collect(Collectors.groupingBy(Person::getCity));
مثال جمعآوری در یک TreeSet:
java
TreeSet<String> set = stream.collect(Collectors.toCollection(TreeSet::new));
۲.۷ استریمهای موازی (Parallel Streams)
یکی از نقاط قوت استریم های دیتا در جاوا، پشتیبانی داخلی از پردازش موازی است. با فراخوانی parallelStream() به جای stream()، یا استفاده از parallel() روی یک استریم موجود، پردازش به طور خودکار بین چندین هسته تقسیم میشود.
java
long sum = LongStream.rangeClosed(1, 10_000_000)
.parallel()
.sum();
مواظب باشید: پردازش موازی فقط زمانی سودمند است که:
- حجم داده بزرگ است (هزاران تا میلیونها عنصر)
- عملیات روی هر عنصر مستقل و بدون حالت (stateless) باشد
- ترتیب عناصر مهم نباشد (یا با
forEachOrderedاستفاده کنید)
۲.۸ استریمهای اولیه (Primitive Streams)
برای جلوگیری از هزینههای اتوباکسینگ، جاوا IntStream، LongStream و DoubleStream را ارائه میدهد. این استریمها متدهای خاصی مانند range(), sum(), average() دارند.
java
// ایجاد IntStream از ۱ تا ۱۰۰ IntStream.rangeClosed(1, 100).sum(); // تبدیل IntStream به Stream<Integer> Stream<Integer> boxed = intStream.boxed();
۳. استریمهای پیشرفته (NIO و فایلها)
Package java.nio.file امکانات مدرنی برای کار با فایلها و استریمها فراهم کرده است. متدهای Files.lines() و Files.list() مستقیماً یک Stream<String> بازمیگردانند که بسیار کارآمد و خودکار بسته میشود.
java
try (Stream<String> lines = Files.lines(Path.of("data.txt"))) {
long count = lines.filter(line -> line.contains("error")).count();
System.out.println("تعداد خطوط حاوی error: " + count);
} catch (IOException e) {
e.printStackTrace();
}
همچنین Files.walk() برای پیمایش دایرکتوریها به صورت بازگشتی و Files.find() برای جستجوی فایلها با شرط، استریم بازمیگردانند.
۴. مثالهای عملی و واقعی
مثال ۱: پردازش گزارشهای لاگ (Log Files)
فرض کنید یک فایل لاگ با میلیونها خط داریم و میخواهیم شمارش خطاها بر اساس سطح (ERROR، WARN، INFO) را بدست آوریم.
java
Map<String, Long> errorCount = Files.lines(Path.of("app.log"))
.parallel()
.filter(line -> line.contains("ERROR") || line.contains("WARN"))
.map(line -> line.split("\\s+")[2]) // فرض کنیم ستون سوم سطح است
.collect(Collectors.groupingBy(s -> s, Collectors.counting()));
مثال ۲: محاسبه آمار فروش
لیستی از محصولات با نام، قیمت و دستهبندی داریم. میانگین قیمت محصولات هر دسته را محاسبه کنید.
java
Map<String, Double> avgPricePerCategory = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.averagingDouble(Product::getPrice)
));
مثال ۳: فیلتر کردن و جمعآوری سفارشات
متن زیر را با استریم پیادهسازی کنید: از لیست سفارشات، فقط سفارشات با مبلغ بیشتر از ۱۰۰۰ را بگیرید، آنها را بر اساس تاریخ مرتب کنید، و سپس یک لیست از شناسه سفارشات برگردانید.
java
List<Long> highValueOrderIds = orders.stream()
.filter(order -> order.getTotal() > 1000)
.sorted(Comparator.comparing(Order::getDate))
.map(Order::getId)
.collect(Collectors.toList());
۵. اشتباهات رایج و نکات بهینهسازی
۱. استفاده مجدد از استریم: یک استریم پس از عملیات نهایی بسته میشود. اگر نیاز به پردازش مجدد دارید، از منبع دوباره استریم بگیرید.
۲. استفاده از استریم برای مجموعههای خیلی کوچک: برای چند ده عنصر، حلقههای سنتی معمولاً سریعتر هستند.
۳. فراموشی try-with-resources برای استریمهای مبتنی بر فایل: استریمهایی که منبعشان فایل یا کانال است باید بسته شوند. از try با استریم استفاده کنید.
۴. تغییر منبع در حین پردازش: اگر در حین پیمایش استریم، مجموعه منبع تغییر کند (مثلاً با remove) ممکن است ConcurrentModificationException رخ دهد.
۵. سربار موازیسازی برای دادههای کوچک: parallel() را فقط برای حجم داده بزرگ و عملیات سنگین استفاده کنید.
۶. آینده استریمهای دیتا در جاوا
در نسخههای جدید جاوا (۱۷، ۲۱، و ۲۵)، بهبودهای زیر به استریمها اضافه شده است:
- Gatherers (جاوا ۲۲): عملیات میانی سفارشی با قابلیت نگهداری حالت (مانند پنجرههای لغزنده).
- Stream.toList() به جای
collect(Collectors.toList())(جاوا ۱۶). - متدهای
mapMultiبرای جایگزینیflatMapبا کارایی بهتر در برخی موارد. - بهبود در عملکرد موازی با استفاده از
ForkJoinPoolسفارشی.
۷. مقایسه استریمهای I/O و Stream API
| ویژگی | استریمهای I/O | Stream API |
|---|---|---|
| هدف | خواندن/نوشتن داده از منابع خارجی | پردازش داده درون حافظه |
| منبع داده | فایل، سوکت، حافظه | کالکشن، آرایه، تابع |
| اجرا | ترتیبی، مسدودکننده (blocking) | ترتیبی یا موازی |
| قابلیت زنجیره | خیر (دستورات جداگانه) | بله (روش فلوئنت) |
| پشتیبانی از لامبدا | خیر | بله |
| مدیریت خطا | Exception معمولی | RuntimeException در عملیات (بدون throws) |
نتیجهگیری نهایی
در این مقاله از دانا پدیا، به طور جامع و تخصصی به بررسی استریم های دیتا در جاوا پرداختیم. استریم های دیتا در جاوا شامل دو دنیای مجزا اما مکمل هستند: استریمهای I/O سنتی برای ارتباط با منابع خارجی (فایل، شبکه) و Stream API برای پردازش کارآمد و شیک دادههای درون حافظه. تسلط بر هر دو بخش برای هر توسعهدهنده جاوا ضروری است. با استفاده از استریمهای بافر شده و NIO میتوانید I/O را بهینه کنید و با Stream API کدهای خواناتر، قابل نگهداریتر و آماده برای موازیسازی بنویسید.
توصیه میکنیم که در پروژههای جدید، تا حد امکان از Stream API برای عملیات روی مجموعهها استفاده کنید. اما همچنان در مواردی که با فایلهای بزرگ سروکار دارید یا نیاز به کنترل دقیق روی بایتها دارید، استریمهای I/O (به خصوص BufferedInputStream و BufferedReader) بهترین گزینه هستند.

سوالات متداول (FAQ)
سوال ۱: تفاوت بین Stream و Collection در جاوا چیست؟
پاسخ: Collection یک ساختار داده است که عناصر را در حافظه ذخیره میکند و امکان دسترسی تصادفی و تغییر (اضافه/حذف) را دارد. Stream یک دیدگاه (view) از دادههاست که عملیات محاسباتی را به صورت تابعی و زنجیرهای امکانپذیر میکند، اما داده را ذخیره نمیکند و پس از مصرف از بین میرود.
سوال ۲: آیا استریمها همیشه از مجموعههای اصلی کپی تهیه میکنند؟
پاسخ: خیر، استریمها یک view از منبع داده هستند و کپی فیزیکی ایجاد نمیکنند (مگر در عملیاتهای نهایی مانند toList() که نتیجه را جمع میکند). این ویژگی باعث کارایی بالای آنها میشود.
سوال ۳: چه زمانی باید از parallelStream استفاده کنم؟
پاسخ: زمانی که حجم داده بسیار بزرگ است (بیش از ۱۰۰۰۰ عنصر)، عملیات روی هر عنصر سنگین و مستقل از بقیه است، و ترتیب نتیجه نهایی اهمیت ندارد (یا از forEachOrdered استفاده میکنید). در غیر این صورت، سربار موازیسازی ممکن است عملکرد را کاهش دهد.
سوال ۴: چگونه میتوانم یک استریم سفارشی برای منبع داده خود بسازم؟
پاسخ: با پیادهسازی اینترفیس Spliterator یا استفاده از StreamSupport.stream() میتوانید استریم سفارشی ایجاد کنید. همچنین متد Stream.iterate() و Stream.generate() برای استریمهای ساده کافی هستند.
سوال ۵: آیا استریمهای I/O (مانند FileInputStream) thread-safe هستند؟
پاسخ: خیر، اکثر استریمهای I/O thread-safe نیستند. اگر چندین ترد به طور همزمان از یک استریم بخوانند/بنویسند، باید همگامسازی دستی (synchronized) انجام دهید. برای خواندن موازی فایل، از Files.lines().parallel() استفاده کنید که زیرساخت آن thread-safe است.
سوال ۶: تفاوت بین findFirst() و findAny() در استریمهای موازی چیست؟
پاسخ: findFirst() همواره اولین عنصر را برمیگرداند و در استریمهای موازی هزینه بیشتری دارد (به دلیل حفظ ترتیب). findAny() هر عنصری را برمیگرداند (معمولاً سریعتر) و برای سناریوهایی که ترتیب مهم نیست توصیه میشود.
سوال ۷: چگونه میتوانم در استریم، خطاهای چکشده (checked exceptions) را مدیریت کنم؟
پاسخ: از آنجا که لامبداها در استریم نمیتوانند checked exception پرتاب کنند، باید آنها را در بدنه لامبدا catch کرده و به یک unchecked exception تبدیل کنید (مثلاً RuntimeException). یا از یک روش کمکی با try-catch استفاده کنید.
سوال ۸: آیا استریمهای IntStream نسبت به Stream<Integer> سریعتر هستند؟
پاسخ: بله، به دلیل عدم نیاز به boxing/unboxing، IntStream هم سریعتر است و هم حافظه کمتری مصرف میکند. برای عملیات عددی همیشه از استریمهای اولیه استفاده کنید.
سوال ۹: نحوه صحیح بستن استریم مبتنی بر فایل چیست؟
پاسخ: همیشه استریم را در بلوک try-with-resources قرار دهید. متد Files.lines() یک Stream<String> برمیگرداند که AutoCloseable است و پس از خروج از بلوک try به طور خودکار بسته میشود.
سوال ۱۰: آیا میتوانم از استریمها برای دادههای زمان واقعی (real-time) استفاده کنم؟
پاسخ: Stream API سنتی برای دادههای از پیش تعیین شده (in-memory) است. برای دادههای جاری (مانند سوکت، پیامهای کافکا) باید از کتابخانههای واکنشی مانند Project Reactor یا RxJava استفاده کنید که مفهوم Flux و Observable را ارائه میدهند. جاوا ۹ نیز Flow (مشابه Reactive Streams) را معرفی کرده است.