<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های صادق خانزادی</title>
        <link>https://virgool.io/feed/@m_32522312</link>
        <description>Java Developer | digipay</description>
        <language>fa</language>
        <pubDate>2026-04-15 08:17:22</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/2602372/avatar/vgSrQu.jpg?height=120&amp;width=120</url>
            <title>صادق خانزادی</title>
            <link>https://virgool.io/@m_32522312</link>
        </image>

                    <item>
                <title>الگوی ساگا (Saga Pattern)</title>
                <link>https://virgool.io/Javenture/%D8%A7%D9%84%DA%AF%D9%88%DB%8C-%D8%B3%D8%A7%DA%AF%D8%A7-saga-pattern-qfdsmotaqn7f</link>
                <description> 10 تا الگوی مهم در طراحی میکروسرویس هست که باید بلد باشید که بتونید ساختار مایکروسرویس های خودتون رو به خوبی پیاده سازی کنید.1-Database per service pattern2-Saga pattern3-API gateway pattern4-Aggregator design pattern5-Circuit breaker design pattern6-Command query responsibility segregation (CQRS)7-Asynchronous messaging8-Event sourcing9-Strangler10-Decomposition patternsسرویس هاتون نیاز به رهبر دارن یا رقص رو خوب بلدن ؟؟!!!یه نکته طلایی همین اول بگیم ذهنتون درگیر بشه بعد بریم شروع کنیم :توی Choreography سرویس‌ها خودشون &quot;رقص&quot; رو بلدنولی توی Orchestration یه رهبر ارکستر (Orchestrator) هست که می‌گه کی چی بزنه 😄الگوی ساگا (Saga Pattern):ساگا مجموعه‌ای از تراکنش‌های محلی (Local Transactions) است. در اپلیکیشن‌های مبتنی بر میکروسرویس، الگوی ساگا می‌تواند به حفظ یکپارچگی داده‌ها (maintain data) در تراکنش‌های توزیع‌شده  (distributed transactions) کمک کند.الگوی ساگا یک راه‌حل جایگزین برای سایر الگوهای طراحی است که امکان اجرای چندین تراکنش را فراهم می‌کند، در حالی که فرصت‌هایی برای بازگردانی (Rollback) در صورت بروز خطا نیز فراهم می‌سازد.به‌بیان ساده، به‌جای اینکه یک تراکنش بزرگ و مرکزی بین چند سرویس اجرا شود، ساگا هر عملیات را در قالب تراکنش‌های جداگانه اما مرتبط اجرا می‌کند. اگر این وسط زبونم لال یکی از تراکنش‌ها با خطا مواجه شود، عملیات‌های جبرانی (Compensating Actions) اجرا می‌شوند تا سیستم به وضعیت سازگار قبلی بازگردد.دوتا روش پیاده سازی داریم :۱. Choreography (هماهنگی غیرمتمرکز):در این روش، هر سرویس پس از انجام یک تراکنش، یک رویداد (Event) منتشر می‌کند. سایر سرویس‌ها به این رویدادها گوش می‌دهند و طبق دستوراتی که برایشان نوشته شده عمل می‌کنند. خود این اقدامات ممکنه رویداد جدیدی منتشر کنند یا نکنند.۲. Orchestration (هماهنگی متمرکز):در این رویکرد، یک &quot;هماهنگ‌کننده&quot; (Orchestrator) مسئول اجرای تراکنش‌ها و مدیریت رویدادها است. به سایر سرویس‌ها اعلام میکنه که چه تراکنش‌های محلی را اجرا کنند.در واقع Orchestrator مانند رهبر ارکستر عمل می‌کند و اجرای مراحل مختلف را کنترل می‌کند.الگوی ساگا یکم پیچیده و سخته و پیاده‌سازی موفق و کاملش  مهارت بالایی میخواد. شاید جایی که الان هستید پیاده سازی شده باشه برید ببینید چطوری نوشتنش یاد بگیرید.یه مزیت بزرگش اینه که بدون ایجاد coupling زیاد بین سرویس‌ها، میتونیم انسجام داده‌ها ( maintained data ) رو حفظ کنیم.بیاید با یه مثال هر کدوم از این دوتا روش رو بهتر بشناسیم :یه نکته رو بگم Orchestration رو لطفا با Api Gateway اشتباه نگیرید کارشون متفاوته سعی میکنم یه مثال براش بزنم .فرض کنید یه فروشگاه اینترنتی دارید و فرض کنید که چنتا مایکروسرویس داریم (خیلی خفنه فروشگاهمون):Order Service → ثبت سفارشInventory Service → بررسی و رزرو موجودیPayment Service → انجام پرداختShipping Service → ارسال محصولNotification Service → ارسال پیام های مرتبط به مشتری (پیامک ، ایمیل و ...)Choreography :بریم سراغ Choreography که کاملاً غیرمتمرکز هست و بر پایه Event-Driven Architecture کار می‌کنه.ما تو روش Choreography، هیچ Orchestrator مرکزی نداریم. هر سرویس فقط به رویدادهای منتشرشده گوش می‌ده و در صورت نیاز، واکنش نشون می‌ده. برای event هم مثلا از RabbitMQ یا Kafka استفاده میکنیم .مراحل اجرا :کاربر میاد یه سفارش ثبت میکنه . مسئولیت ثبت سفارش به عهده Order Service هست .Order Service سفارش رو در دیتابیس ذخیره می‌کنه.و یه رویداد OrderCreated منتشر می‌کنه.نکته میتونیم رویداد هامون رو نام گذاری کنیم و هر رویداد برای کار خاصی باشه . تصمیم با خودتونه  (&quot;OrderCreated&quot;:&quot;event&quot;)این پایین یه نمونه از رویداد ایجاد شده رو میبینید.{
  &amp;quotevent&amp;quot: &amp;quotOrderCreated&amp;quot,
  &amp;quotdata&amp;quot: {
    &amp;quotorderId&amp;quot: &amp;quot123&amp;quot,
    &amp;quotuserId&amp;quot: &amp;quot456&amp;quot,
    &amp;quotproductId&amp;quot: &amp;quotabc&amp;quot,
    &amp;quotquantity&amp;quot: 2,
    &amp;quottotalPrice&amp;quot: 500000
  }
}همه سرویس ها در حال گوش دادن به رویداد مورد نظر خودشون هستن .در این مرحله Inventory Service که داره به رویداد OrderCreated گوش میده. وقتی این رویداد رو دید:بررسی می‌کنه موجودی کافی هست یا نهاگه کافی بود، موجودی رو رزرو می‌کنهرویداد InventoryReserved منتشر می‌کنهدر این مرحله Payment Service داره به رویداد InventoryReserved گوش میده .وقتی این رویداد رو دید:پرداخت رو انجام می‌ده (مثلاً از کیف پول کاربر)اگه موفق بود، رویداد PaymentSucceeded منتشر می‌کنهاگه ناموفق بود، رویداد PaymentFailed منتشر می‌کنهدر مرحله آخر هم Shipping Service داره به رویداد PaymentSucceeded گوش میده .وقتی این رویداد رو دید:عملیات ارسال رو آغاز می‌کنهرویداد OrderShipped منتشر می‌کنهدر صورت خطا چه میشه؟ مثلاً اگر PaymentFailed اتفاق بیفته:Inventory Service می‌تونه به PaymentFailed گوش بده و موجودی رو آزاد کنه و رویداد InventoryReleased رو منتشر کنه .Order Service می‌تونه سفارش رو به وضعیت &quot;ناموفق&quot; ببرهجمله مهمی که اول گفتم :  توی Choreography سرویس‌ها خودشون &quot;رقص&quot; رو بلدنOrchestration :یک سرویس مرکزی (به‌نام Orchestrator) تصمیم می‌گیره چه کاری انجام بشه، به کدوم سرویس‌ها پیام بده، به چه ترتیبی این کارها انجام بشن، و اگه خطایی پیش اومد، چه عکس‌العملی نشون بده.متمرکز بودن اینه که همه‌ی تصمیم‌گیری‌ها، توسط همین Orchestrator انجام می‌شه.خوب ما اینجا یه سرویس اصلی و مهم داریم که توی روش قبلی نداشتیم : PurchaseOrchestratorدر Choreography  بر اساس هر event سرویس ها خودشون میزدن و میرقصیدن ولی اینجا ازین خبرا نیست .در اینجا PurchaseOrchestrator همه کار هارو پشت سر هم انجام میده و خطا هارو بررسی میکنه و تصمیم میگیره در هر مرحله باید چه اتفاقی بیفته .اگر مثلاً پرداخت شکست خورد، می‌تونه سفارش رو کنسل کنه یا پیام خطا بده.در واقع :ترتیب کار سرویس‌ها رو تعیین میکنهبهشون فرمان میدهتصمیم‌گیری کنه که در صورت خطا، چی‌کار کنهگردش فرآیند (Workflow) رو مدیریت میکنهتوی Orchestration یه رهبر ارکستر (Orchestrator) هست که می‌گه کی چی بزنه 😄یه نکته رو یادمون نره Api Gateway و Orchestration کلا ربطی به هم ندارن .API Gateway یه ورودی واحد (Single Entry Point) برای کل سیستم میکروسرویس‌هاست.کارهایی که معمولاً انجام می‌ده:احراز هویت و امنیت (Authentication &amp; Authorization)مسیریابی درخواست‌ها (Routing)محدودسازی نرخ درخواست (Rate Limiting)کش کردن (Caching)تبدیل فرمت درخواست و پاسخ (Transformation)نسخه‌بندی API (API Versioning) این یعنی GateWay بیشتر تمرکز روی مدیریت ورودی داره، نه منطق کسب‌و‌کار یا جریان فرآیندها.پس Orchestrator  چیه؟ ( توی Saga Orchestration)ترتیب کار سرویس‌ها رو تعیین کنهبهشون فرمان بدهتصمیم‌گیری کنه که در صورت خطا، چی‌کار کنهگردش فرآیند (Workflow) رو مدیریت کنه این یعنی Orchestrator روی منطق و کنترل فرآیند متمرکزه.پس چرا بعضی جاها Gateway به عنوان Orchestrator استفاده می‌شه؟در بعضی سیناریوهای ساده یا BFF (Backend For Frontend)، ممکنه Gateway:چند درخواست به سرویس‌های مختلف بدهنتیجه‌ها رو تجمیع کنه (Aggregation)پاسخ نهایی رو به کلاینت بدهدر این حالت‌ها، Gateway یه جور Orchestration سبک (Lightweight) انجام می‌ده، ولی هنوز مثل یه Orchestrator واقعی نیست.خوب اگر دوس داشتید میتونیم با اسپرینگ بوت و rabbitMQ بیایم یه نمونه پیاده سازی کنیم .منتظر نگاه های قشنگنتون هستم .بازم اینو بگم :توی Choreography سرویس‌ها خودشون &quot;رقص&quot; رو بلدنولی توی Orchestration یه رهبر ارکستر (Orchestrator) هست که می‌گه کی چی بزنه 😄</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Mon, 07 Apr 2025 01:12:30 +0330</pubDate>
            </item>
                    <item>
                <title>Java Object Mapper</title>
                <link>https://virgool.io/Javenture/java-object-mapper-trictgjsko9i</link>
                <description>توی این آموزش میخوایم انواع روش هایی که میشه دوتا Object رو به هم Map کنیم رو توضیح بدیم .چنتا Dependency معرفی میکنیم. و از یکیش که بهتر و خفن تره استفاده میکنیم . (هدف این آموزش اینه که از Dependency استفاده کنیم.)چند مدل کد بدون استفاده از Dependency مینویسیم . (روش های خیلی ساده و پیچیده) چنتا روش برای Map کردن کلاس های مختلف داریم 1- استفاده از dependency :1- MapStruct&lt;dependency&gt;
     &lt;groupId&gt;org.mapstruct&lt;/groupId&gt; 
    &lt;artifactId&gt;mapstruct&lt;/artifactId&gt; 
    &lt;version&gt;1.5.5.Final&lt;/version&gt; 
&lt;/dependency&gt;

 &lt;dependency&gt; 
     &lt;groupId&gt;org.mapstruct&lt;/groupId&gt; 
     &lt;artifactId&gt;mapstruct-processor&lt;/artifactId&gt; 
     &lt;version&gt;1.5.5.Final&lt;/version&gt; 
    &lt;scope&gt;provided&lt;/scope&gt; 
&lt;/dependency&gt;2-ModelMapper&lt;dependency&gt; 
      &lt;groupId&gt;org.modelmapper&lt;/groupId&gt; 
      &lt;artifactId&gt;modelmapper&lt;/artifactId&gt;
      &lt;version&gt;3.1.0&lt;/version&gt;
 &lt;/dependency&gt;
2- استفاده از روش های دستی و طاقت فرسا :توی این حالت میتونید از reflection استفاده کنید میتونید برید دستی setter , getter کنید میتونید براش builder بنویسیدمیتونید constructor بنویسید.میتونید از objectMepper های جاوا استفاده کنید یا از Gson استفاده کنید البته باید فیلد ها هم نام باشند .بیاید توی هر کلاس mapper ایجاد کنید .هر کدوم از این روش ها یه سری مشکلات به همراه داره ، نگهداری کد رو دچار مشکل میکنه مثلا اگر constructor بنویسید به ازای هر فیلد جدید باز باید تغییر بدید و یه ور کد میترکه و تست دوچار مشکل میشه و ...  که خودتون بهتر از میدونید .خوب حالا مزیت هر روش چیه :1- اگر بیایم از mapStruct استفاده کنیم  سرعت : بسیار بالا خوانایی کد : عالی  یعنی خیلی خیلی عالیزمان بندی اجرا : compile-time انعطاف پذیریش هم بالاست  2- اگر بیایم از ModelMapper استفاده کنیم سرعت : متوسط خوانایی کد : خوب   زمان بندی اجرا : Runtime  انعطاف پذیریش بسیار بسیار بالاست 3- روش های دستی هم :سرعت : بالا بستگی به کدی که میزنی داره خوانایی کد : بستگی به کد داره زمان بندی اجرا : دستی (custom) انعطاف پذیریش بالا - بستگی به کدت داره حالا چرا همش گفتیم بستگی به کدت داره یکی اینکه از چه روشی استفاده کنی و اینکه چقدر کثیف کد بزنی میتونه تاثیر گذار باشه .برای اینکه بهتر درک کنید که چرا ما میایم از dependency استفاده میکنیم ، بیایم اول یه چنتا کد دستی بزنیم برای map کردن . (ممکنه کدی که اینجا میزنم خطا داشته باشه چون وقت کافی برای تست نداشتم اخر شب داشتم مینوشتم اینو  ، خودتون یه دستی به سروگوشش بکشید. )خوب بیام دوتا کلاس داشته باشیم که میخوایم اینارو به هم map کنیم و بعد بیایم از reflection برای map کردن این دوتا کلاس استفاده کنیم .class Employee {
    private String fullName;
    private int age;

    public String getFullName() {
       return fullName;
    }

    public void setFullName(String fullName) {
       this.fullName = fullName;
    }

    public int getAge() {
       return age;
    }

    public void setAge(int age) {
       this.age = age;
    }
}



class Person {
    private String name;
    private int yearsOld;

    public String getName() {
       return name;
    }

    public void setName(String name) {
       this.name = name;
    }

    public int getYearsOld() {
       return yearsOld;
    }

    public void setYearsOld(int yearsOld) {
       this.yearsOld = yearsOld;
    }
}حالا شاید بگید خوب اینجا دوتا فیلد هست میایم اینارو با constructor یا با  همون setter , getter یا اصلا یه builder مینویسیم و  میریزیم رو هم ، ولی هر کدوم از این روش ها ایراداتی داره که خودتون بهتر از من میدونید. حالا این کدی که داریم میزنیم هم خیلی خفن نیستا در نهایت میخوایم به dependency برسیم ولی گفتیم از لطف خارج نیست که چنتا کد هم بزنیم .public class CustomObjectMapper {
    public static &lt;S, T&gt; T map(S source, Class&lt;T&gt; targetClass) {
       if (source == null || targetClass == null) {
          throw new IllegalArgumentException(&amp;quotSource and target class must not be null&amp;quot);
       }
       try {
             // ایجاد یک نمونه از کلاس هدف
     T target = targetClass.getDeclaredConstructor().newInstance();

              // دریافت فیلدهای کلاس مبدا
     Field[] sourceFields = source.getClass().getDeclaredFields();

              for (Field sourceField : sourceFields) {
                  sourceField.setAccessible(true); // دسترسی به فیلد خصوصی

       // مقدار فیلد را بخوانید
       Object value = sourceField.get(source);

                  // فیلد هم‌نام را در کلاس هدف پیدا کنید
       Field targetField;
                   try {
                       targetField = targetClass.getDeclaredField(sourceField.getName());
                   } catch (NoSuchFieldException e) {
                        continue; // اگر فیلدی وجود ندارد، به فیلد بعدی بروید
       }
                  targetField.setAccessible(true);
                   
                   // بررسی کنید آیا نوع داده‌ها یکسان است
       if (targetField.getType().isAssignableFrom(sourceField.getType())) {
                            targetField.set(target, value); // مقداردهی به فیلد
       }
          }
          return target;
       } catch (Exception e) {
             throw new RuntimeException(&amp;quotError while mapping objects&amp;quot, e);
       }
    }
}public class Main {
    public static void main(String[] args) {
          Employee employee = new Employee();
          employee.setFullName(&amp;quotJohn Doe&amp;quot);
          employee.setAge(30);

           // Map کردن
    Person person = CustomObjectMapper.map(employee, Person.class);

           // مقداردهی را بررسی کنید
     // خروجی: null (چون نام‌ها متفاوت‌اند)
    System.out.println(
                   &amp;quotName: &amp;quot + person.getName()
            );

          // خروجی: 0 (چون فیلد‌ها هم‌نام نیستند)
           System.out.println(
                 &amp;quotYears Old: &amp;quot + person.getYearsOld()
           ); 
    }
}کدی که زدیم شبیه همون ObjectMapper خود جاواست سعی کردم کامنت فارسی بزارم براتون که راحت درکش کنید . اگر به این خط دقت کنید میبینید که برای مقدار دهی دنبال فیلد های هم نام میگرده و توی مثال ما چون فیلد ها هم نام نیست خطا میخوره و مقادیر خالیه . targetField = targetClass.getDeclaredField(sourceField.getName()); توی این خط هم بررسی میکنه حتما نوع داده فیلد ها هم یکی باشه .if (targetField.getType().isAssignableFrom(sourceField.getType())) {                             
         targetField.set(target, value); // مقداردهی به فیلد        
}پس اگر به این دوتا نکته دقت کنید متوجه میشید که نام فیلد ها و نوع فیلد ها مهمه .البته میشد توی همین reflection بالا هم بیایم یه mapping table ایجاد کنیم و فیلد های غیر هم نام رو هم پیدا کنیم . ولی حی نیاز به کد بیشتر هست. حالا به dependency میرسیم و از این مشکلات خلاص میشید.  :)خوب حالا بریم ببینیم MapStruct چیکار میکنه و چی داره برامون :اول از همه که برای استفاده بیاید dependency که بالا گفتیم رو اضافه کنید.من همیشه عادت دارم بیام annotation ها و متدها رو بگم بعد مثال بزنم و نمیدونم این کار درسته یا نه شاید شما ترجیح بدید که بیام توی یه مثال راجب annotation صحبت کنیم . خلاصه اینکه نظرتون رو بگید.ولی اینجا میام ترکیبی میرم هم توضیح میدم و همونجا مثالش رو میزنم .من چیزایی که باهاش کار کردم رو میگم اگر چیز بیشتری بود بگید اضافه کنم .1- @Mapperاین انوتیشن  یه کلاس یا درواقع یه interface  را به عنوان یک Mapper معرفی می‌کند.باید آن را روی Interface قرار دهیم.چنتا attribute مهم داره که همینجا میگم بهتون :componentModelبرای مدیریت bean ها استفادش میکنیم مثلا اگر از spring استفاده مکنید و مقدارش رو برابر  componentModel = &quot;spring&quot;قرار بدید مشخص میکنه که مدیریت Bean توسط Spring کنترل بشه .چند مقدار دیگه هم میگیره اینجا مینویسم خودتون راجبش بخونید :&quot;default&quot;  &quot;spring&quot;   &quot;cdi&quot;  &quot;jsr330&quot;unmappedTargetPolicyاین مقدار تعیین می‌کند که اگر فیلدی در DTO یا Entity وجود داشت که MapStruct نتوانست مقداردهی کند، چه اتفاقی بیفتد.مثلا من میام میگم فیلدی موجود نبود کامپایلر error بده :unmappedTargetPolicy = ReportingPolicy.ERRORاگر مقدار رو برابر WARN بزارید فقط یه هشدار نمایش میده اگر هم برابر IGNORE باشه هیچ خطا یا هشداری نمیده .importsاین ویژگی برای وارد کردن کلاس‌های خارجی به Mapper استفاده می‌شود.اگر می‌خواهی در متدهای Custom Mapping از کلاس‌هایی استفاده کنی که خارج از این کلاس Mapper هستند، باید آن‌ها را اینجا import کنی.مثالا فرض کنید من میخوام از یه Utils خاصی توی کارم استفاده کنم . @Mapper(componentModel = &quot;spring&quot;, imports = { CustomUtils.class })public interface PaymentMapper {               @Mapping(                 target = &quot;formattedAmount&quot;, expression =                 &quot;java(CustomUtils.valueOf(payment.getAmount()).setScale(100))&quot;       )           PaymentDto toDto(Payment payment); }ناراحت نباشید جولو تر مثال میزنیم یاد میگیرید.2-@Mappingیکی از مهم‌ترین Annotation‌ها در MapStruct است که برای تبدیل فیلدهای یک کلاس به کلاس دیگر استفاده می‌شود.مهم ترین انوتیشن همینه ، خوب بریم attribute هاشو بگیم :Source &amp; Targetدوتا attribute داریم که مکمل همن که معمولا باهم میان target , source :به خط کد زیر توجه کنید :@Mapping(target = &amp;quotname&amp;quot, source = &amp;quotfullName&amp;quot)
Person toPerson(Employee empl);همون طور که متوجه شدید target به فیلد مقصد اشاره دارد و source به فیلد مبدا یا همون فیلد ورودی.ignore:نادیده گرفتن یک فیلد خاص  ، اگر بخواهیم یک فیلد از کلاس مقصد مقداردهی نشود، مقدار ignore = true را تنظیم میکنیم .@Mapper(componentModel = &amp;quotspring&amp;quot) 
public interface PersonMapper {   
    @Mapping(target = &amp;quotyearsOld&amp;quot, ignore = true)   
     Person toPerson(Employee empl); 
}expression:بعضی جاها ممکنه لازم داشته باشید یه فیلد target رو با دستورات جاوا مقدار دهی کنید ، چه میدونم مثلا شاید لازم داشته باشید یه UUID به فیلد userId بدید یا اینکه یه Date یا Systerm.currentTime بدید یه فیلد updated_at و یا مثلا بخواید یه فیلد ورودی رو یه تغییری در لحظه بدید و بعد ذخیره کنید و حالا هرچی ... اینجاست که این attribute به کمکتون میاد.بیاید اول کلاس Person رو یکم ارتقا بدیم :@Setter @Getter
@AllArgsConstructor
@NoArgsConstructor
class Person {     
    private long id;
    private String uuid;

    private String name;     
    private int yearsOld; 
    
    private Boolean enabled;
    private Date date;
}حالا بریم پرش کنیم:@Mapper(componentModel = &amp;quotspring&amp;quot)  
public interface PersonMapper {  
      @Mapping(target = &amp;quotyearsOld&amp;quot, source=&amp;quotempl.age&amp;quot)  
      @Mapping(target = &amp;quotid&amp;quot, ignore= true)
      @Mapping(target = &amp;quotuuid&amp;quot, expression=&amp;quotjava(UUID.randomUUID()&amp;quot)
      @Mapping(target = &amp;quotdate&amp;quot, expression=&amp;quotjava(new Date())&amp;quot)   
      @Mapping(target = &amp;quotname&amp;quot, source=&amp;quotempl.fullName&amp;quot)
      @Mapping(target = &amp;quotenabled&amp;quot,source=&amp;quotenabled&amp;quot)
      Person toPerson(Employee empl, boolean enabled); 
 }اگر دقت کنید میبینید که مقادیر uuid , date رو با استفاده از متدهای جاوا پر کردیم . و همچنین اینکه الان به دلیل اینکه در ورودی متد toPerson دوتا پارامتر داریم بنابر این باید در source مشخص کنیم از کدام پارامتر میخوایم استفاده کنیم .source=&amp;quotempl.fullName&amp;quot 
source=&amp;quotenabled&amp;quotمیتونید در java() بیاید یه validate برای فیلد های خاص بنویسید و خیلی کارهای باحال دیگه و ازین جانگولر بازیا.3- @Namedبرای نام گذاری متد ها استفاده میشه ، نه متد های معمولی متدهایی برای تبدیل ها و بررسی های اختصاصی.خوب حالا یعنی چی :فرض کنید میخواید بعد از اینکه یه source به target تبدیل شد بیایم یه متد سوم رو کال کنیم که بیاد روی نتیجه نهایی یعنی target یه تغییری یا یه بررسی انجام بده .بریم یه مثال ببینیم :قبلش باید یچی دیگه هم توضیح بدم که قاطی نکنید .qualifiedByName به ما اجازه می‌دهد تا یک متد خاص را در @Mapping با qualifiedByName مشخص کنیم و از آن در تبدیل فیلدها استفاده کنیم.دوتا کلاس جدید نیاز داریم :public class User {
     private String name;
     private String email; 
    private String categoryType;  // مقدار اصلی که باید تبدیل شود
}

public class UserDto {
     private String name;
     private String email;
     private String subCategoryType;  // مقدار نهایی بعد از تبدیل
}حالا میخوام مثل قبل یه mapping داشته باشیم و با یه تفاوت که بعد از map شدن بیاد روی category یه کاری انجام بده .@Mapper(componentModel = &amp;quotspring&amp;quot)
public interface UserMapper { 
         
        @Mapping(
               source = &amp;quotcategoryType&amp;quot, 
               target = &amp;quotsubCategoryType&amp;quot, qualifiedByName = &amp;quottoSubCategoryType&amp;quot
         )
        UserDto toDto(User user);
        
      @Named(&amp;quottoSubCategoryType&amp;quot)
      default String toSubCategoryType(String type) {
              if (type == null) return &amp;quotUNKNOWN&amp;quot
              switch (type) {
                           case &amp;quotHOUSE&amp;quot: return &amp;quotReal Estate&amp;quot
                           case &amp;quotCAR&amp;quot: return &amp;quotVehicle&amp;quot 
                           default: return &amp;quotOther&amp;quot 
              } 
      } 
}خوب چه اتفاقی افتاد :وقتی مقدار categoryType به subCategoryType تبدیل و Map میشود. mapStruct میاد متد toSubCategoryType رو صدا میزنه ، این کار باعث میشه پیچیدگی های اضافه کاهش پیدا کنه و کد تمیز تر بشه و یه سری validate شدن هارو میتونیم در متدهای مختلف پیاده سازی کنیم .خوب حالا که این dependecy رو یادگرفتیم ، میشه گفت مزیت هاش اینه که هر فیلدی با هر نامی بود رو میتونید به هم map کنید ، میتونید ignore کنید ، میتونید validator بنویسید  ، میتونید چندین متد mapper بنویسید بین دوتا کلاس  ، میتونید متدهای مجزا بنویسید و استفاده کنید و میتونید از کدها و متدهای جاوا برای مقدار دهی استفاده کنید و ....تا درودی دیگر بدرود.امیدوار لذت برده باشید و براتون مفید بوده باشه .منتظر نگاه های قشنگتون هستم . مراقب خودتون باشید . 🌹🌹</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 01 Feb 2025 12:51:59 +0330</pubDate>
            </item>
                    <item>
                <title>using JUnit5 and Mockito (coding and test)</title>
                <link>https://virgool.io/Javenture/using-junit5-and-mockito-coding-and-test-lotwspa9pb1x</link>
                <description>یه مجموعه آموزش داریم تحت عنوان using JUnit5 and Mockito که اومدیم توی چنتا سرفصل تقسیمش کردیم .این آموزش به دو بخش تقسیم شده مفاهیم کلی تست و مثال ها و انوتیشن ها mockito و junit5. امیدوارم مبحث مفاهیم کلی تست رو خونده باشید ، توی این آموزش میایم انوتیشن ها و متدهایی که قرار توی مثال های این آموزش استفاده کنیم رو توضیح میدیم و بعد هم مثال هامون رو میزنیم .توی این آموزش به موارد زیر میپردازیم :1- متدها و انوتیشن ها. 2- تفاوت و موارد استفاده هر انوتیشن و متدهایی که گفتیم.3- مثال هامون و توضیحاتش:        - یه نمونه تست ساده        - یه نمونه RestApi (میایم از mock برای دیتاهامون و کلاس هامون استفاده میکنیم)      - یه نمونه mock هزارتایی از دیتابیس1- متد ها و انوتیشن ها قبل از اینکه بریم مثال هامون رو بزنیم اول انوتیشن ها و متدهایی که قراره توی این آموزش استفاده کنیم رو بیاریم و بگیم چی هستن .چون خیلی زیاد و طولانی میشه نمیشه همه متدها و انوتیشن هارو بررسی کرد بنابراین میایم چیزایی که معمولا استفاده میشه توی تست ها یا حداقل چیزایی که خودم روزمرره استفاده میکنم رو میارم .برای spring:@WebMvcTest()برای JUnit:@Test@DisplayName@BeforEach@AfterEach@BeforAll@AfterAllassertionMethods(assertThat,assertEqual,...)برای Mockito:@Mock@InjectMocks@Captor@Spygiven()verify()when()doReturn()2- تفاوت و موارد استفاده هر متد و انوتیشن@WebMvcTest()یک annotation در فریم‌ورک Spring Boot است که برای تست کنترلرهای MVC (Model-View-Controller) استفاده می‌شود. این annotation به طور خاص برای تست لایه‌ی وب در برنامه‌های Spring طراحی شده است و امکان تست کنترلرها را به صورت ایزوله فراهم می‌کند. فقط اجزای مربوط به لایه وب (مانند کنترلرها، کنترلرهای exception، فیلترهای MVC، و کانفیگ‌های مرتبط با وب) را بارگذاری کند. این کار باعث می‌شود که تست‌های شما سبک‌تر و سریع‌تر اجرا شوند، زیرا نیازی به بارگذاری کل برنامه Spring ندارید.وقتی از @WebMvcTest استفاده می‌کنید، Spring Boot فقط اجزای ضروری برای تست کنترلرها را بارگذاری می‌کند. این شامل موارد زیر است:کنترلرها (Controller)کنترلرهای استثنا (ControllerAdvice)فیلترهای وبکانفیگ‌های مرتبط با وب (مانند WebMvcConfigurer)MockMvc برای ارسال درخواست‌های HTTP و بررسی پاسخ‌هابه طور پیش‌فرض، @WebMvcTest اجزای دیگری مانند سرویس‌ها، ریپازیتوری‌ها، و سایر لایه‌های برنامه را بارگذاری نمی‌کند. این کار ایزوله‌سازی تست‌ها را تضمین می‌کند و باعث می‌شود که تست‌های شما فقط بر رفتار کنترلر متمرکز شوند.حالا چرا باید ازش استفاده کنیم ، البته بایدی توش نیست میتونید استفاده نکنید راهکار برای تست زیاد هست :تست‌های شما فقط بر کنترلرها متمرکز می‌شوند و وابستگی به سایر لایه‌های برنامه ندارند. این کار باعث می‌شود که تست‌های شما دقیق‌تر و قابل نگهداری‌تر باشند.با بارگذاری نکردن کل برنامه، تست‌ها سریع‌تر اجرا می‌شوند که باعث افزایش بهره‌وری در فرآیند توسعه می‌شود.استفاده از MockMvc نوشتن تست‌ها را بسیار ساده‌تر می‌کند. شما می‌توانید به راحتی درخواست‌ها را شبیه‌سازی کنید و پاسخ‌ها را بررسی کنید.این annotation به شما کمک می‌کند تا تست‌های خود را بر روی لایه وب متمرکز کنید و از صحت کارکرد کنترلرها اطمینان حاصل کنید.@WebMvcTest(PostsController.class) // مشخص کردن کنترلر مورد نظر برای تست 
public class PostsControllerTest { 
        @Autowired 
         private MockMvc mockMvc; 
        @Test 
         public void testGetEndpoint() throws Exception { 
               mockMvc.perform(MockMvcRequestBuilders.get(&amp;quot/api/posts&amp;quot)) .and
         }
}@Test بالا سر هر متد تست باید این انوتیشن رو بزارید و گرنه به عنوان تست اجرا نمیشه.@DisplayNameاین انوتیشن به شما این امکان را می‌دهد که یک نام قابل فهم و توصیفی برای تست‌ها تعیین کنید تا گزارش‌های تست خواناتر و مفهومی‌تر باشند.@BeforEachاین انوتیشن برای اجرای کد قبل از هر تست استفاده می‌شود. کدی که در این متد قرار می‌گیرد، پیش از هر تست اجرا می‌شود.@AfterEach این انوتیشن برای اجرای کد بعد از هر تست استفاده می‌شود. معمولاً برای تمیزکاری‌ها یا بازنشانی داده‌ها کاربرد دارد.@BeforAll این انوتیشن برای اجرای کد قبل از اجرای تمامی تست‌ها استفاده می‌شود و معمولاً برای انجام عملیات‌های سنگین (مانند راه‌اندازی پایگاه داده یا ارتباطات شبکه) به کار می‌رود.@AfterAll مشابه @BeforAll ، این انوتیشن برای کدهایی استفاده می‌شود که باید پس از اجرای تمام تست‌ها اجرا شوند. معمولاً برای آزادسازی منابع یا تمیزکاری‌های عمومی استفاده می‌شود.@Mockاین انوتیشن برای Mock کردن کلاس‌ها و وابستگی‌ها استفاده می‌شود. این انوتیشن به Mockito می‌گوید که یک شی از کلاس هدف ایجاد کند، که رفتار آن قابل شبیه‌سازی باشد. @InjectMocks این انوتیشن به Mockito می‌گوید که وابستگی‌های Mock شده را به صورت خودکار به کلاس هدف  تزریق کند.@Captor این انوتیشن برای تعریف یک کپی از آرگومان‌های ورودی به متدها یا مقادیر خروجی استفاده می‌شود. معمولاً برای بررسی دقیق‌تر پارامترهای ارسال شده به متدهای Mock شده کاربرد دارد.@Spy این انوتیشن برای ایجاد یک Spy (نمونه واقعی) از یک شی استفاده می‌شود. برخلاف Mock، Spy‌ها رفتار واقعی شی را حفظ می‌کنند اما می‌توانند رفتار خاصی را شبیه‌سازی کنند یا تغییر دهند.given() این متد برای شبیه‌سازی رفتار یک شی Mock شده استفاده می‌شود. شما می‌توانید با استفاده از given(...) مشخص کنید که وقتی یک متد خاص فراخوانی می‌شود، چه پاسخی باید داده شود.متد given() بخشی از کتابخانه AssertJ است که شبیه when() عمل می‌کند، اما به خاطر شکل نوشته شدنش خیلی به روان بودن تست و قابل فهم تر شدن تست کمک میکنه .given(myService.performAction()).willReturn(&amp;quotExpected Value&amp;quot);verify() این متد برای تایید اینکه یک متد خاص در Mock فراخوانی شده است یا نه، استفاده می‌شود.when()مشابه given(...) ، این متد برای تعریف رفتار یک Mock به کار می‌رود، اما در نسخه‌های قدیمی‌تر Mockito معمولاً از when(...).thenReturn(...) استفاده می‌شد. در نسخه‌های جدیدتر ماکیتو given بیشتر به کار می‌رود.متد when یک ابزار برای شبیه‌سازی رفتار متدهای اشیاء Mock شماست.زمانی استفاده می‌شود که می‌خواهید بگویید یک متد خاص باید چه مقدار یا چه چیزی را برگرداند.MyService myService = mock(MyService.class); when(myService.performAction()).thenReturn(&amp;quotExpected Value&amp;quot);حالا توی این مثال thenReturn چیکار میکنه :متد thenReturn() به شما این امکان را می‌دهد که مقداری را که باید در پاسخ به یک فراخوانی متد مشخص شده برگشت داده شود، تعریف کنید.doReturn()متد doReturn() مشابه when().thenReturn() است، اما استفاده از آن امکان شبیه‌سازی متدهایی که عوارض جانبی دارند یا متدهایی که void هستند، را نیز فراهم می‌آورد.زمانی استفاده می‌شود که می‌خواهید از متد spy با رفتار واقعی استفاده کنید یا می‌خواهید یک متد void را شبیه‌سازی کنید.doReturn(&amp;quotExpected Value&amp;quot).when(myService).performAction();تفاوت های بعضی از متدها و انوتیشن ها : بعضی هارو که به ذهنم در این لحظه رسید رو میگم .1- فرق بین given و when چیه ؟در Mockito، بین given و when تفاوتی در استفاده وجود دارد، اما هر دو به طور کلی برای تعریف رفتار اشیاء Mock استفاده می‌شوندwhen()به این ساختار دقت کنید :when(mock.someMethod()).thenReturn(someValue);معمولا قدیمی‌تر است و بیشتر در نسخه‌های اولیه Mockito استفاده می‌شد.شما از when برای تعیین آنچه که باید در هنگام فراخوانی یک متد خاص بر روی شی Mock اتفاق بیفتد استفاده می‌کنید.پس از آن، با استفاده از thenReturn یا متد های دیگر موجود ، می‌توانید تعیین کنید که چه مقدار باید برگرداند.given()به این ساختار هم یه نیگا بندازید:given(mock.someMethod()).willReturn(someValue);ساختار جدیدتر و ترجیحی در Mockito است، به ویژه در هنگام استفاده از Mockito با JUnit 5.این روش خیلی قابل فهم تر  و خواناتر ، و این امکان رو میده خیلی راحت تر و ملموس تر ، رفتار Mock ها را تعریف کنیم.از willReturn برای تعیین مقداری که باید هنگام فراخوانی متد برگردانده شود استفاده می‌شود.یه سری تفاوت خیلی مهم دارن :خوانایی:given خیلی خواناتر و برای همه دوولوپر های یک پروژه میتونه راحت تر و قابل فهم تر باشه.when خیلی به given نزدیکه شکل ساختاریش اما چون توی ساختارش بین متد ها یه حالت chain وجود داره یکم پیچیدگی ایجاد میکنه.سازگاری با JUnit 5: given به طور خاص برای سازگاری بهتر با روش‌های مدرن نوشتن تست طراحی شده است و معمولاً در پروژه‌هایی که از JUnit 5 استفاده می‌کنند، ترجیح داده می‌شود.عملکرد:از نظر عملکرد، هیچ تفاوتی در کارایی وجود ندارد. هر دو روش به یک روش مشابه کار می‌کنند و تنها تفاوت در نحوه نوشتن و خوانایی کد است.در نهایت، انتخاب بین given و when بستگی به سلیقه شخصی شما و تیم توسعه دارد. اگر می‌خواهید به کدی با خوانایی بیشتر نزدیک شوید، ممکن است given را ترجیح دهید. با این حال، برای اکثر تست‌ها هر دو روش به خوبی کار میکنه .2- فرق بین spy و mock چیه ؟Mockتعریف: Mock به شما این امکان را می‌دهد که یک شی از یک کلاس را شبیه‌سازی کنید. زمانی که از Mock استفاده می‌کنید، رفتار کلاس اصلی شبیه‌سازی شده و شما می‌توانید کنترل کاملی بر روی آن داشته باشید. Mock تمام متدهای کلاس را به‌طور پیش‌فرض بدون پیاده‌سازی واقعی آن‌ها در نظر می‌گیرد و شما می‌توانید با استفاده از روش‌هایی مانند when یا given رفتار موردنظر خود را تعیین کنید.شما با استفاده از mock چیزی شبیه‌سازی می‌کنید، یعنی وابستگی های یک کلاس یا یک شی به طور کامل پیاده سازی نشده و همه چیز فیک هست . این به معنای این است که هیچ رفتاری واقعی در کلاس وجود نداره ، مگر اینکه صراحتاً آن را تعریف کنید.کاربرد:Mock برای تست کردن کد بدون نیاز به اجرای واقعی متدهای موجود در کلاس اصلی استفاده می‌شود. در mock، هیچ پیاده‌سازی از متدها وجود ندارد مگر اینکه آنها را شبیه‌سازی کنید.این به شما اجازه می‌دهد تا وابستگی‌ها را شبیه‌سازی کنید و وابستگی‌هایی که اثر جانبی دارند (مانند دیتابیس و یا شبکه) را نادیده بگیرید.@Mock
private MyService myService;

when(myService.performAction()).thenReturn(expectedValue);Spyتعریف: Spy به شما این امکان را می‌دهد که یک شی واقعی از یک کلاس ایجاد کنید و بر روی آن کنترل داشته باشید. در حقیقت، Spy یک نمونه واقعی از کلاس است که می‌توانید برخی از متدهای آن را شبیه‌سازی کنید، در حالی که متدهای دیگر آن همچنان رفتار واقعی خود را حفظ می‌کنند. با استفاده از spy شما از یک شیء واقعی استفاده می‌کنید، به این معنی که بسیاری از رفتارهای واقعی آن حفظ می‌شود. شما می‌توانید متدها را شبیه‌سازی کنید یا به رفتار واقعی شیء رو داشته باشید.کاربرد:Spy زمانی کاربرد دارد که می‌خواهید بخشی از رفتار کلاس اصلی را تغییر دهید یا شبیه‌سازی کنید، اما در عین حال می‌خواهید به عملکرد طبیعی سایر متدها دسترسی داشته باشید. در spy، می‌توانید متدها را به صورت واقعی اجرا کرده و فقط برخی از آنها را شبیه‌سازی کنید. spy ممکن است کمی کندتر باشد چون میاد متد های واقعی رو هم اجرا میکنه .بسیار مفید است زمانی که برخی از متدها خاص هستند و نیاز به آزمایش واقعی آن‌ها دارید.@Spy
private MyService myService = new MyServiceImpl();

// شما می‌توانید بخشی از رفتار را شبیه‌سازی کنید
doReturn(mockedValue).when(myService).someMethod();تفاوت‌های کلیدی بین Mock و Spyرفتار:Mock: تمام متدها به‌طور پیش‌فرض شبیه‌سازی شده و هیچ‌گونه رفتار واقعی ندارند تا زمانی که شما به صراحت آن‌ها را تعریف کنید.Spy: متدها رفتار واقعی خود را دارند، مگر اینکه شما خاصاً بخواهید که برخی از آن‌ها شبیه‌سازی (Mock) شوند.موارد استفاده:Mock: برای زمانی که می‌خواهید تنها بر روی رفتار یک وابستگی تمرکز کنید و به اجرا و خروجی‌های واقعی آن نیاز ندارید.Spy: برای زمانی که نیاز به آزمایش رفتار واقعی برخی از متدهای یک کلاس دارید، اما می‌خواهید که دیگر متدها را شبیه‌سازی کنید.ایجاد شی:Mock: به سادگی یک شی Mock شده ایجاد می‌شود.Spy: شما باید از یک شی واقعی (نمونه) استفاده کنید و برای Spy آن را به‌عنوان شی اصلی قرار دهید.تست رفتارهای پیچیده:اگر شما بخواهید فقط برخی از متدها را شبیه‌سازی کنید و بقیه رفتارهای واقعی را حفظ کنید، از spy استفاده کنید.اگر شما به طور کامل بخواهید کلاس را شبیه‌سازی کنید و به رفتار واقعی آن نیازی ندارید، mock گزینه بهتری است.خلاصهMock: برای ایجاد رفتار خاص و شبیه‌سازی وابستگی‌ها استفاده می‌شود. هیچ جزئیاتی از رفتار واقعی نخواهد داشت.Spy: از یک شی واقعی بهره می‌گیرد و می‌توانید رفتار برخی از متدها را شبیه‌سازی کرده و بقیه را به‌صورت واقعی اجرا کند.استفاده از mock و spy به موقعیت و نیاز شما بستگی دارد. اگر نیاز دارید که یک رفتار خاص را به‌طور کامل شبیه‌سازی کنید، از mock استفاده کنید. اما اگر بخواهید در کنار شبیه‌سازی، از عملکرد واقعی شیء نیز بهره ببرید، spy گزینه مناسب‌تری است.3- مثال ها - یه نمونه تست سادهاول کار بیاید این dependency هارو اضافه کنید :&lt;!-- already added by Spring Initializr--&gt; 
&lt;dependency&gt; 
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; 
    &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
    &lt;scope&gt;test&lt;/scope&gt; 
&lt;/dependency&gt; 

&lt;!-- add JUnit5 (Jupiter) --&gt; 
&lt;dependency&gt; 
    &lt;groupId&gt;org.junit.jupiter&lt;/groupId&gt; 
    &lt;artifactId&gt;junit-jupiter-engine&lt;/artifactId&gt;
    &lt;scope&gt;test&lt;/scope&gt; 
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;org.junit.jupiter&lt;/groupId&gt;
   &lt;artifactId&gt;junit-jupiter-api&lt;/artifactId&gt;
   &lt;version&gt;5.7.1&lt;/version&gt;
   &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;

 &lt;!-- add Mockito --&gt;
 &lt;dependency&gt; 
    &lt;groupId&gt;org.mockito&lt;/groupId&gt; 
    &lt;artifactId&gt;mockito-core&lt;/artifactId&gt;
    &lt;scope&gt;test&lt;/scope&gt; 
&lt;/dependency&gt;
میخوایم مثل همه جاهای دیگه ما هم یه متد بیاریم که یه عمل جمع رو انجام میده و بعد تستش کنیم :public class Calculator {   
      public int add(int a, int b) { 
            return a + b;     
       } 
}حالا بیایم تست رو بنویسیم :import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; 
public class CalculatorTest { 
    @Test
     public void testAdd() { 
           Calculator calculator = new Calculator(); 
            int result = calculator.add(2, 3); 
            assertEquals(5, result, &amp;quot2 + 3 should equal 5&amp;quot); 
      } 
}شرح کاری که کردیم :1- انوتیشن @Test :  نشان‌دهنده این است که این متد یک تست است. 2- متد assertEquals(expected, actual) : برای مقایسه‌ی مقدار مورد انتظار (expected) و مقدار واقعی (actual) استفاده می‌شود.3-  پیام &quot;2 + 3 should equal 5&quot; در صورتی که تست شکست بخورد، نمایش داده می‌شود.در JUnit انواع مختلفی از assertions برای بررسی شرایط مختلف داریم:assertEquals(expected, actual): بررسی می‌کند که مقادیر برابر باشندassertTrue(condition): بررسی می‌کند که شرط صحیح باشدassertFalse(condition): بررسی می‌کند که شرط غلط باشدassertNotNull(object): بررسی می‌کند که شیء نال نباشدassertNull(object): بررسی می‌کند که شیء نال باشدحالا یکم متد رو پیچیده ترش کنیم :public class Calculator {
    public int divide(int a, int b) {
        if (b == 0) { 
           throw new ArithmeticException(&amp;quotCannot divide by zero&amp;quot); 
        }
        return a / b; 
     } 
}بریم تستش کنیم :import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*; 
public class CalculatorTest { 
    @Test 
    public void testDivide() { 
         Calculator calculator = new Calculator(); 
         int result = calculator.divide(10, 2); 
         assertEquals(5, result, &amp;quot10 / 2 should equal 5&amp;quot); 
    } 
    @Test 
    public void testDivideByZero() { 
         Calculator calculator = new Calculator(); 
         ArithmeticException exception = assertThrows(ArithmeticException.class, () -&gt; { 
            calculator.divide(10, 0);
          }); 
         assertEquals(&amp;quotCannot divide by zero&amp;quot, exception.getMessage()); 
     } 
}خوب توی این تست نیاز داریم exception رو در صورت اتفاق افتادن بررسی کنیم بنابراین در متد testDivideByZero از assertThrows استفاده می‌کنیم تا اطمینان حاصل کنیم که در صورتی که بخواهیم تقسیم بر صفر انجام دهیم، استثنای ArithmeticException پرتاب می‌شود.حالا بیایم یکم تست هامون رو تمیز تر و خواناترش کنیم :توی تست های بالا دیدید که برای ایجاد یک نمونه از  Calculator اومدیم داخل متد تستمون به ازای هر متد تست یه بار instance ساختیم . این کار مشکلی نداره اما اگر قرار باشه چندین متد تست داشته باشیم که بخوایم توی هر کدوم از متد های یک instance از این کلاس داشته باشیم اونوقت زیاد جالب نیست . حالا باید چیکار کنیم : در تست های گروهی میشه از after و before استفاده کرد import org.junit.jupiter.api.*; 

public class CalculatorTest { 
    private Calculator calculator; 
    
     @BeforeEach 
     public void setUp() { 
         calculator = new Calculator(); 
      } 

     @Test
      public void testAdd() { 
           int result = calculator.add(2, 3);
           assertEquals(5, result); 
       } 

      @AfterEach 
       public void tearDown() {
             // عملیات پاکسازی، اگر نیاز باشد 
        } 
}یکم جولو تر از mock استفاده میکنیم و روال یکم پیچیده تر میشه . (برای تست‌های پیچیده‌تر که نیاز به تعامل با پایگاه‌داده‌ها، APIها یا سرویس‌های خارجی دارند. )لطفا تست هارو خیلی سختش نکنید . موقع تست شلکس کنید .هر تست باید مستقل از دیگر تست‌ها و تغییرات یک تست نباید بر تست‌های دیگه تأثیر بگذارد.سعی کنید تمام قسمت‌های مهم کد تحت پوشش بیمه حضرت تست قرار بدید.اگر اینجا میخواستیم از mock استفاده کنیم چیطور میشد :import static org.mockito.Mockito.*; 
import org.junit.jupiter.api.Test; 

public class CalculatorServiceTest { 
     @Test 
      public void testCalculateWithMock() { 
           Calculator calculator = mock(Calculator.class); 
           when(calculator.add(2, 3)).thenReturn(5);
           int result = calculator.add(2, 3); 
           assertEquals(5, result); 
      }
} - یه نمونه RestApi (میایم از mock برای دیتاهامون و کلاس هامون استفاده میکنیم) میخوایم یه controller بنویسیم که اطلاعات کاربر رو توی یه api خیلی ساده دریافت و ذخیره میکنه . توی این تیکه کدی که میزنیم لایه سرویس هم داریم که طبیعتا توی لایه سرویس ریپازیتوری داریم و ...@RestController 
@RequestMapping(&amp;quot/user/profile&amp;quot) 
public class UserProfileController { 
     @Autowired 
     private UserProfileService userProfileService; 
     
     @PostMapping 
     public UserProfile createUser(@RequestBody UserProfile user){ 
             return userProfileService.addUser(user); 
     } 
     
     @GetMapping 
     public List&lt;UserProfile&gt; findAllUsers(){ 
           return userProfileService.findAllUsers(); 
     } 
}خوب همه چیز فکر کنم مشخص باشه حالا بریم تست رو بنویسیم :@ExtendWith(MockitoExtension.class)
public class UserProfileControllerTest {
    @InjectMocks
    private UserProfileController userProfileController;

    @Mock
    private UserProfileService userProfileService;

    @DisplayName(&amp;quotTest - Insert New userProfile - test without exception&amp;quot)
    @Test
    public void insertNewUserProfile(){
        UserProfile user = new UserProfile();
        user.setId(1);
        user.setFirstName(&amp;quotmehrdad&amp;quot);
        user.setLastName(&amp;quotkhanzadi&amp;quot);
        user.phoneNumber(&amp;quot09120909090&amp;quot)

        given(userProfileController.createUser(user)).willReturn(user);

        UserProfile userProfile = userProfileController.createUser(user);

       assertThat(userProfile.getId()).isEqualTo(user.getId());
       assertThat(userProfile.getFirstName()).isEqualTo(user.getFirstName());
       assertThat(userProfile.getLastName()).isEqualTo(user.getLastName());
       assertThat(userProfile.getPhoneNumber()).isEqualTo(user.getPhoneNumber());
    }

    @DisplayName(&amp;quotTest - findAll and getAll userProfiles - test without exception&amp;quot)
    @Test
    public void findAllData(){
        UserProfile firstUser = new UserProfile();
        firstUser.setId(1);
        firstUser.setFirstName(&amp;quotmehrdad&amp;quot); 
        firstUser.setLastName(&amp;quotkhanzadi&amp;quot);  
        firstUser.phoneNumber(&amp;quot09120909090&amp;quot)

        UserProfile secondUser = new UserProfile();
        secondUser.setId(2);
        secondUser.setFirstName(&amp;quotsadegh&amp;quot); 
        secondUser.setLastName(&amp;quotkhanzadi&amp;quot); 
        secondUser.phoneNumber(&amp;quot09126959493&amp;quot)

        List&lt;UserProfile&gt; users = new ArrayList&lt;&gt;;
        users.add(firstUser);
        users.add(secondUser)

       given(userProfileController.findAllData()).willReturn(allPosts);

       List&lt;UserProfile&gt; results = postController.findAllUsers();
       assertThat(results).hasSize(2);

        users.stream.forEach(R -&gt; {
           assertThat(R.getFirstName()).isEqualTo(&amp;quotmehrdad&amp;quot);
           assertThat(R.getPhoneNumber()).isEqualTo(&amp;quot09030909090&amp;quot);
        });
    }
}@ExtendWith(MockitoExtension.class) در نسخه‌های جدید JUnit (JUnit 5) برای اتصال Mockito به سیستم تست JUnit استفاده می‌شود. این انوتیشن به صورت خودکار mock‌ها را ایجاد کرده و تزریق می‌کند، به طوری که نیاز به انجام تنظیمات دستی نیست.@InjectMocksاین انوتیشن یک نمونه از کلاسی که شما در حال تست آن هستید ایجاد می‌کند و mock‌هایی که با انوتیشن @Mock مشخص شده‌اند را به صورت خودکار در آن تزریق می‌کند. در واقع، @InjectMocks به Mockito می‌گوید که تمام mock‌های ساخته شده باید به این کلاس تزریق شوند تا به‌طور خودکار تست‌ها را بر اساس نیاز شما انجام دهد.@Mockاین انوتیشن برای ایجاد پیاده‌سازی mock برای کلاس‌ها یا وابستگی‌هایی که در تست به آن‌ها نیاز دارید استفاده می‌شود. به عبارت ساده‌تر، هر زمانی که شما نیاز به شبیه‌سازی یک شیء از کلاس خاصی برای تست دارید، از این انوتیشن استفاده می‌کنید. @Mock به Mockito می‌گوید که یک نسخه جعلی از این کلاس بسازد که بتوانید رفتار آن را کنترل و بررسی کنید.نکته : دوستان این روش تست برای restApi هامون خوبه ولی خیلی جاها میبینید که با استفاده از متد های موجود در controller میان و تست رو انجام میدن اینجا هم ما از  userProfileController استفاده کردیم و یه ماک ساختیم ازش :@InjectMocks private UserProfileController userProfileController;حالا میرید یه جایی میبینید به جای اینکه بیان unit by unit تست کنن میان integration test انجام میدن و این بستگی به جنس کاری شما داره ، یه جایی لازم دارید کل روال کار با صدا زدن یه سرویس تا انتهای ذخیره سازی توی دیتابیس پیش بره و جواب صحیح و یا خطا برگشت داده بشه ، میشه به صورت container بیایم با docker در زمان test دیتابیس و کش و ... رو بیاریم بالا و تست هارو بزنیم وقتی تست تمام شد container دیتابیس و ... بسته میشه و دوشواری هم نداریم . (مبحث integrationTest رو توی یه آموزش دیگه باید بررسی کنیم)-یه نمونه mock هزارتایی از دیتابیس:خوب اول بیایم برای مثال قبل که زدیم برای تست repository یه مدل تست بریم :لایه repository:public interface UserProfileRepository extend JpaRepository&lt;User,Long&gt; { 
       User findById(Long userId); 
}لایه service:@Service 
public class UserProfileService { 
       private final UserProfileRepository userRepository; 
      
        @Autowired 
        public UserService(UserProfileRepository userRepository) { 
               this.userRepository = userRepository; 
        }
 
        public UserProfile getUserById(Long userId) { 
             return userRepository.findById(userId).convertToDto(); 
        } 
}بریم تستش رو داشته باشیم :import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class UserServiceTest {

    @Mock
     UserProfileRepository userRepository;
   
    @InjectMocks
    UserProfileService userService;
 
    @BeforeEach
    public setUp() {
      MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testGetUserById() {
      User mockUser = new User(1L, &amp;quotSadegh&amp;quot, &amp;quotKhanzadi&amp;quot, &amp;quot09030909090&amp;quot);
      
      when(userRepository.findById(1L)).thenReturn(mockUser);
      UserProfile user = userService.getUserById(1L);
      assertThat(user.getFirstName()).isEqualTo(&amp;quotSadegh&amp;quot);
    }
}
اگر دقت کنید این بالا یدونه دیتا داشتیم حالا اگر بخوایم 1000 تا user داشته باشیم چی میشه ؟؟خودتونم میتونید راهکار داشته باشیدا این راهکار منه public class UserServiceTest {

    @Mock
    UserProfileRepository userRepository;

    @InjectMocks
    UserProfileService userService;

    @BeforeEach
    public void setUp() {
       MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testGetUserByIdWithMultipleUsers() {
       List&lt;User&gt; mockUsers = TestDataGenerator.generateUserList(1000);

       when(userRepository.findById(500L)).thenReturn(mockUsers.get(499)); // کاربر شماره 500

       UserProfile user = userService.getUserById(500L);
       assertEquals(&amp;quotUser 500&amp;quot, user.getName());
    }

    public static List&lt;User&gt; generateUserList(int count) { 
          List&lt;User&gt; users = new ArrayList&lt;&gt;(); 
          for (int i = 1; i &lt;= count; i++) {      
               users.add(new User((long) i, &amp;quotUser &amp;quot + i));     
           }       
           return users;   
      }
}
متد generateUserList میاد 1000 تا کاربر میسازه اول کار و بعد کار با اون 1000 کاربر پیش میره.امیدوارم راضی بوده باشید تلاش میکنم در یه آموزش جدا بیام InegrationTest رو توضیح بدم .با تشکر از نگاه های زیباتون .</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 04 Jan 2025 12:02:05 +0330</pubDate>
            </item>
                    <item>
                <title>using JUnit5 and Mockito (مفاهیم کلی تست)</title>
                <link>https://virgool.io/Javenture/using-junit5-and-mockito-%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85-%DA%A9%D9%84%DB%8C-%D8%AA%D8%B3%D8%AA-c6dtsoj8r5wk</link>
                <description>یه مجموعه آموزش داریم تحت عنوان using JUnit5 and Mockito که اومدیم توی چنتا سرفصل تقسیمش کردیم .این آموزش به دو بخش تقسیم شده مفاهیم کلی تست و مثال ها و انوتیشن ها mocito و junit5 .این آموزش رو با توضیحات حوصله سربر انواع تست و کلیات شروع میکنیم و برای ادامه به آموزش مثال ها و انوتیشن ها mocito و junit5 برید و  با قدرت ادامه بدید.انواع تست در مهندسی نرم افزارتست‌نویسی یکی از بخش‌های حیاتی در فرآیند توسعه نرم‌افزار است که به شما کمک می‌کند تا اطمینان حاصل کنید که کد به درستی کار می‌کند. انواع مختلفی از تست‌ها برای سنجش بخش‌های مختلف نرم‌افزار وجود دارد که هرکدام هدف خاص خود را دارند و در مراحل مختلف فرآیند توسعه استفاده می‌شوند.تست‌های واحد (Unit Testing)تست‌های یکپارچگی (Integration Testing)تست‌های سیستم (System Testing)تست‌های پذیرش (Acceptance Testing)تست‌های رابط کاربری (UI Testing)تست‌های امنیتی (Security Testing)تست‌های عملکردی (Performance Testing)تست‌های استرس (Stress Testing)تست‌های رگرسیونی (Regression Testing)تست‌های قابلیتشناسی (Usability Testing)یه موارد هم مثل TDD , BDD , ATDD , ... داریم که مختصر یه توضیح میدمتست‌های واحد (Unit Testing) :  ما با این کار داریمتوضیح:تست واحد، پایه‌ای‌ترین نوع تست است که به بررسی یک واحد کوچک از برنامه (معمولاً یک متد یا کلاس) می‌پردازد. هدف این است که مطمئن شویم هر واحد به درستی و مطابق با انتظار عمل می‌کند.ویژگی‌ها:محدوده تست: یک بخش کوچک از کد، مانند یک متد.ابزارهای متداول: JUnit (برای جاوا)هدف: شبیه‌سازی شرایط مختلف و بررسی اینکه آیا کد تحت شرایط مختلف به درستی عمل می‌کند یا خیر.مثال:فرض کنید یک متد add در کلاسی به نام calculator داریم. تست واحد این متد بررسی می‌کند که آیا جمع دو عدد به درستی انجام می‌شود یا نه.تست‌های یکپارچگی (Integration Testing)توضیح:تست‌های یکپارچگی برای بررسی تعاملات بین چند واحد مختلف (کلاس‌ها یا ماژول‌ها) به کار می‌روند. این تست‌ها به شما کمک می‌کنند که مطمئن شوید اجزای مختلف سیستم به درستی با هم کار می‌کنند.ویژگی‌ها:محدوده تست: چند واحد یا ماژول که با هم تعامل دارند.ابزارهای متداول: JUnit, TestNG، و ابزارهای خاص مانند Spring Test برای فریم‌ورک‌های مبتنی بر Spring.هدف: بررسی اینکه آیا تعاملات بین اجزای مختلف (مانند پایگاه داده، سرویس‌ها، APIها) به درستی کار می‌کنند یا خیر.مثال:فرض کنید یک سرویس وب دارید که برای انجام عملیات‌های پیچیده از چندین ماژول استفاده می‌کند. تست یکپارچگی بررسی می‌کند که آیا این ماژول‌ها به درستی و بدون مشکل با هم ارتباط برقرار می‌کنند.ما الان توی پروژه ای که داریم برای تست یه docker به صورتی اتومات کانفیگ شده که با استارت کردن یه تست ، container های داکر جهت تست اجرا میشن (redis , mysql , ...) و بعد از پایان هر متد تست ، بسته به کانفیگمون container ها بسته و container های جدید اجرا میشن. تست‌های سیستم (System Testing)توضیح:تست سیستم به طور کلی بررسی می‌کند که آیا سیستم به طور کلی به درستی کار می‌کند یا خیر. این تست‌ها معمولاً بعد از انجام تست‌های واحد و یکپارچگی انجام می‌شوند و تمام عملکرد سیستم را ارزیابی می‌کنند.ویژگی‌ها:محدوده تست: کل سیستم نرم‌افزاری که شامل تمام اجزا و زیرسیستم‌ها می‌شود.ابزارهای متداول: تست‌های دستی یا خودکار با استفاده از ابزارهایی مانند Selenium، JMeter و یه سری از شرکت ها پول ندارن تستر بگیرن یه تعداد نفر رو گذاشتن با postman سرویس هارو کال میکنن .هدف: ارزیابی عملکرد کلی سیستم از نظر عملکرد، امنیت، و تطابق با نیازمندی‌ها.مثال:در تست سیستم ممکن است تست کنید که آیا تمامی ویژگی‌های اپلیکیشن وب، از جمله ثبت‌نام کاربر، جستجو، و پرداخت، به درستی و بدون اشکال کار می‌کنند یا خیر.تست‌های پذیرش (Acceptance Testing)توضیح:تست پذیرش بررسی می‌کند که آیا نرم‌افزار یا ویژگی خاص مطابق با نیازمندی‌های تجاری و خواسته‌های کاربر نهایی عمل می‌کند یا خیر. این نوع تست معمولاً توسط تیم‌های QA یا حتی خود مشتری انجام می‌شود.ویژگی‌ها:محدوده تست: ارزیابی تطابق نرم‌افزار با نیازمندی‌ها و خواسته‌های کاربر.ابزارهای متداول: Cucumber، FitNesse، SpecFlow (برای BDD).هدف: اطمینان از اینکه نرم‌افزار تمام نیازهای تجاری و عملکردی را برآورده می‌کند.مثال:اگر پروژه‌ای برای فروش آنلاین محصولات انجام داده‌اید، تست پذیرش می‌تواند شامل بررسی این باشد که آیا مشتری می‌تواند به درستی محصولی را جستجو ، آن را به سبد خرید اضافه کند و پرداخت را انجام دهد.تست‌های رابط کاربری (UI Testing)توضیح:تست‌های رابط کاربری به بررسی تعاملات کاربر با اپلیکیشن می‌پردازند. این تست‌ها به شما کمک می‌کنند تا اطمینان حاصل کنید که رابط کاربری (UI) به درستی و طبق انتظارات کاربر عمل می‌کند.ویژگی‌ها:محدوده تست: قسمت‌هایی از سیستم که مستقیماً با کاربر تعامل دارند (مانند فرم‌ها، دکمه‌ها، منوها).ابزارهای متداول: Selenium, Appium, Cypress.هدف: بررسی درست بودن نمایش و عملکرد رابط کاربری در شرایط مختلف.مثال:تست UI می‌تواند شامل بررسی این باشد که آیا فرم ثبت‌نام به درستی نمایش داده می‌شود و کاربر می‌تواند بدون هیچ مشکلی فرم را پر کند و ارسال کند.تست‌های امنیتی (Security Testing)توضیح:تست‌های امنیتی به بررسی آسیب‌پذیری‌های نرم‌افزار و تهدیدات امنیتی می‌پردازند. این تست‌ها به‌ویژه در اپلیکیشن‌های حساس و سیستم‌هایی که داده‌های حساس را پردازش می‌کنند، اهمیت دارند.ویژگی‌ها:محدوده تست: آسیب‌پذیری‌های امنیتی مانند  SQL Injection، حملات XSS، حملات CSRF و سایر تهدیدات.ابزارهای متداول: OWASP ZAP, Burp Suite.هدف: ارزیابی امنیت سیستم و پیدا کردن آسیب‌پذیری‌های ممکن.مثال:تست امنیتی ممکن است شامل بررسی این باشد که آیا یک فرم ورودی در وب‌سایت در برابر حملات  SQL Injection محافظت شده است یا خیر.تست‌های عملکردی (Performance Testing)توضیح:تست‌های عملکردی برای ارزیابی عملکرد سیستم تحت شرایط مختلف، مانند بار زیاد یا استفاده طولانی‌مدت، انجام می‌شوند. این تست‌ها به شما کمک می‌کنند تا مطمئن شوید که سیستم توانایی مدیریت بار و عملکرد مطلوب را دارد.ویژگی‌ها:محدوده تست: عملکرد کلی سیستم مانند زمان پاسخگویی، مصرف منابع، و مقیاس‌پذیری.ابزارهای متداول: JMeter, Gatling, LoadRunner.هدف: بررسی اینکه آیا سیستم تحت فشارهای مختلف قادر به حفظ عملکرد خود است یا خیر.مثال:تست عملکردی می‌تواند شامل بررسی این باشد که آیا وب‌سایت قادر به مدیریت 1000 کاربر همزمان بدون کاهش سرعت یا خرابی است یا خیر.تست‌های استرس (Stress Testing)توضیح:تست استرس به طور خاص برای بررسی سیستم تحت فشار و شرایط غیرعادی طراحی می‌شود. هدف آن سنجش این است که سیستم تا چه حد می‌تواند از بار اضافی بدون خرابی پشتیبانی کند.ویژگی‌ها:محدوده تست: بار غیرمعمول و شرایط فشار بالا.ابزارهای متداول: JMeter, LoadRunner.هدف: شبیه‌سازی شرایط بحرانی و بررسی اینکه آیا سیستم می‌تواند عملکرد خود را حفظ کند یا خیر.مثال:تست استرس ممکن است شامل شبیه‌سازی تعداد بسیار زیادی درخواست همزمان به یک وب‌سایت باشد تا عملکرد آن تحت فشار شدید بررسیتست‌های رگرسیونی (Regression Testing)توضیح:تست رگرسیونی به بررسی این می‌پردازد که آیا تغییرات جدید در کد باعث ایجاد مشکلات یا خرابی در بخش‌های قبلی نرم‌افزار شده است یا خیر.ویژگی‌ها:محدوده تست: بررسی تاثیر تغییرات جدید بر بخش‌های مختلف نرم‌افزار.ابزارهای متداول: JUnit، Selenium.هدف: اطمینان از اینکه هیچ یک از ویژگی‌های موجود تحت تاثیر تغییرات جدید قرار نگرفته است.مثال:اگر به کد یک اپلیکیشن تغییراتی اضافه کنید، تست رگرسیونی بررسی می‌کند که آیا ویژگی‌های قدیمی مانند ورود به سیستم یا ارسال ایمیل‌ها هنوز به درستی کار می‌کنند یا خیر.تست‌های قابلیتشناسی (Usability Testing)توضیح:تست‌های قابلیتشناسی به بررسی اینکه آیا استفاده از نرم‌افزار برای کاربر نهایی راحت و منطقی است یا خیر می‌پردازند. این تست‌ها معمولاً از کاربران واقعی یا نمایندگان کاربران انجام می‌شوند.ویژگی‌ها:محدوده تست: بررسی تجربه کاربری و قابلیت استفاده.ابزارهای متداول: تست‌های دستی یا خودکار.هدف: اطمینان از اینکه رابط کاربری و تجربه کاربری بهینه هستند.حالا بگیم که BDD , TDD , ATDD چیهتوسعه نرم‌افزار تحت مفهومی به نام «توسعه مبتنی بر تست» (Test-Driven Development) و «توسعه مبتنی بر رفتار» (Behavior-Driven Development) می‌تواند به تضمین کیفیت نرم‌افزار کمک کند. علاوه بر این دو، روش‌های دیگری نیز وجود دارند که می‌توانند در فرآیند توسعه نرم‌افزار مورد استفاده قرار گیرند. (من همین سه مورد رو بلد بودم ممکنه موارد دیگه هم وجود داشته باشه پس خودتون سرچ بزنید)Test-Driven Development (TDD)تعریفیک روش توسعه نرم‌افزار است که بر اساس نوشتن تست‌های خودکار قبل از نوشتن کد اصلی تاکید دارد. فرآیند معمول TDD شامل مراحل زیر است:نوشتن تست جدید: ابتدا یک تست کوچک و خاص برای عملکردی که قصد اضافه کردن آن به نرم‌افزار را دارید، بنویسید. این تست باید در ابتدا رد شود چون هنوز کدی برای آن ویژگی نوشته نشده است.نوشتن کد: اکنون کدی بنویسید که تست را پاس کند. در این مرحله تمرکز باید فقط بر پاس کردن تست باشد و نه بهینه‌سازی.بازبینی کد (Refactor): بهبود کد برای اطمینان از بهینه بودن آن از نظر عملکرد و خوانایی، بدون تغییر رفتار آن.تکرار مراحل: این چرخه برای هر ویژگی جدید یا رفع باگ تکرار می‌شود.مزایااطمینان از کار کردن صحیح ویژگی‌های نرم‌افزار از ابتدا.تشویق به طراحی مناسب و ماژولار.مستندسازی خودکار ویژگی‌ها و کد.Behavior-Driven Development (BDD)تعریفتکامل یافته TDD است که بر رفتار نرم‌افزار از دید کاربر تمرکز می‌کند. در این روش، تست‌ها به شکل قابل درک و فهم برای همه اعضای تیم ، از جمله توسعه‌دهندگان، تست‌کنندگان، و مدیران پروژه نوشته میشه .فرآیندبر اساس یه سناریو معمولا پیش میره که چنتا step میتونه داشته باشه ،  که معمولاً یه قالب کلی داره :Given: شرایط اولیه یا پیش‌نیازهایی که باید قبل از اجرای رفتار مهیا شوند.When: اتفاق یا عملی که برای بررسی رفتار رخ می‌دهد.Then: نتیجه‌ای که پس از وقوع عمل انتظار می‌رود.مزایاایجاد ارتباط بهتر بین تمام اعضای پروژه .مشخص کردن دقیق رفتار مورد انتظار سیستم.Acceptance Test-Driven Development (ATDD)مشابه BDD، اما تمرکز بیشتری بر پذیرش کلی نرم‌افزار دارد. در این روش، تست‌های قبل از توسعه ویژگی‌ها نوشته می‌شوند و دیدگاه تمام اعضای یک پروژه را منعکس می‌کنند.مفهوم MOCK : (توی آموزش بعدی کدش رو میزاریم)حالا mock چیه :  Mocking یا شبیه‌سازی یکی از مفاهیم مهم در تست‌نویسی است که به شما کمک می‌کند برای بخش‌هایی از سیستم که نمی‌خواهید در تست‌ها به طور واقعی اجرا شوند، نسخه‌های جعلی (mock) ایجاد کنید. این کار برای تست‌های واحد (Unit Testing) و تست‌های یکپارچگی (Integration Testing) ضروری است، به‌خصوص زمانی که بخش‌هایی از سیستم وابستگی به منابع خارجی مانند پایگاه‌داده‌ها، APIها، یا سرویس‌های دیگر دارند.چرا نیاز به Mocking داریم؟در تست‌نویسی، معمولاً نمی‌خواهیم تمام اجزای سیستم را در یک زمان تست کنیم، زیرا این کار می‌تواند تست را پیچیده و زمان‌بر کند. به علاوه، ممکن است در برخی شرایط مانند:وابستگی به پایگاه‌داده‌ها  (که ممکن است داده‌ها در آن تغییر کنند یا دسترسی به آن دشوار باشد).فراخوانی سرویس‌های خارجی (APIها یا وب‌سرویس‌ها) که سرعت یا هزینه زیادی دارند.نیاز به شبیه‌سازی رفتارهایی که به سختی می‌توان آن‌ها را تحت کنترل قرار داد (مثلاً زمانی که یک سرویس از بیرون خطا می‌دهد).در چنین مواردی، می‌توانیم از Mocking استفاده کنیم تا تنها بخش‌های موردنظر سیستم را تست کنیم و رفتار سایر بخش‌ها را شبیه‌سازی نماییم.  1. ابزارهای Mocking در جاوادر جاوا، چندین کتابخانه برای mocking وجود دارد که از رایج‌ترین آن‌ها می‌توان به Mockito و EasyMock اشاره کرد. در اینجا به توضیح مختصر از Mockito می‌پردازیم که یکی از محبوب‌ترین ابزارهای mocking است.1.1. Mockitoیک فریم‌ورک برای ایجاد mocks، stubs و spies است که به شما کمک می‌کند تا وابستگی‌های خارجی را شبیه‌سازی کرده و فقط بخشی از سیستم را که مورد نظر دارید، تست کنید.1.2. ایجاد Mock با Mockito بیاید یه مثال بزنیم ، فرض کنید که کلاسی به نام DatabaseService داریم که وابستگی به یک پایگاه‌داده دارد. می‌خواهیم هنگام نوشتن تست‌ها از پایگاه‌داده واقعی استفاده نکنیم، بنابراین از mocking استفاده می‌کنیم.1.3. Mockito رفتارهای پیچیده‌ترهمچنین می‌توانید رفتارهای پیچیده‌تری مانند پرتاب استثنا (throwing exceptions)، شمارش تعداد فراخوانی‌ها، یا بررسی مقدارهای بازگشتی در mock را شبیه‌سازی کنید. 1.4. استفاده از پایگاه‌داده In-Memory (برای ماک کردن پایگاه داده)یکی از روش‌های رایج برای انجام تست‌های پایگاه‌داده بدون نیاز به پایگاه‌داده واقعی، استفاده از In-memory database است. پایگاه‌داده‌هایی مانند H2، HSQLDB و Derby می‌توانند در حافظه اجرا شوند و داده‌ها را بدون نیاز به ذخیره‌سازی بر روی دیسک نگهداری کنند.هم میشه از mockito استفاده کرد هم میشه از SpringDataJpa برای تستهامون استفاده کنیم. برای ادامه مباحث تست به آموزش Junit و Mockito برید اونجا با مثال های کابردی انواع حالت های مختلف که بهش بر میخورید رو تست کردیم.موفق و پیروز باشید .اگر موردی به ذهنتون رسید که کم بود بگید اضافه کنم. </description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 04 Jan 2025 11:53:44 +0330</pubDate>
            </item>
                    <item>
                <title>LRU (Least Recently Used) Cache</title>
                <link>https://virgool.io/Javenture/lru-least-recently-used-cache-yozdbfrvmbtk</link>
                <description>خوب برگشتیم با یه آموزش دیگه از مجموعه آموزش های جاوا ، البته توضیحاتش زیاد ربطی به جاوا نداره ولی کدی که میزنیم جاواست . (منو برد به دوران دانشگاه)واقعیت اینکه دارم یه commons برای کش مینویسم که به غیر از تکنولوژی های مرسوم مثل redis , aerospike , memcached و ...  میخوام از Collectionهای جاوا استفاده کنم برای پیاده سازی کش .حالا برای کش کردم یه مفهموم داریم تحت عنوان LRU که میخوام اول اینو توضیح بدم ، بعد میریم یه نمونه کد از پروژه ای که دارم مینویسم رو براتون میزارم. نگران نباشید COMMONS کامل بشه روی گیت در اختیارتون قرار میدم.یه منبع : کدش رو از این و gpt کمک گرفتم .www.javaxp.comکش LRU (Least Recently Used) یک ساختار داده‌ای است که برای مدیریت مؤثر یک کش با اندازه ثابت از عناصر طراحی شده است. این کش به گونه‌ای عمل می‌کند که همواره عنصری که کمتر استفاده‌ شده (least recently used) را زمانی که کش از ظرفیت خود فراتر می‌رود، حذف می‌کند. هدف کش LRU حفظ داده‌های پرکاربردتر در کش است و اطمینان از حذف داده‌های قدیمی یا کم استفاده شده هنگام رسیدن به حداکثر ظرفیت.1. مفهوم کشکش یک منطقه ذخیره‌سازی موقتی است که برای نگهداری داده‌های پرکاربرد استفاده می‌شود. هدف از کش کردن ارائه دسترسی سریعتر به این داده‌ها از طریق ذخیره‌سازی آنها در مکانی است که سریعتر از منبع اصلی (مثلا یک پایگاه داده یا سرور خارجی) است.برای مثال، در یک مرورگر وب، کش داده‌هایی مانند تصاویر و فایل‌های وب‌سایت‌های قبلاً مشاهده شده را ذخیره می‌کند. هنگامی که دوباره به این وب‌سایت مراجعه می‌کنید، مرورگر می‌تواند این داده‌ها را از کش بازیابی کند و زمان بارگذاری را کاهش دهد.2. چه چیزی کش LRU را منحصر به فرد می‌کند؟ویژگی بارز کش LRU سیاست حذف ( اشغال دور خودش جمع نمیکنه ) آن است: کمتر استفاده‌شده. این بدان معناست که کش به حفظ اقلامی که اخیراً بیشتر استفاده شده‌اند، اولویت می‌دهد و مواردی را که برای مدت طولانی‌تری استفاده نشده‌اند، حذف می‌کند. این ویژگی به خصوص در سناریوهایی که برخی داده‌ها بیشتر از دیگران مورد استفاده قرار می‌گیرند، بسیار مفید است.ترتیب حذف: کش عنصر کمتر استفاده‌شده را زمانی که از ظرفیت خود فراتر می‌رود، حذف می‌کند.(برای این حالت و تعریف این ظریفت ها جولو تر توی کد مشخص میکنیم داستان رو فعلا بخون فقط)کارایی: کش‌های LRU به گونه‌ای طراحی شده‌اند که داده‌هایی را که احتمالاً به زودی دوباره استفاده خواهند شد، در خود نگهداری کنند و نرخ دسترسی را افزایش دهند.3. چگونه کش LRU کار می‌کند؟کش LRU معمولاً از ترکیبی از یک جدول هش (یا دیکشنری) برای دسترسی سریع به داده‌ها و یک لیست پیوندی دو طرفه برای حفظ ترتیب عناصر بر اساس آخرین زمان استفاده تشکیل شده است. روش کار به ترتیب زیر است:افزودن یک عنصر جدید:اگر عنصر در کش موجود نباشد و جا برای افزودن وجود داشته باشد، عنصر به جدول هش و لیست پیوندی اضافه می‌شود.عنصر جدید به ابتدای لیست اضافه می‌شود که نشان‌دهنده این است که اخیراً دسترسی یافته است.دسترسی به یک عنصر:وقتی یک عنصر دسترسی پیدا می‌کند، به ابتدای لیست منتقل می‌شود تا نشان‌دهنده استفاده اخیر آن باشد.این عمل در پیگیری عناصر اخیر کمک می‌کند تا در زمان حذف، کمتر استفاده‌شده به راحتی حذف شود.حذف:اگر کش از حد خود فراتر رود (cacheSize)، عنصر کمتر استفاده‌شده (که در پایان لیست پیوندی است) حذف می‌شود.  (توی کدی که در ادامه میارم مشخص میکنیم این مقادیر رو )این اطمینان می‌دهد که کش همواره عناصر بیشتری را که اخیراً مورد استفاده قرار گرفته‌اند، در خود نگه داشته و برای ورودی‌های جدید فضای کافی داشته باشد.4. ساختارهای داده در کش LRUیک کش LRU کارآمد به دو ساختار داده اصلی وابسته است:جدول هش (دیکشنری): این امکان را فراهم می‌کند که عملیات get و put به طور متوسط در زمان اجرا O(1) شوند. جدول هش هر کلید را به مقدار متناظر آن در کش نگاشت می‌کند.لیست پیوندی دو طرفه: این امکان را فراهم می‌کند که عملیات انتقال از ابتدای لیست و حذف از انتهای آن نیز در زمان اجرا O(1) شود. لیست پیوندی ترتیب دسترسی را نگه می‌دارد و حذف عناصر کمتر استفاده‌شده را آسان می‌کند.چرا از هر دو ساختار استفاده می‌شود؟جدول هش دسترسی سریع به داده‌ها بر اساس کلید را فراهم می‌کند، اما ترتیب دسترسی را حفظ نمی‌کند.لیست پیوندی دو طرفه ترتیب دسترسی را نگهداری کرده و حذف ساده‌ترین عناصر را تسهیل می‌کند.5. عملیات در کش LRUget(key): مقدار مرتبط با key را از کش بازیابی می‌کند.       . اگر key وجود داشته باشد، این کلید به ابتدای لیست منتقل شده و مقدار آن برگشت داده می‌شود.       . اگر key وجود نداشته باشد، -1 یا مقدار مشابهی برگردانده می‌شود تا نشان دهد که پیدا نشده است.put(key, value): مقدار برای key را درج یا به‌روزرسانی می‌کند.          . اگر key وجود داشته باشد، مقدار آن به‌روزرسانی شده و کلید به ابتدای لیست منتقل می‌شود.          . اگر key وجود نداشته باشد:              - اگر کش پر باشد، عنصر کمتر استفاده‌شده را (آخرین عنصر در لیست پیوندی) حذف می‌کند.              - جفت کلید-مقدار جدید به جدول هش و ابتدای لیست پیوندی اضافه می‌شود.6. کاراییعملیات به دلیل نکات زیر کارآمد است:عملیات get(key) و put(key, value) هر دو دارای  زمان پیچیدگی O(1) هستند، چون جدول هش دسترسی ثابت را فراهم می‌کند.حذف عنصر کمتر استفاده‌شده نیز دارای  زمان پیچیدگی O(1) است زیرا حذف از لیست پیوندی (از انتها) و به‌روزرسانی در جدول هش در زمان ثابت صورت می‌گیرد.7. کاربردهای عملی کش LRUکش‌های LRU در سناریوهایی که مدیریت حجم ذخیره‌سازی محدود و دسترسی سریع به داده‌ها مهم است، به‌طور گسترده‌ای مورد استفاده قرار می‌گیرند. برخی از کاربردهای رایج عبارتند از:مرورگرهای وب: ذخیره‌سازی تصاویر و فایل‌های وب‌سایت‌های پر بازدید. وقتی کش پر شود، منابع کمتر استفاده‌شده حذف می‌شود.کشینگ کوئری‌های پایگاه داده: در پایگاه داده‌ها، می‌توان کوئری‌ها یا نتایج پر استفاده را کش کرد. وقتی کوئری جدیدی وارد می‌شود و کش پر است، کمتر استفاده‌شده‌ها حذف خواهند شد.مدیریت حافظه: کش‌های LRU در سیستم‌عامل‌ها و سیستم‌های حافظه مجازی برای نگهداری صفحات اخیر در حافظه استفاده می‌شوند، در حالی که صفحات کم‌تر استفاده شده از حافظه خارج می‌شوند.شبکه‌های تحویل محتوا (CDN): هنگام ارائه محتوا مانند تصاویر یا ویدئوها، CDNها معمولاً از کش‌های LRU برای ذخیره‌سازی محتواهای پر درخواست در لبه شبکه استفاده می‌کنند.8. انواع مختلف کش LRUبرخی از انواع یا گسترش‌های کش LRU که ممکن است عملکرد یا ویژگی‌های آن را بهبود دهند یا تغییر دهند عبارتند از:LFU (Least Frequently Used): برخلاف LRU که کمتر استفاده‌شده را حذف می‌کند، LFU اقلامی را حذف می‌کند که به کمترین تعداد دفعات دسترسی داشته‌اند.MRU (Most Recently Used): در مقابل LRU، کش MRU اقلامی را حذف می‌کند که اخیراً بیشترین استفاده را داشته‌اند.کشینگ دو سطحی:در سیستم‌هایی با کش‌های بزرگتر، ممکن است از کش‌های دو سطحی یا سلسله‌مراتبی استفاده شود که یک سطح برای اقلام پرکاربرد و سطح دیگر برای اقلام کمتر کاربردی است.9. نمونه پیاده‌سازی یه چی خیلی ساده ولی کاربردی بگیم ، همه موارد بالارو نداره ولی سعی میکنیم اروم اروم کاملش کنیم :public class LRUCache&lt;K, V&gt; {    private static final float hashTableLoadFactor = 0.75f;    private Map&lt;K, V&gt; map;    private int cacheSize; public LRUCache(int cacheSize) {        this.cacheSize = cacheSize;        int hashTableCapacity = (int) Math.ceil(cacheSize / hashTableLoadFactor) + 1;        map = Collections.synchronizedMap(new LinkedHashMap&lt;K, V&gt;(hashTableCapacity, hashTableLoadFactor, true) {            // (an anonymous inner class)            private static final long serialVersionUID = 1;            @Override            protected boolean removeEldestEntry(Map.Entry&lt;K, V&gt; eldest) {                return size() &gt; LRUCache.this.cacheSize;            }        });    } public synchronized V get(K key) {        return map.get(key);    } public synchronized V remove(K key) {        return map.remove(key);    } public synchronized void put(K key, V value) {        map.put(key, value);    } public synchronized void clear() {        map.clear();    } public synchronized int usedEntries() {        return map.size();    } public synchronized Collection&lt;Map.Entry&lt;K, V&gt;&gt; getAll() {        return new ArrayList&lt;&gt;(map.entrySet());    }}خوب اگر به این خط کد دقت کنید :private static final float hashTableLoadFactor = 0.75f;این یک فاکتور بارگزاری (load factor) برای جداول هش است که به‌عنوان شاخصی برای کنترل میزان پرشدگی استفاده می‌شود. مقدار 0.75 به این معنی است که جدول هش زمانی که به 75% ظرفیت خود برسد، اندازه‌اش افزایش می‌یابد.خوب حالا یکی بگه این چیه پس :int hashTableCapacity = (int) Math.ceil(cacheSize / hashTableLoadFactor) + 1;در اینجا به عنوان ظرفیت اولیه برای LinkedHashMap تعریف شده است که در ساختار LRUCache استفاده می‌شود. این ظرفیت اولیه نمایانگر تعداد اولیه باکت‌ها یا سطل‌هایی است که HashMap باید در خود جای دهد تا با تعداد اولیه عناصر مورد نظر تطابق داشته باشد.این رابطه توش چیه حالا :  cacheSize / hashTableLoadFactorاین رابطه نشان می‌دهد که ظرفیت اولیه (hashTableCapacity) باید کمی بیشتر از cacheSize تنظیم شود تا فاکتور بار نیز در نظر گرفته شود.فاکتور بار 0.75 به این معنی است که وقتی HashMap به 75% ظرفیت خود برسد، شروع به افزایش اندازه می‌کند. با استفاده از این فرمول، تعداد باکت‌های واقعی مورد نیاز حساب می‌شود تا مطمئن شوند که cacheSize مدنظر را بتوانند به طور مؤثری پشتیبانی کند.حالا چرا تهش یه +1 داره :یک واحد به مقدار محاسبه شده اضافه می‌شود تا از مشکلات بالقوه‌ی پرشدگی جدول جلوگیری شود و فضای اضافی برای رشد بهتر فراهم گردد.این محاسبه به بهینه‌سازی عملکرد LinkedHashMap و موثر نگه داشتن LRU Cache کمک می‌کند تا مطمئن شود که ظرفیت کافی برای مدیریت تعداد درخواست‌های مشخص شده برای ذخیره‌سازی را دارد.باقی موارد هم دیگه فکر کنم واضح باشه فقط جاهایی که یکم سوال بیشتر روش بود رو سعی کردم توضیح بدم.امیدوارم به کارتون بیاد ، لطفا اگر اطلاعاتی دارید که بهم کمک کنه برای بهتر کردن پروژه بگید.خلاصه هر گلی زدید به سر خودتون زدید :))نتیجه‌گیریکش LRU یک مکانیزم بسیار کارآمد برای مدیریت یک کش با اندازه ثابت با سیاست حذف بر اساس کمتر استفاده‌شده است. این کش اطمینان می‌دهد که داده‌های پرکاربردتری که اخیراً استفاده شده‌اند، در حافظه باقی بمانند و به طور خودکار داده‌های قدیمی‌تر یا کم‌استفاده‌تر را حذف کند تا فضایی برای ورودی‌های جدید فراهم گردد.با ترکیب جدول هش برای دسترسی سریع و لیست پیوندی دو طرفه برای نگهداری ترتیب، کش LRU زمان پیچیدگی بهینه O(1) را برای عملیات اصلی خود به دست می‌آورد و این امر باعث می‌شود یک ابزار قدرتمند در سیستم‌هایی باشد که نیاز به مدیریت حجم زیادی از داده‌های پرکاربرد دارند.آدرس گیت رو بعد از کامل شدن اینجا میزارم سر بزنید تا 1 هفته دیگه .منتظر نگاه های زیباتون هستم .</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 16 Nov 2024 02:55:25 +0330</pubDate>
            </item>
                    <item>
                <title>How to do logging in Spring Boot?</title>
                <link>https://virgool.io/Javenture/how-to-do-logging-in-spring-boot-k2r8o9ftlhvq</link>
                <description>در دنیای برنامه‌نویسی جاوا، برای ثبت وقایع (Logging)، چندین کتابخانه و ابزار مختلف وجود دارد. ما 4 تا از پراستفاده ترین هاشون ( LogBack , Log4J , Log4j2 , Slf4j ) رو قبلا مقایسه کردیم و دلیل استفاده از هر کدوم رو شرح دادیم ، اگر آشنایی ندارید حتما یه سر بهش بزنید.توی این آموزش قصد داریم روش به کارگیری این ابزار ها رو در spring boot آموزش بدیم.1- Logback - slf4j برای استفاده از SLF4J به همراه Logback در یک پروژه Spring Boot، شما می‌توانید از روش‌های مختلفی بهره‌برداری کنید. SLF4J یک لایه انتزاعی برای لاگ‌برداری است و Logback به عنوان پیاده‌ساز مناسبی برای آن عمل می‌کند.اضافه کردن وابستگی‌ها:&lt;dependency&gt;
       &lt;groupId&gt;org.slf4j&lt;/groupId&gt; 
       &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
 &lt;/dependency&gt; 

&lt;dependency&gt;
       &lt;groupId&gt;ch.qos.logback&lt;/groupId&gt;
       &lt;artifactId&gt;logback-classic&lt;/artifactId&gt;
 &lt;/dependency&gt;پیکربندی Logback:خوب میشه با سه روش پیکر بندی انجام داد :روش اول استفاده از logback.xml روش دوم استفاده از logback-spring.xmlروش سوم استفاده از application.propertiesخوب حالا بریم هر کدوم رو بررسی کنیم :1- استفاده از logback.xmlشما می‌توانید یک فایل پیکربندی به نام logback.xml در دایرکتوری src/main/resources ایجاد کنید. &lt;configuration&gt; 
      &lt;appender name=&amp;quotSTDOUT&amp;quot class=&amp;quotch.qos.logback.core.ConsoleAppender&amp;quot&gt;
         &lt;encoder&gt;
            &lt;pattern&gt;%d{yyyy-MM-dd HH:mm:ss} - %msg%n&lt;/pattern&gt; 
         &lt;/encoder&gt; 
     &lt;/appender&gt;
     &lt;root level=&amp;quotINFO&amp;quot&gt;
         &lt;appender-ref ref=&amp;quotSTDOUT&amp;quot/&gt;
      &lt;/root&gt; 
&lt;/configuration&gt;2- استفاده از logback-spring.xmlاگر می‌خواهید پیکربندی‌تان تحت Spring Boot باشد، می‌توانید از logback-spring.xml استفاده کنید که به شما اجازه می‌دهد از ویژگی‌های Spring Boot بهره ببرید:&lt;configuration&gt;
      &lt;springProfile name=&amp;quotdevelopment&amp;quot&gt; 
         &lt;appender name=&amp;quotSTDOUT&amp;quot class=&amp;quotch.qos.logback.core.ConsoleAppender&amp;quot&gt; 
         &lt;encoder&gt;
              &lt;pattern&gt;%d{yyyy-MM-dd HH:mm:ss} - %msg%n&lt;/pattern&gt; 
         &lt;/encoder&gt; 
      &lt;/appender&gt; 
 
     &lt;root level=&amp;quotDEBUG&amp;quot&gt;
           &lt;appender-ref ref=&amp;quotSTDOUT&amp;quot/&gt;
      &lt;/root&gt; 
     &lt;/springProfile&gt;
 &lt;/configuration&gt;یه چنتا کانفیگ اضافی هم بگیم بعد بریم سر مورد سوم :تنظیم سطح لاگشما می‌توانید سطح لاگ را در فایل پیکربندی خود تغییر دهید:&lt;logger name=&quot;com.example&quot; level=&quot;DEBUG&quot;/&gt;ذخیره لاگ‌ها در فایل:       یه سر به آموزش Logback بزنید.&lt;appender name=&amp;quotFILE&amp;quot class=&amp;quotch.qos.logback.core.FileAppender&amp;quot&gt;
           &lt;file&gt;
                  logs/app.log
           &lt;/file&gt; 
           &lt;encoder&gt;
                 &lt;pattern&gt;%d{yyyy-MM-dd HH:mm:ss} - %msg%n&lt;/pattern&gt;
            &lt;/encoder&gt; 
&lt;/appender&gt;

 &lt;root level=&amp;quotINFO&amp;quot&gt; 
       &lt;appender-ref ref=&amp;quotFILE&amp;quot/&gt;
&lt;/root&gt;3-تنظیمات لاگ‌برداری در application.properties3.1. تنظیم سطح لاگشما می‌توانید سطح لاگ را برای کل برنامه یا برای دسته‌های خاصی از کلاس‌ها تنظیم کنید:# تنظیم سطح لاگ برای کل برنامه 
logging.level.root=INFO 

# تنظیم سطح لاگ برای یک بسته خاص 
logging.level.com.example=DEBUG
3.2. تنظیم فرمت لاگشما می‌توانید فرمت لاگ را نیز تنظیم کنید:# تنظیم فرمت لاگ برای کنسول 
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n

 # تنظیم فرمت لاگ برای فایل
 logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
3.3. ذخیره لاگ‌ها در فایلاگر می‌خواهید لاگ‌ها را در یک فایل ذخیره کنید، می‌توانید مسیر فایل را مشخص کنید:# فعال‌سازی ذخیره‌سازی لاگ‌ها در فایل 
logging.file.name=logs/app.log
 #یا 
logging.file.path=logs
۴. تنظیم سطح لاگ برای سطح‌های مختلفشما می‌توانید تنظیمات را برای سطوح مختلف ثبت کنید:# تنظیم سطح لاگ برای WARN 
logging.level.root=WARNنمونه‌ای کامل از تنظیماتدر اینجا یک نمونه از تنظیمات در application.properties آورده شده است:# تنظیم سطح لاگ ریشه 
logging.level.root=INFO

 # تنظیم سطح لاگ برای بسته خاص
 logging.level.com.example=DEBUG 

# تنظیم مسیر فایل 
logging.file.name=logs/app.log 

# تنظیم الگوی لاگ
 logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%nاستفاده از application.properties یا application.yml برای پیکربندی لاگ‌برداری در Spring Boot بسیار آسان و منعطف است. این روش به شما اجازه می‌دهد تا به راحتی تنظیمات خود را تغییر دهید و بهتر با محیط‌های مختلف (توسعه، تولید و غیره) سازگار شوید.خوب حالا لاگ زدنش چطوریه:import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 
import org.springframework.stereotype.Service; 
@Service
public class MyService {   
    private static final Logger logger = LoggerFactory.getLogger(MyService.class);     
    
     public void performAction() {        
           logger.info(&amp;quotAction has been performed!&amp;quot);     
     } 
}2- Log4j2 - slf4j برای استفاده از Log4j2 به همراه SLF4J در یک پروژه Spring Boot، شما باید چنتا کار ساده انجام بدید . Log4j2 یک پیاده‌ساز قدرتمند و سریع برای SLF4J است و از قابلیت‌های پیشرفته‌ای برخوردار است.اضافه کردن وابستگی‌ها:&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; 
    &lt;artifactId&gt;spring-boot-starter-logging&lt;/artifactId&gt;
    &lt;scope&gt;exclude&lt;/scope&gt; &lt;!-- حذف Logback --&gt;
 &lt;/dependency&gt;

 &lt;dependency&gt;
     &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
     &lt;artifactId&gt;log4j-slf4j-impl&lt;/artifactId&gt;
 &lt;/dependency&gt;

 &lt;dependency&gt;
     &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
     &lt;artifactId&gt;log4j-core&lt;/artifactId&gt;
 &lt;/dependency&gt;

 &lt;dependency&gt;
     &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt; 
     &lt;artifactId&gt;log4j-api&lt;/artifactId&gt;
 &lt;/dependency&gt;پیکربندی Log4j2:خوب میشه با سه روش پیکر بندی انجام داد :روش اول استفاده از log4j2.xml روش دوم استفاده از log4j2.yamlروش سوم استفاده از log4j2.jsonروش چهارم استفاده از application.propertiesخوب حالا بریم هر کدوم رو بررسی کنیم :1- استفاده از log4j2.xmlشما می‌توانید فایل پیکربندی Log4j2 را به نام log4j2.xml، log4j2.json یا log4j2.yaml در دایرکتوری src/main/resources ایجاد کنید. در اینجا یک نمونه ساده از log4j2.xmlگفتیم:&lt;?xml version=&amp;quot1.0&amp;quot encoding=&amp;quotUTF-8&amp;quot?&gt;
&lt;Configuration status=&amp;quotWARN&amp;quot&gt;
    &lt;Appenders&gt;
        &lt;Console name=&amp;quotConsole&amp;quot target=&amp;quotSYSTEM_OUT&amp;quot&gt;
            &lt;PatternLayout pattern=&amp;quot%d{yyyy-MM-dd HH:mm:ss} - %msg%n&amp;quot/&gt;
        &lt;/Console&gt;
        &lt;File name=&amp;quotFileLogger&amp;quot fileName=&amp;quotlogs/app.log&amp;quot&gt;
            &lt;PatternLayout pattern=&amp;quot%d{yyyy-MM-dd HH:mm:ss} - %msg%n&amp;quot/&gt;
        &lt;/File&gt;
    &lt;/Appenders&gt;
    &lt;Loggers&gt;
        &lt;Root level=&amp;quotINFO&amp;quot&gt;
            &lt;AppenderRef ref=&amp;quotConsole&amp;quot/&gt;
            &lt;AppenderRef ref=&amp;quotFileLogger&amp;quot/&gt;
        &lt;/Root&gt;
    &lt;/Loggers&gt;
&lt;/Configuration&gt;یه چنتا کانفیگ اضافی هم بگیم بعد بریم سر مورد بعدی:تنظیم سطح لاگشما می‌توانید سطح لاگ را در فایل پیکربندی Log4j2 تنظیم کنید:&lt;Loggers&gt;
    &lt;Logger name=&amp;quotcom.example&amp;quot level=&amp;quotDEBUG&amp;quot additivity=&amp;quotfalse&amp;quot&gt;
        &lt;AppenderRef ref=&amp;quotConsole&amp;quot/&gt;
    &lt;/Logger&gt;
    &lt;Root level=&amp;quotINFO&amp;quot&gt;
        &lt;AppenderRef ref=&amp;quotConsole&amp;quot/&gt;
    &lt;/Root&gt;
&lt;/Loggers&gt;فعال‌سازی ذخیره لاگ‌ها در فایلبرای ذخیره لاگ‌ها در یک فایل، در قسمت appenders ، از File استفاده می‌شود که در نمونه بالا نشان داده شده است. (یه سر به آموزش Log4j2 بزنید)2-تنظیمات Log4j2 در application.properties (مثل همون Logback)۱. تنظیم سطح لاگمی‌توانید سطح لاگ را برای کل برنامه یا برای بسته‌های خاص تنظیم کنید:# تنظیم سطح لاگ برای ریشه
logging.level.root=INFO

# تنظیم سطح لاگ برای یک بسته خاص
logging.level.com.example=DEBUG۲. ذخیره لاگ‌ها در فایلبرای ذخیره‌سازی لاگ‌ها در یک فایل، می‌توانید نام و مسیر فایل را از این طریق تنظیم کنید:# فعال‌سازی ذخیره‌سازی لاگ‌ها در فایل
logging.file.name=logs/app.log

# تنظیم سطح لاگ با ذخیره در فایل
logging.file.path=logs۳. تنظیم الگوی لاگبرای تنظیم فرمت (الگو) لاگ‌ها:# تنظیم الگوی لاگ برای کنسول
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n

# تنظیم الگوی لاگ برای فایل
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} - %msg%nدر اینجا یک نمونه کامل از پیکربندی در application.propertiesگفتیم:# تنظیم سطح لاگ ریشه
logging.level.root=INFO

# تنظیم سطح لاگ برای بسته خاص
logging.level.com.example=DEBUG

# تنظیم نام فایل لاگ
logging.file.name=logs/app.log

# تنظیم الگوی لاگ برای کنسول
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%nقابلیت‌های اضافی۱. فعال‌سازی لاگ‌برداری غیرهمزماناگر می‌خواهید از لاگ‌برداری غیرهمزمان استفاده کنید:چون Log4j2 از Asynchronous Logging (ثبت وقایع غیرهمزمان) پشتیبانی میکنه میتونید از این کانفیگ استفاده کنید.logging.async.enabled=trueجمع‌بندیاستفاده از application.properties برای پیکربندی Log4j2 در Spring Boot بسیار ساده و موثر است و به شما این امکان را می‌دهد که پیکربندی‌های خود را به راحتی مدیریت کنید.خوب حالا بریم باهاش یه لاگ بزنیم :import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 
import org.springframework.stereotype.Service;

@Service
public class MyService {      
     private static final Logger logger = LoggerFactory.getLogger(MyService.class); 
     
      public void performAction() {        
           logger.info(&amp;quotAction has been performed!&amp;quot);     
       }
 }سخن آخر: اگر به دنبال ویژگی‌های پیشرفته، عملکرد قوی و انعطاف‌پذیری هستید، Log4j2 گزینه بهتری خواهد بود. اما اگر سادگی و کاربرپسندی برای شما در اولویت است و برای پروژه‌های متوسط کار می‌کنید، Logback می‌تواند انتخاب مناسبی باشد. در هر صورت، با توجه به نیازهای خاص پروژه و تیم خود، می‌توانید انتخاب مناسبی داشته باشید.امیدوارم خوشتون بیاد و لذت ببریداین آموزش هم بخونید کمکتون میکنه :  LogBack , Log4J , Log4j2 , Slf4jمنتظر نگاه قشنگتون هستم.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Fri, 13 Sep 2024 12:38:39 +0330</pubDate>
            </item>
                    <item>
                <title>LogBack , Log4J , Log4j2 , Slf4j</title>
                <link>https://virgool.io/Javenture/logback-log4j-log4j2-sla4j-d1jahqbnigkp</link>
                <description>موارد استفاده تا تفاوت هرکدوم:در دنیای برنامه‌نویسی جاوا، برای ثبت وقایع (Logging)، چندین کتابخانه و ابزار مختلف وجود دارد.1 - Log4jیک کتابخانه ثبت وقایع قدیمی و محبوب است که توسط Apache توسعه یافته است. این کتابخانه به برنامه‌نویسان اجازه می‌دهد تا وقایع و پیام‌ها را در هر سطحی (حالت Debug، Info، Warn، Error، Fatal) ثبت کنند.ویژگی‌ها:پیکربندی ساده و انعطاف‌پذیر.پشتیبانی از appenders مختلف (کنسول، فایل، دیتابیس و…).لاگ‌گیری دوره‌ای و چرخشی.یه نموه ساده از نحوه استفاده :&lt;log4j:configuration&gt;
     &lt;appender name=&amp;quotconsole&amp;quot class=&amp;quotorg.apache.log4j.ConsoleAppender&amp;quot&gt;
          &lt;layout class=&amp;quotorg.apache.log4j.PatternLayout&amp;quot&gt; 
               &lt;param name=&amp;quotConversionPattern&amp;quot value=&amp;quot%d{ISO8601} %-5p [%t] %c: %m%n&amp;quot/&gt; 
          &lt;/layout&gt;
      &lt;/appender&gt; 
      &lt;root&gt; 
         &lt;priority value=&amp;quotdebug&amp;quot/&gt; 
         &lt;appender-ref ref=&amp;quotconsole&amp;quot/&gt;
      &lt;/root&gt;
 &lt;/log4j:configuration&gt;2-Log4j2نسخه جدیدتر و پیشرفته‌تر Log4j است که چندین محدودیت نسخه قبلی را برطرف کرده و ویژگی‌های بیشتری را اضافه کرده است. این کتابخانه همچنین بهینه‌تر است و عملکرد بالاتری دارد.ویژگی‌ها:پشتیبانی از Asynchronous Logging (ثبت وقایع غیرهمزمان).معماری بهبود یافته و سبک‌تر.پشتیبانی از APIهای مختلف و قابلیت گسترش.نقاط قوت:عملکرد بالا: Log4j2 می‌تواند مدیریت ثبتی کارآمدتری را ارائه دهد، به خصوص در بارهای سنگین.ویژگی‌های پیشرفته: مانند پشتیبانی از ثبت وقایع غیرهمزمان، پیکربندی ساده، و پشتیبانی از JSON و XML.دستوریابی و ابزارهای کمکی: Log4j2 دارای ابزارهای پیکربندی با رابط کاربری گرافیکی (GUI) برای آسان‌تر کردن تنظیمات است.نقاط ضعف:پیچیدگی: ممکن است مستندات و تنظیمات پیچیده به نظر برسند و نیاز به زمان زیادی برای یادگیری داشته باشند.مدیریت وابستگی‌ها: مدیریت بسیاری از وابستگی‌ها (مثل اتصال به SLF4J) می‌تواند چالش برانگیز باشد.باگ‌های امنیتی:Log4Shell: یکی از بزرگترین مشکلات امنیتی در Log4j2 منتشر شده بود که اجازه اجرای کد از راه دور (Remote Code Execution) را می‌دهد. این باگ به طور گسترده‌ای مورد سوءاستفاده قرار گرفت و منجر به نگرانی‌های جدی امنیتی شد. به همین دلیل مهم است که به‌روزرسانی‌های امنیتی را به‌روز نگه‌دارید.دلیل محبوبیت :محبوبیت Log4j2 به دلیل کارایی بالا و ویژگی‌های مدرن آن است. بسیاری از پروژه‌های بزرگ و پیچیده از آن استفاده می‌کنند.یه نموه ساده از نحوه استفاده :&lt;Configuration status=&amp;quotWARN&amp;quot&gt;
 &lt;Appenders&gt;
       &lt;Console name=&amp;quotConsole&amp;quot target=&amp;quotSYSTEM_OUT&amp;quot&gt;
             &lt;PatternLayout pattern=&amp;quot%d %p %c{1} - %m%n&amp;quot/&gt;
      &lt;/Console&gt;
 &lt;/Appenders&gt;
 &lt;Loggers&gt;
    &lt;Root level=&amp;quotdebug&amp;quot&gt;
            &lt;AppenderRef ref=&amp;quotConsole&amp;quot/&gt;
     &lt;/Root&gt;
 &lt;/Loggers&gt;
&lt;/Configuration&gt;3. SLF4J (Simple Logging Facade for Java)یک رابط (Facade) برای سیستم‌های ثبت وقایع است و به برنامه‌نویسان این امکان را می‌دهد که از هر کتابخانه‌ای (مانند Log4j، Logback) به راحتی استفاده کنند. این کار به سادگی تغییر کتابخانه‌ی ثبت وقایع بدون تغییر در کد برنامه انجام می‌پذیرد.ویژگی‌ها:استقلال از پیاده‌سازی‌های زیرین.قابلیت تغییر کتابخانه ثبت وقایع بدون تغییر در کد اصلی.نقاط قوت:واسط کلی: SLF4J به‌عنوان یک facade برای بسیاری از پیاده‌سازی‌های لاگینگ عمل می‌کند، بنابراین می‌توانید به آسانی از یک کتابخانه به دیگری تغییر دهید.ساده‌سازی گزارش‌گیری: برای کار با چندین کتابخانه لاگینگ تنها به یک API نیاز دارید.نقاط ضعف:عدم پیاده‌سازی مستقل: SLF4J خودش ابزار لاگینگ نیست و برای کار به یک پیاده‌سازی (مثل Log4j یا Logback) نیاز دارد.باگ‌های امنیتی:به خودی خود به طور مستقیم با مسائل امنیتی درگیر نیست، اما امنیت پیاده‌سازی‌هایی که به آن متکی هستند، مهم است.موارد استفاده و محبوبیت:در بین توسعه‌دهندگان Java به محبوبیت بالایی دست یافته است، به‌خصوص افرادی که نیاز به انعطاف‌پذیری لاگینگ دارند.یه نمونه از نحوه استفاده :import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Example {
     private static final Logger logger = LoggerFactory.getLogger(Example.class);

     public void doSomething() {
           logger.info(&amp;quotThis is an info message&amp;quot);
     }

}4. Logbackیک کتابخانه ثبت وقایع پیشرفته است که توسط خالق Log4j توسعه یافته و می‌تواند به عنوان یک جانشین Log4j استفاده شود. این کتابخانه به طور پیش‌فرض با SLF4J سازگاری کامل دارد.ویژگی‌ها:پشتیبانی بهتر از عملکرد و سبک ثبت وقایع.تنوع در اپندرها و الگوهای خروجی.پشتیبانی از فایل‌های پیکربندی XML و Groovy.نقاط قوت:عملکرد و ساده‌سازی: Logback به عنوان یک جانشین برای Log4j طراحی شده و به طور مستقیم با SLF4J ادغام شده است.پیکربندی آسان: پیکربندی Logback ساده و مستقیم است و می‌توان به راحتی آن را به صورت XML یا Groovy نوشت.مشاهده و ردیابی آسان: Logback امکانات پیشرفته‌ای برای مشاهده و ردیابی خطاها دارد.نقاط ضعف:معکوس‌پذیری کمتر: در مقایسه با Log4j2 ممکن است در موارد خاص عملکرد کمتری داشته باشد.نقص در بازخورد از جامعه: با اینکه Logback مورد توجه است، اما گاهی اوقات به اندازه Log4j به روزرسانی نمی‌شود.باگ‌های امنیتی:در مقایسه با Log4j2 به ندرت با باگ‌های امنیتی بزرگ روبرو شده است. با این حال، همیشه باید به‌روزرسانی‌های امنیتی را دنبال کرد تا مطمئن شوید که آسیب‌پذیری‌های احتمالی برطرف شده‌اند.دلیل محبوبیت:به خاطر سادگی و کارایی در پروژه‌های متوسط و بزرگ محبوب است و به طور گسترده‌ای در پروژه‌های جدید توصیه می‌شود.یه نمونه ساده از نحوه استفاده :&lt;configuration&gt; 
      &lt;appender name=&amp;quotconsole&amp;quot class=&amp;quotch.qos.logback.core.ConsoleAppender&amp;quot&gt;
           &lt;encoder&gt; 
                &lt;pattern&gt;
                     %date %level [%thread] %logger{10} - %msg%n
                &lt;/pattern&gt;
           &lt;/encoder&gt;
      &lt;/appender&gt;
      &lt;root level=&amp;quotdebug&amp;quot&gt; 
            &lt;appender-ref ref=&amp;quotconsole&amp;quot/&gt;
       &lt;/root&gt;
 &lt;/configuration&gt;خوب حالا بریم نحوه استفاده رو بگیم :شما می‌توانید از هر دو کتابخانه Log4j2 و Logback به همراه SLF4J استفاده کنید، زیرا SLF4J به عنوان یک واسط یا facade عمل می‌کند که امکان استفاده از پیاده‌سازی‌های مختلف کتابخانه‌های لاگینگ را فراهم می‌کند.1-  استفاده از Logback به همراه SLF4Jکانفیگ maven :&lt;dependencies&gt;
     &lt;!-- SLF4J API --&gt; 
     &lt;dependency&gt;
         &lt;groupId&gt;org.slf4j&lt;/groupId&gt; 
         &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt; 
         &lt;version&gt;1.7.36&lt;/version&gt; 
      &lt;/dependency&gt;

      &lt;!-- Logback Classic --&gt;
      &lt;dependency&gt; 
           &lt;groupId&gt;ch.qos.logback&lt;/groupId&gt;
           &lt;artifactId&gt;logback-classic&lt;/artifactId&gt;
          &lt;version&gt;1.2.10&lt;/version&gt;
       &lt;/dependency&gt;
 &lt;/dependencies&gt;پیکربندی Logback:شما می‌توانید Logback را با استفاده از یک فایل پیکربندی XML پیکربندی کنید. نام فایل باید logback.xml باشد و باید در دایرکتوری src/main/resources قرار گیرد.&lt;configuration&gt;
         &lt;!-- تنظیم کنسول لاگ --&gt; 
        &lt;appender name=&amp;quotCONSOLE&amp;quot class=&amp;quotch.qos.logback.core.ConsoleAppender&amp;quot&gt; 
              &lt;encoder&gt; 
                      &lt;pattern&gt;
                                 %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
                     &lt;/pattern&gt;
              &lt;/encoder&gt; 
       &lt;/appender&gt; 

       &lt;!-- تنظیم فایل لاگ --&gt;
        &lt;appender name=&amp;quotFILE&amp;quot class=&amp;quotch.qos.logback.core.FileAppender&amp;quot&gt; 
                &lt;file&gt; myapp.log &lt;/file&gt; &lt;!-- نام فایل لاگ --&gt;
                &lt;append&gt;true&lt;/append&gt; &lt;!-- برای افزودن به فایل موجود --&gt;
                &lt;encoder&gt;
                        &lt;pattern&gt;
                                %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
                        &lt;/pattern&gt; 
               &lt;/encoder&gt; 
         &lt;/appender&gt;
       
       &lt;!-- تعیین سطح لاگ برای کلاسی خاص --&gt; 
       &lt;logger name=&amp;quotcom.example&amp;quot level=&amp;quotDEBUG&amp;quot/&gt; 

       &lt;!-- سطح لاگ کلی --&gt;
       &lt;root level=&amp;quotINFO&amp;quot&gt; 
           &lt;appender-ref ref=&amp;quotCONSOLE&amp;quot/&gt; 
           &lt;appender-ref ref=&amp;quotFILE&amp;quot/&gt; 
      &lt;/root&gt;
 &lt;/configuration&gt;در این پیکربندی:یک appender برای نمایش لاگ‌ها در کنسول تعریف شده است.یک logger برای package com.example با سطح لاگ DEBUG تعریف شده است.بخش root سطح لاگ INFO را با ارجاع به CONSOLE تنظیم کرده است.نکات اضافیمی‌توانید پارامترهای file و pattern را به دلخواه تغییر دهید.با استفاده از size و timeBasedRollingPolicy می‌توانید لاگ‌ها را به صورت چرخشی ذخیره کنید.کد جاواحالا یک کلاس جاوا ایجاد کنید که از SLF4J برای لاگ‌گیری استفاده کند. مثلا:package com.example;  
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory;

public class LoggingExample {     
         private static final Logger logger = LoggerFactory.getLogger(LoggingExample.class);
      
         public static void main(String[] args) {         
                logger.debug(&amp;quotThis is a debug message.&amp;quot);       
                logger.info(&amp;quotThis is an info message.&amp;quot);     
                logger.warn(&amp;quotThis is a warning message.&amp;quot);  
                logger.error(&amp;quotThis is an error message.&amp;quot);    
         } 
}2- استفاده از Log4j2 به همراه SLF4Jبرای استفاده از Log4j2 به همراه SLF4J، باید SLF4J و Log4j2 را در پروژه‌تان تنظیم کنید. این تنظیمات ابتدا شامل اضافه کردن وابستگی‌ها (dependencies) برای کتابخانه‌های مورد نیاز است.کانفیک maven :&lt;!-- SLF4J API --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
    &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
     &lt;version&gt;1.7.36&lt;/version&gt;
&lt;/dependency&gt;

&lt;!-- Log4j2 API --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
    &lt;artifactId&gt;log4j-slf4j-impl&lt;/artifactId&gt;
    &lt;version&gt;2.19.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;!-- Log4j2 Core --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
    &lt;artifactId&gt;log4j-core&lt;/artifactId&gt;
    &lt;version&gt;2.19.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;!-- SLF4J Binding for Log4j2 --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
    &lt;artifactId&gt;log4j-api&lt;/artifactId&gt;
    &lt;version&gt;2.19.0&lt;/version&gt;
&lt;/dependency&gt;پیکربندی Log4j2 :شما می‌توانید Log4j2 را با استفاده از یک فایل پیکربندی XML پیکربندی کنید. نام فایل باید log4j2.xml باشد و باید در دایرکتوری src/main/resources قرار گیرد.&lt;?xml version=&amp;quot1.0&amp;quot encoding=&amp;quotUTF-8&amp;quot?&gt; 
 &lt;Configuration status=&amp;quotWARN&amp;quot&gt; 

     &lt;Appenders&gt; 
        &lt;!-- تنظیم فایل لاگ --&gt;
        &lt;File name=&amp;quotFileLogger&amp;quot fileName=&amp;quotlogs/myapp.log&amp;quot append=&amp;quottrue&amp;quot&gt; 
           &lt;PatternLayout pattern=&amp;quot%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n&amp;quot/&gt; 
       &lt;/File&gt; 

       &lt;!-- تنظیم لاگ کنسولی --&gt;
       &lt;Console name=&amp;quotConsoleLogger&amp;quot&gt; 
          &lt;PatternLayout pattern=&amp;quot%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n&amp;quot/&gt; 
      &lt;/Console&gt;
   &lt;/Appenders&gt; 

   &lt;Loggers&gt;
        &lt;Logger name=&amp;quotcom.example&amp;quot level=&amp;quotdebug&amp;quot additivity=&amp;quotfalse&amp;quot&gt;
              &lt;AppenderRef ref=&amp;quotFileLogger&amp;quot/&gt;
              &lt;AppenderRef ref=&amp;quotConsoleLogger&amp;quot/&gt;
       &lt;/Logger&gt; 
       &lt;Root level=&amp;quotinfo&amp;quot&gt; 
           &lt;AppenderRef ref=&amp;quotFileLogger&amp;quot/&gt; 
           &lt;AppenderRef ref=&amp;quotConsoleLogger&amp;quot/&gt; 
       &lt;/Root&gt; 
   &lt;/Loggers&gt; 

&lt;/Configuration&gt;در این پیکربندی:یک appender برای نمایش لاگ‌ها در کنسول تعریف شده است.یک logger برای package com.example با سطح لاگ debug تعریف شده است.بخش root سطح لاگ info را با ارجاع به Console تنظیم کرده است.نکات اضافیمی‌توانید نام فایل و الگوی لاگ را به دلخواه تغییر دهید.قابلیت‌های پیشرفته‌تری مانند RollingFileAppender را برای چرخش فایل‌های لاگ ارائه می‌دهد. برای این کار می‌توانید به جای File، از RollingFile استفاده کنید.کد جاواحالا یک کلاس جاوا ایجاد کنید که از SLF4J برای لاگ‌گیری استفاده کند. مثلاً:package com.example;  

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory;  

public class LoggingExample {    
       private static final Logger logger = LoggerFactory.getLogger(LoggingExample.class);      
       
       public static void main(String[] args) {        
              logger.debug(&amp;quotThis is a debug message.&amp;quot);       
              logger.info(&amp;quotThis is an info message.&amp;quot);   
              logger.warn(&amp;quotThis is a warning message.&amp;quot);   
              logger.error(&amp;quotThis is an error message.&amp;quot);    
       }
 }خوب حالا یه مسئله :اگر به فایل های کانفیگ هر کدوم نگاه کنید این چند خط دیده میشه در log4j2:&lt;Logger name=&amp;quotcom.example&amp;quot level=&amp;quotdebug&amp;quot additivity=&amp;quotfalse&amp;quot&gt; 
        &lt;AppenderRef ref=&amp;quotConsole&amp;quot /&gt; 
&lt;/Logger&gt; و در LogBack :&lt;logger name=&quot;com.example&quot; level=&quot;DEBUG&quot;/&gt;حالا یه سوال پیش میاد ایا باید برای تعریف log Level  برای کلاس های هر پکیج بیایم و این چند خط رو بنویسیم :جواب سوال اینه که بله باید تعریف کنید این به شما کمک میکند که برای هر پیکیج خاص بسته به نیاز log level خاص خود را تعیین کنید . (به عنوان مثال این پایین LogBack رو میگم)&lt;Logger name=&amp;quotcom.example.package1&amp;quot level=&amp;quotdebug&amp;quot/&gt;
 &lt;Logger name=&amp;quotcom.example.package2&amp;quot level=&amp;quoterror&amp;quot/&gt;هرچند که میشه root هم داشت که برای کل پروژه تعریف میشه :&lt;root level=&amp;quotINFO&amp;quot&gt;
      &lt;appender-ref ref=&amp;quotCONSOLE&amp;quot /&gt; 
&lt;/root&gt;محبوبیت و انتخاببهترین انتخاب بستگی به نیازهای پروژه شما دارد:Log4j2 و Logback هر دو عملکرد بالایی دارند و با SLF4J سازگاری خوبی دارند. انتخاب یکی از آنها بستگی به نیازهای خاص پروژه شما دارد:Log4j2: برای عملکرد بهتر در بارهای سنگین و پشتیبانی از ویژگی‌های مدرن مانند ثبت وقایع غیرهمزمان (Asynchronous).Logback: برای تنظیمات پیشرفته و پشتیبانی از فایل‌های پیکربندی XML و Groovy.اگر به پیکربندی ساده و عملکرد بهینه بیشتر علاقه دارید، Logback یک گزینه عالی است. اگر نیاز به ویژگی‌های پیشرفته‌تری دارید، Log4j2 می‌تواند مناسب‌تر باشد.برای پروژه‌های جدید، پیشنهاد می‌شود از Log4j2 یا Logback (در کنار SLF4J) استفاده کنید؛ چرا که این کتابخانه‌ها به ویژگی‌ها و کارایی بهتری نسبت به Log4j قدیمی و پشتیبانی بهتری برای نیازهای پروژه‌های مدرن دارند.نتیجه‌گیریانتخاب میان Log4j2 و Logbackانتخاب بین Log4j2 و Logback به همراه SLF4J بستگی به نیازهای خاص پروژه شما دارد. هر کدام از این گزینه‌ها نقاط قوت و ضعف خاص خود را دارند1-Log4j2 با SLF4J:نقاط قوت:عملکرد بالا: Log4j2 طراحی شده تا عملکرد بسیار بالا و بهینه‌تری در بارهای سنگین داشته باشد.ویژگی‌های پیشرفته: مانند ثبت وقایع غیرهمزمان (Asynchronous Logging) که می‌تواند کارایی را در اپلیکیشن‌های مقیاس بزرگ بهبود بخشد.پیکربندی انعطاف‌پذیر: پیکربندی از طریق فایل‌های XML، JSON، YAML و حتی برنامه‌نویسی امکان‌پذیر است.مدیریت بهتر خطا: Log4j2 ابزارهای بیشتری برای مدیریت خطاها و اشکال‌زدایی ارائه می‌دهد.نقاط ضعف:پیچیدگی: ممکن است تنظیمات و پیکربندی آن در ابتدا برای برخی توسعه‌دهندگان پیچیده به نظر برسد.حساسیت به باگ‌ها: مانند مشکلات امنیتی اخیر (Log4Shell) که می‌تواند عواقب جدی داشته باشد.2- Logback با SLF4Jنقاط قوت:سادگی و کاربرپسندی: Logback به عنوان جایگزینی برای Log4j طراحی شده و پیکربندی آن ساده‌تر است.ادغام مستقیم با SLF4J: Logback به‌طور مستقیم با SLF4J ترکیب شده است، به این معنی که نیازی به وابستگی‌های اضافی نیست.مشاهده و ردیابی خطاها: Logback ابزارهای مناسبی برای ردیابی و جمع‌آوری اطلاعات خطاها فراهم می‌کند.عملکرد مطلوب: معمولاً Logback عملکرد مطلوبی دارد، به ویژه برای پروژه‌های متوسط.نقاط ضعف:ویژگی‌های محدودتر: در مقایسه با Log4j2 ممکن است برخی از ویژگی‌های پیشرفته‌تر را نداشته باشد.پشتیبانی از بار سنگین: در برخی سناریوهای بسیار بار سنگین، عملکرد آن ممکن است نسبت به Log4j2 کمی پایین‌تر باشد.موارد استفادهLog4j2 با SLF4J:مناسب برای پروژه‌های بزرگ و پیچیده که نیاز به عملکرد بالا و ویژگی‌های پیشرفته دارند. اگر به دنبال ثبت وقایع غیرهمزمان و پیکربندی انعطاف‌پذیر هستید.Logback با SLF4J:مناسب برای پروژه‌های متوسط و کوچک که نیاز به سادگی و کاربرپسندی دارند. توصیه برای پروژه‌های جدید به خصوص اگر تیم از SLF4J به خوبی آگاه است.سخن آخر: اگر به دنبال ویژگی‌های پیشرفته، عملکرد قوی و انعطاف‌پذیری هستید، Log4j2 گزینه بهتری خواهد بود. اما اگر سادگی و کاربرپسندی برای شما در اولویت است و برای پروژه‌های متوسط کار می‌کنید، Logback می‌تواند انتخاب مناسبی باشد. در هر صورت، با توجه به نیازهای خاص پروژه و تیم خود، می‌توانید انتخاب مناسبی داشته باشید.امیدوارم خوشتون بیاد و لذت ببریدمنتظر نگاه  قشنگتون هستم </description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Fri, 13 Sep 2024 02:20:20 +0330</pubDate>
            </item>
                    <item>
                <title>Exception Handling - Sample Code (Spring Boot)</title>
                <link>https://virgool.io/Javenture/exception-handling-simple-code-spring-boot-tcnuvknyrcrm</link>
                <description>قبلا در رابطه با Exception Handling و انواع خطا ها خیلی مفصل صحبت کردیم و آشنا شدیم اگر آموزش Java Exception Handling رو نخوندید پیشنهاد میکنم اول از اون شروع کنید.خوب الان میخوام از یه نمونه کد که توی Spring به همراه دوست خفنم پیاده سازی کردیم براتون پرده برداری کنم.دوست خفن و یاور همیشگی من :  سید امین سید محمدی آدرس لینکدینش : https://www.linkedin.com/in/seyedamin-seyedmohammadiتا 4 صبح داشتیم برای بهتر شدن کار ایده میدادیم و حی پاک میکردیم و حی مینوشتیم سر سری رد نشید.یه فایل Postman هم جهت تست پروژه براتون گذاشتم توی مسیر گیت.نمونه خروجی سرویس:{
     &amp;quothttp_status_code&amp;quot: &amp;quotINTERNAL_SERVER_ERROR&amp;quot,
     &amp;quothttp_custom_error_code&amp;quot: 0,
     &amp;quottimestamp&amp;quot: &amp;quot2024-09-04T17:46:42.344+00:00&amp;quot,
     &amp;quotmessage&amp;quot: &amp;quotnot handler exception&amp;quot,
      &amp;quotdescription&amp;quot: &amp;quotInternal Server Error&amp;quot
}این آدرس git پروژه :  آدرس وب پروژه : https://github.com/sadeghkhanzadi/exception-handlingآدرس گیت پروژه جهت clone گرفتن :  https://github.com/sadeghkhanzadi/exception-handling.git    توضیح درباره کد های پروژه : (تا 4 صبح داشتیم ایده پردازی میکردیما سر سری رد نشید ازش )اول از همه بگم این خطا به عنوان یک commons توی پروژه اصلیمون بود که من جداش کردم و انواع خطاهای microservice های مختلف پروژه رو توی پکیج InternalExceptions قرار دادیم.که مثلاکلاس OauthException برای خطاهای مربوط به IdentityManagment و Oauth و از این قبیل موارد و کلاس AsyncException برای خطاهای مربوط به Sync ، Async و MessageBroker و از این قبیل موارد و ...و اما یک کلاس خیلی مهم برای دیگر خطا هایی که ممکنه هر لحظه اتفاق بیفته و از عهده کنترلشون بر نیاید با نام UnCheckedExceptions ایجاد کردیم که مثلا خطاهای Db Constraints و خطاهای چک نشده مثل IllegalArgumentException در آن دریافت میگردد و میتواند در این کلاس هندلشون کنید.اگر میخواید Db Constraints  هارو هندل کنید میتونید Db Constraints هارو در دیتابس خودتون تغییر نام بدید و بعد بیاید اینجا دریافتش کنید که اون خودش یه مبحث مربوط به دیتابیس BaseException  Interface:هر کدوم از این کلاس ها از یک interface به اسم BaseException ایمپلیمنت کردن BaseException:

public interface BaseException {
     ErrorMessage getErrorMessage(Throwable t);
}همانطور که مشاهده میکنید این اینترفیس یک متد دارد که به عنوان پارامتر ورودی یک Throwable دریافت میکند که این به این دلیل است که بتواند انواع خطاهای کنترل شده و نشده و error ها را پشتیبانی کند و هیچی از دستمون در نره.شکل پیاده سازی این متد در هر کلاس به صورت زیر میباشد :@Override
public ErrorMessage getErrorMessage(Throwable ex) {
    OauthException exc = (OauthException) ex;
    return new ErrorMessage.Builder()
            .message(exc.getMessage())
            .timestamp(new Date())
            .description(exc.getError_description())
            .httpStatusCode(exc.http_status_code)
            .http_custom_error_code(exc.http_custom_error_code)
            .builder();
}دلیل نوشتن این متد اصلا چی بود : بریم بفهمیم ExceptionConfiguration:اگر به کلاس ExceptionConfiguration نگاه کنید به این متد میرسید : oauthException@ResponseBody
    @ExceptionHandler({Throwable.class})
//    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity&lt;ErrorMessage&gt; oauthException(
            Throwable ex, WebRequest request) {
        Class&lt;? extends Throwable&gt; aClass = ex.getClass();
        BaseException baseException = baseExceptionMap.get(aClass.getSimpleName());
        ErrorMessage message;
        if (baseException != null) {
            message = baseException.getErrorMessage(ex);
        } else {
            message = UnCheckedExceptions.getErrorMessage(ex);
        }
        //todo logs
        return new ResponseEntity&lt;ErrorMessage&gt;(message, new HttpHeaders(), message.getHttp_status_code());
    }همان طور که متوجه شدید هر زمان در یک سرویس خطا اتفاق میفتد یه صورت اتوماتیک خطا توسط متد فوق دریافت میگردد Class&lt;? extends Throwable&gt; aClass = ex.getClass();در این خط نام کلاس خطای مربوطه دریافت میشود مثلا فرض کنید AsyncException برگدونیم پس در اینجا نام کلاس میشه AsyncException  سپس: BaseException baseException = baseExceptionMap.get(aClass.getSimpleName());کلاسی که از baseException ایمپلیمنت کرده باشد ایجاد و برگشت داده میشود. و متن پیام موجود در آن جهت ایجاد خطای خروجی ایجاد بر میگردد.شاید این سوال پیش بیاید اگر خطایی را ما هندل نکردیم چی میشه :if (baseException != null) {             
      message = baseException.getErrorMessage(ex);        
در این خط خطاهایی که ما پیاده سازی کردیم در صورت پرتاب شدن دریافت میگردد
 } else {             
      message = UnCheckedExceptions.getErrorMessage(ex);        
در این خط هم خطاهایی که ما پیاده سازی نکرده باشیم و به اصطلاح هندل نشده دریافت میگردد
 }خوب بریم یکم بیشتر وارد کلاس ExceptionConfiguration بشیم :یکم قبل تر به این تکه کد در متد oauthException اشاره کردیم BaseException baseException = baseExceptionMap.get(aClass.getSimpleName());خوب همانطور که مشاهده میکنید baseExceptionMap  یک HashMap میباشد که در زمان اجرا شدن اپلیکیشن از اسامی Exception Class ها پر میشود.  (OauthException , AsyncException , ...)مسیر Exception Class ها در ابتدای کلاس ExceptionConfiguration در متغیر exceptionPath قرار میگیرد private static final String exceptionPath =&quot;   مسیر سیستم خودتون رو بدید به پکیج InternalExceptions &quot;و سپس در زمان اجرا شده اپلیکیشن در بلوک static موجود در کلاس ExceptionConfiguration کلاس ها توسط متد initBaseException شناسایی شده و در HashMap نام برده شده قرار میگیرد.static {
    try {
        initBaseException();
    } catch (ClassNotFoundException e) {
        throw new RuntimeException(e);
    } catch (InstantiationException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}
متد initBaseException:در این متد ادرس پکیج Exception Class ها به صورت یک set از متد findAllClassesUsingClassLoader برگشت داده میشود و حالا زمان آن است که هر یک از این کلاس ها ایجاد شوند و در baseExceptionMap قرار بگیرند. در واقع ما داریم یک HashMap از Exception Class ها ایجاد میکنیم تا در صورت بروز خطا در متد oauthException قابل دسترس باشد که قبل تر توضیح داده شد . private static void initBaseException() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    Set&lt;Class&gt; classSet = findAllClassesUsingClassLoader(exceptionPath);
    for (Class i : classSet) {
        BaseException b = (BaseException) Class.forName(i.getName()).newInstance();
        System.out.println(&amp;quotException Class Name: &amp;quot + i.getSimpleName());
        baseExceptionMap.put(
                i.getSimpleName(),b
        );
    }
}متد fillAllClassesUsingClassLoader :این متد آدرس Exception Class ها را به عنوان پارامتر ورودی دریافت میکند. و آدرس پکیج هر کلاس را در set قرار میدهد و برمیگرداند.public static Set&lt;Class&gt; findAllClassesUsingClassLoader(String packageName) {
    InputStream stream = ClassLoader.getSystemClassLoader()
            .getResourceAsStream(packageName.replaceAll(&amp;quot[.]&amp;quot, &amp;quot/&amp;quot));
    BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
    return reader.lines()
            .filter(line -&gt; line.endsWith(&amp;quot.class&amp;quot))
            .map(line -&gt; getClass(line, packageName))
            .collect(Collectors.toSet());
}متد getClass:در این متد نام کلاس و آدرس پکیج کلاس به عنوان پارامتر ورودی دریافت میگردد و سپس یک کلاس برگشت داده میشود.private static Class getClass(String className, String packageName) {
    try {
        return Class.forName(packageName + &amp;quot.&amp;quot
                + className.substring(0, className.lastIndexOf(&#039;.&#039;)));
    } catch (ClassNotFoundException e) {
        // handle the exception
    }
    return null;
}
امیدوارم توی پروژه هاتون استفاده کنید و لذت ببرید .منتظر نگاه های قشنگتون هستم.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Wed, 04 Sep 2024 22:45:29 +0330</pubDate>
            </item>
                    <item>
                <title>Java Collections - Everything You MUST Know</title>
                <link>https://virgool.io/Javenture/java-collections-everything-you-must-know-irpe7k4z2wbb</link>
                <description>در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingتوی این آموزش میخوایم راجب Collection ها در جاوا صحبت کنیم و تا جایی که میتونیم بررسیش کنیم و هرچی نکته بلدیم رو بیاریم .چنتا سوال هم اون آخر میگم خیلی باحاله توی مصاحبه ها هم میاد.همین اول کار بگم هرچی بلد بودم رو آوردم و اگر نکته جالبی میدونید بگید که اضافه کنم . نمای کلی Java Collectionsنگاه کلی  :مجموعه‌ها در جاوا (Java Collections) ساختارهای داده‌ای هستند که برای ذخیره، سازماندهی و مدیریت گروهی از اشیاء استفاده می‌شوند. این مجموعه‌ها به شما اجازه می‌دهند تا به جای کار با تک تک اشیاء، با کل مجموعه به عنوان یک واحد کار کنید.چرا مجموعه‌ها مهم هستند؟سادگی کار با داده‌ها: به جای مدیریت آرایه‌های ثابت، مجموعه‌ها امکان افزودن، حذف و جستجوی عناصر را به صورت دینامیک فراهم می‌کنند.انواع مختلف داده‌ها: مجموعه‌های جاوا از انواع مختلف داده‌ها پشتیبانی می‌کنند، از جمله اعداد، رشته‌ها و اشیاء سفارشی.الگوریتم‌های آماده: بسیاری از عملیات رایج مانند مرتب‌سازی، جستجو و فیلتر کردن بر روی مجموعه‌ها به صورت آماده در کتابخانه‌های جاوا وجود دارند.انعطاف‌پذیری: مجموعه‌ها در اندازه و نوع داده‌ها انعطاف‌پذیر هستند و با رشد برنامه شما به راحتی قابل تغییر هستند.انواع اصلی مجموعه‌ها در جاواList: مجموعه‌ای مرتب از عناصر است که هر عنصر می‌تواند چندین بار تکرار شود.                       ArrayList:پیاده‌سازی متداول List است که بر اساس آرایه‌ها ساخته شده است.LinkedList: پیاده‌سازی دیگری از List است که بر اساس نودها ساخته شده و برای عملیات درج و حذف در وسط لیست بهینه شده است.Set: مجموعه‌ای از عناصر منحصر به فرد است. هر عنصر فقط یک بار می‌تواند در مجموعه وجود داشته باشد.                                                                                                                                                          HashSet: پیاده‌سازی متداول Set است که بر اساس جدول هش ساخته شده و برای جستجوی سریع عناصر بهینه شده است.TreeSet: پیاده‌سازی دیگری از Set است که عناصر را به صورت مرتب شده ذخیره می‌کند.Map: مجموعه‌ای از جفت‌های کلید-مقدار است. هر کلید باید منحصر به فرد باشد.                                      HashMap: پیاده‌سازی متداول Map است که بر اساس جدول هش ساخته شده است.                    TreeMap: پیاده‌سازی دیگری از Map است که کلیدها را به صورت مرتب شده ذخیره می‌کند.عملیات رایج روی مجموعه‌هااضافه کردن عنصر: اضافه کردن یک عنصر جدید به مجموعه.حذف عنصر: حذف یک عنصر از مجموعه.جستجوی عنصر: پیدا کردن یک عنصر خاص در مجموعه.ایجاد زیرمجموعه: ایجاد یک مجموعه جدید که شامل بخشی از عناصر مجموعه اصلی است.مرتب‌سازی: مرتب کردن عناصر مجموعه بر اساس یک معیار خاص.ایجاد تکرار کننده: ایجاد یک شیء تکرار کننده برای پیمایش عناصر مجموعه.چه زمانی از چه مجموعه‌ای استفاده کنیم؟List: زمانی که ترتیب عناصر مهم باشد و نیاز به دسترسی به عناصر با اندیس داشته باشیدSet: زمانی که نیاز به مجموعه ای از عناصر منحصر به فرد داشته باشیدMap: زمانی که نیاز به نگاشت بین کلیدها و مقادیر داشته باشیدیه مثال ساده : import java.util.ArrayList; 
import java.util.List;
public class Example {   
     public static void main(String[] args) {    

          List&lt;String&gt; fruits = new ArrayList&lt;&gt;();        
          fruits.add(&amp;quotapple&amp;quot);        
          fruits.add(&amp;quotbanana&amp;quot);        
          fruits.add(&amp;quotorange&amp;quot);         
          System.out.println(fruits);
          // خروجی: [apple, banana, orange]
} }نکات مهمGeneric types: مجموعه‌ها در جاوا از generic types پشتیبانی می‌کنند که به شما اجازه می‌دهد تا نوع عناصر ذخیره شده در مجموعه را مشخص کنید.Iterators: برای پیمایش عناصر یک مجموعه از iterators استفاده می‌شود.Collections framework: مجموعه‌های جاوا بخشی از Collections framework هستند که شامل کلاس‌ها و رابط‌های مختلفی برای کار با مجموعه‌ها است.موارد اضافه شده در جاوا 8 برای کار با Collection ها :جاوا 8 با معرفی ویژگی‌های جدیدی، کار با مجموعه‌ها را بسیار قدرتمندتر و انعطاف‌پذیرتر کرده است. برخی از مهم‌ترین این ویژگی‌ها عبارتند از:1. Stream API:پردازش داده‌های موازی و موازی‌نما: استریم‌ها به شما اجازه می‌دهند تا روی مجموعه‌ها عملیات موازی یا موازی‌نما را به صورت روان انجام دهید.عملیات فیلتر کردن، نگاشت و کاهش: با استفاده از متدهایی مانند filter, map, reduce و ... می‌توانید به راحتی داده‌های خود را دستکاری کنید.پایپلاینینگ: عملیات مختلف را می‌توانید به صورت زنجیره‌ای روی استریم‌ها اعمال کنید.2. Lambda Expressions:نوشتن کدهای کوتاه و خواناتر: لامبدا اکسپرشنز به شما اجازه می‌دهند تا به صورت مختصر و مفید کدهای تابعی بنویسید.استفاده در متدهای تابعی: لامبدا اکسپرشنز به عنوان آرگومان متدهایی که یک رابط تابعی را انتظار دارند، استفاده می‌شوند.تسهیل کار با Stream API: لامبدا اکسپرشنز به طور گسترده‌ای در Stream API استفاده می‌شوند.3. Method References:مراجعه به متدها به عنوان آرگومان: متد رفرنس‌ها به شما اجازه می‌دهند تا به جای نوشتن لامبدا اکسپرشن، مستقیماً به یک متد موجود ارجاع دهید.کاهش حجم کد: متد رفرنس‌ها به شما کمک می‌کنند تا کدهای تکراری را کاهش دهید.4. Default Methods in Interfaces:اضافه کردن پیاده‌سازی پیش‌فرض به رابط‌ها: با استفاده از متدهای پیش‌فرض، می‌توانید به رابط‌های موجود متدهای جدید اضافه کنید بدون اینکه کلاس‌های پیاده‌ساز را تغییر دهید.تسهیل تکامل API: متدهای پیش‌فرض به شما کمک می‌کنند تا API‌های خود را بدون شکستن سازگاری با نسخه‌های قبلی، توسعه دهید.List&lt;String&gt; names = Arrays.asList(&amp;quotAlice&amp;quot, &amp;quotBob&amp;quot, &amp;quotCharlie&amp;quot);

// قبل از جاوا 8
List&lt;String&gt; longNames = new ArrayList&lt;&gt;();
for (String name : names) {
    if (name.length() &gt; 5) {
        longNames.add(name);
    }
}

// 8با استفاده از استریم و لامبدادر جاوا 
List&lt;String&gt; longNames = names.stream()
        .filter(name -&gt; name.length() &gt; 5)
        .collect(Collectors.toList());همانطور که می‌بینید، کد جاوا 8 بسیار خواناتر و خلاصه‌تر است.مزایای استفاده از این ویژگی‌ها:کدهای کوتاه‌تر و خواناتر: استفاده از لامبدا اکسپرشنز و Stream API باعث می‌شود کدهای شما کوتاه‌تر و خواناتر شوند.کارایی بهتر: Stream API امکان پردازش موازی داده‌ها را فراهم می‌کند که منجر به افزایش کارایی می‌شود.انعطاف‌پذیری بیشتر: با استفاده از این ویژگی‌ها، می‌توانید عملیات پیچیده‌ای را بر روی مجموعه‌ها به صورت ساده‌تر انجام دهید.در کل، جاوا 8 با معرفی این ویژگی‌ها، یک جهش بزرگ در زمینه برنامه‌نویسی تابعی و کار با مجموعه‌ها ایجاد کرده است.موارد اضافه شده در جاوا 10 برای کار با Collection ها :جاوا 10 تغییرات چشمگیری در زمینه کار با مجموعه‌ها ایجاد نکرد. تمرکز اصلی این نسخه بر روی بهبود عملکرد، قابلیت اطمینان و برخی ویژگی‌های زیرساختی بوده است.با این حال، برخی از تغییرات غیر مستقیم می‌توانند بر روی نحوه کار با مجموعه‌ها تاثیر بگذارند:بهبود عملکرد Garbage Collector: با بهبود عملکرد Garbage Collector، مدیریت حافظه در برنامه‌های جاوا به ویژه آن‌هایی که از مجموعه‌های بزرگ استفاده می‌کنند، بهبود یافته است. این امر می‌تواند به طور غیرمستقیم بر روی کارایی عملیات روی مجموعه‌ها تاثیر بگذارد.اضافه شدن Var برای پارامترهای لامبدا: این ویژگی به شما اجازه می‌دهد تا نوع پارامترهای لامبدا را به کامپایلر واگذار کنید. این می‌تواند کد شما را کوتاه‌تر و خواناتر کند، اما به طور مستقیم بر روی عملکرد مجموعه‌ها تاثیر نمی‌گذارد.موارد اضافه شده در جاوا 11 برای کار با Collection ها :جاوا 11، گرچه تغییرات بنیادینی در کار با مجموعه‌ها ایجاد نکرد، اما با معرفی ویژگی‌های جدید و بهبودهای عملکردی، بهینه‌سازی‌هایی را در این حوزه ارائه داده است.مهم‌ترین تغییراتی که در جاوا 11 در ارتباط با مجموعه‌ها رخ داده است، به شرح زیر است:1. مجموعه‌های غیرقابل تغییر (Immutable Collections):ایجاد مجموعه‌های خواندنی: یکی از مهم‌ترین ویژگی‌های اضافه شده در جاوا 11، امکان ایجاد مجموعه‌های غیرقابل تغییر است. این مجموعه‌ها پس از ایجاد، قابل تغییر نیستند و از ایجاد تغییرات ناخواسته در داده‌ها جلوگیری می‌کنند.بهبود امنیت و قابلیت اطمینان: مجموعه‌های غیرقابل تغییر به ویژه در محیط‌های چند نخی بسیار مفید هستند، زیرا از بروز خطاهای ناشی از تغییرات همزمان در مجموعه‌ها جلوگیری می‌کنند.بهبود عملکرد: در برخی موارد، استفاده از مجموعه‌های غیرقابل تغییر می‌تواند به بهبود عملکرد برنامه‌ها کمک کند.List&lt;String&gt; immutableList = List.of(&amp;quotapple&amp;quot, &amp;quotbanana&amp;quot, &amp;quotorange&amp;quot);
// immutableList.add(&amp;quotgrape&amp;quot); // این خط منجر به خطا می‌شود2. بهبود عملکرد Garbage Collector:مدیریت بهتر حافظه: با بهبود عملکرد Garbage Collector، مدیریت حافظه در برنامه‌های جاوا به ویژه آن‌هایی که از مجموعه‌های بزرگ استفاده می‌کنند، بهبود یافته است. این امر می‌تواند به طور غیرمستقیم بر روی کارایی عملیات روی مجموعه‌ها تاثیر بگذارد.3. سایر تغییرات:بهبودهای جزئی در API: برخی از متدهای مربوط به مجموعه‌ها در جاوا 11 بهبود یافته‌اند تا استفاده از آن‌ها آسان‌تر شود.حذف برخی از متدهای منسوخ شده: برخی از متدهای منسوخ شده که با مجموعه‌ها مرتبط بودند، از جاوا 11 حذف شده‌اند. متد toArray(IntFunction&lt;T[]&gt; generator) یکی از تغییرات مهمی است که در جاوا 11 به رابط Collection اضافه شده است. این متد به شما امکان می‌دهد تا آرایه‌ای با نوع دلخواه و اندازه مناسب از عناصر یک مجموعه ایجاد کنید.چرا این متد مهم است؟انعطاف‌پذیری بیشتر: قبل از جاوا 11، متد toArray() تنها امکان ایجاد آرایه‌ای از نوع مشخص شده در تعریف مجموعه را فراهم می‌کرد. اما متد جدید به شما اجازه می‌دهد تا نوع آرایه خروجی را به طور دلخواه مشخص کنید.جلوگیری از هشدارهای کامپایلر: در برخی موارد، استفاده از متد قدیمی toArray() منجر به هشدارهای کامپایلر می‌شد. متد جدید این مشکل را برطرف کرده است.بهبود کارایی: در برخی سناریوها، استفاده از متد جدید می‌تواند به بهبود کارایی کمک کند، زیرا از ایجاد آرایه‌های موقتی جلوگیری می‌کند.List&lt;String&gt; fruits = List.of(&amp;quotapple&amp;quot, &amp;quotbanana&amp;quot, &amp;quotorange&amp;quot);
String[] fruitArray = fruits.toArray(String[]::new);در مثال بالا، متد toArray() یک آرایه از نوع String[] با اندازه مناسب ایجاد می‌کند و عناصر مجموعه fruits را در آن کپی می‌کند.مزایای استفاده از این متد:نوع آرایه خروجی قابل کنترل است.خطاهای زمان کامپایل کاهش می‌یابد.در برخی موارد، کارایی بهبود می‌یابد.توجه:این متد از یک IntFunction به عنوان ورودی استفاده می‌کند که وظیفه ایجاد آرایه خالی با اندازه مشخص را بر عهده دارد.اندازه آرایه ایجاد شده برابر با تعداد عناصر مجموعه است.اگر نوع آرایه‌ای که شما مشخص می‌کنید با نوع عناصر مجموعه مطابقت نداشته باشد، یک ArrayStoreException رخ می‌دهد.در کل، متد toArray(IntFunction&lt;T[]&gt; generator) یک ابزار قدرتمند برای کار با مجموعه‌ها در جاوا 11 است و به شما امکان می‌دهد تا عملیات تبدیل مجموعه به آرایه را با انعطاف‌پذیری بیشتری انجام دهید.در کل، جاوا 11 با معرفی مجموعه‌های غیرقابل تغییر و بهبود عملکرد Garbage Collector، گامی مهم در جهت بهبود کارایی و امنیت برنامه‌های جاوا برداشته است.جمع‌بندیدر حالی که جاوا 11 تغییرات بنیادینی در نحوه کار با مجموعه‌ها ایجاد نکرده است، اما با معرفی ویژگی‌های جدید و بهبودهای عملکردی، بهینه‌سازی‌هایی را در این حوزه ارائه داده است. به ویژه، مجموعه‌های غیرقابل تغییر یک ابزار قدرتمند برای افزایش امنیت و قابلیت اطمینان برنامه‌ها هستند.هنوز وقت نکردم موارد مربوط به جاوا 14 و 17 و 21 رو بخونم اونها رو بهم وقتی خوندم قرار میدم .بیایم یه چنتا مثال برای حالت های مختلف بزنیم :1- خوب اولین مثال ها برای ابزار iterator هست :یک ابزار قدرتمند در جاوا برای پیمایش عناصر یک مجموعه (مانند List، Set، Map) است. این ابزار به شما اجازه می‌دهد تا بدون دانستن ساختار داخلی مجموعه، روی عناصر آن به صورت ترتیبی حرکت کنید.پیمایش یک ArrayList:import java.util.ArrayList;
import java.util.Iterator;

public class IteratorExample {
    public static void main(String[] args) {
        ArrayList&lt;String&gt; fruits = new ArrayList&lt;&gt;();
        fruits.add(&amp;quotApple&amp;quot);
        fruits.add(&amp;quotOrange&amp;quot);

        Iterator&lt;String&gt; iterator = fruits.iterator();
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println(fruit);
        }
    }
} 
//خروجی 
//Apple
//Orangeحذف عناصر در حین پیمایش:import java.util.ArrayList;
import java.util.Iterator;

public class IteratorExample {
    public static void main(String[] args) {
        ArrayList&lt;String&gt; numbers = new ArrayList&lt;&gt;();
        numbers.add(&amp;quotOne&amp;quot);
        numbers.add(&amp;quotTwo&amp;quot);
        numbers.add(&amp;quotThree&amp;quot);

        Iterator&lt;String&gt; iterator = numbers.iterator();
        while (iterator.hasNext()) {
            String number = iterator.next();
            if (number.equals(&amp;quotTwo&amp;quot)) {
                iterator.remove();
            }
        }

        // چاپ عناصر باقی مانده
   for (String number : numbers) {
            System.out.println(number);
        }
    }
}نکته مهم: هنگام حذف عنصری در حین پیمایش با Iterator، باید بلافاصله بعد از فراخوانی next() و قبل از فراخوانی next() بعدی، از متد remove() استفاده کنید. در غیر این صورت، یک IllegalStateException رخ خواهد داد.پیمایش یک HashMap:import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class IteratorExample {
    public static void main(String[] args) {
        Map&lt;String, Integer&gt; ages = new HashMap&lt;&gt;();
        ages.put(&amp;quotAlice&amp;quot, 30);
        ages.put(&amp;quotBob&amp;quot, 25);
        ages.put(&amp;quotCharlie&amp;quot, 35);

        // پیمایش کلیدها
   Iterator&lt;String&gt; keys = ages.keySet().iterator();
        while (keys.hasNext()) {
            String key = keys.next();
            System.out.println(&amp;quotKey: &amp;quot + key + &amp;quot, Value: &amp;quot + ages.get(key));
        }
    }
}مزایای استفاده از Iterator:پیمایش ایمن: از تغییرات تصادفی در مجموعه در حین پیمایش جلوگیری می‌کند.انعطاف‌پذیری: برای انواع مختلف مجموعه‌ها قابل استفاده است.پشتیبانی از عملیات حذف: امکان حذف عناصر در حین پیمایش را فراهم می‌کند.موارد استفاده از Iterator:پیمایش عناصر در مجموعه‌های مختلفحذف عناصر در حین پیمایشایجاد ساختارهای داده سفارشینکات مهم:یادتون باشه Iterator فقط برای پیمایش رو به جلو استفاده می‌شود.برای پیمایش به عقب یا دسترسی تصادفی به عناصر، از ساختارهای داده دیگری مانند List استفاده کنید.همیشه قبل از فراخوانی next(), از hasNext() استفاده کنید تا از خطای NoSuchElementException جلوگیری شود.با استفاده از Iterator، می‌توانید به صورت ایمن و انعطاف‌پذیر بر روی عناصر مجموعه‌های مختلف در جاوا پیمایش کنید.2- حالا یه چنتا مثال برای Stream Api بزنیم :یکی از قدرتمندترین ویژگی‌های جاوا 8 و نسخه‌های بعدی است که به شما اجازه می‌دهد روی مجموعه داده‌ها به صورت تابعی عمل کنید. با استفاده از Stream API می‌توانید عملیات فیلتر کردن، نگاشت، کاهش، مرتب‌سازی و بسیاری دیگر را به صورت زنجیره‌ای و خوانا اجرا کنید.فیلتر کردن عناصر یک لیست:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        List&lt;Integer&gt; numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

        // فیلتر کردن اعداد زوج
   List&lt;Integer&gt; evenNumbers = numbers.stream()
                .filter(n -&gt; n % 2 == 0)
                .collect(Collectors.toList());

        System.out.println(evenNumbers); // خروجی: [2, 4, 6, 8]
    }
}نگاشت عناصر به یک نوع داده دیگر:import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        List&lt;String&gt; names = Arrays.asList(&amp;quotAlice&amp;quot, &amp;quotBob&amp;quot, &amp;quotCharlie&amp;quot);

        // تبدیل هر نام به طول آن
   List&lt;Integer&gt; lengths = names.stream()
                .map(String::length)
                .collect(Collectors.toList());

        System.out.println(lengths); // خروجی: [5, 3, 7]
    }
}مرتب سازی عناصر :import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        List&lt;String&gt; names = Arrays.asList(&amp;quotAli&amp;quot, &amp;quotBahram&amp;quot, &amp;quotChangiz&amp;quot);

        // مرتب‌سازی بر اساس حروف الفبا
   List&lt;String&gt; sortedNames = names.stream()
                .sorted()
                .collect(Collectors.toList());

        System.out.println(sortedNames); // خروجی: [Ali, Bahram, Changiz]
    }
}یه کار سخت تر انجام بدیم مثلا پیدا کردن طولانی ترین کلمه در بین کلمات یک لیست:import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        List&lt;String&gt; words = Arrays.asList(&amp;quotapple&amp;quot, &amp;quotorange&amp;quot, &amp;quotkiwi&amp;quot);

        // پیدا کردن طولانی‌ترین کلمه
   String longestWord = words.stream()
                .max(Comparator.comparingInt(String::length))
                .orElse(&amp;quotNo words found&amp;quot);

        System.out.println(longestWord); // خروجی: orange
    }
}مزایای استفاده از Stream API:خوانایی بهتر کد: کدهای نوشته شده با Stream API معمولاً خواناتر و مختصرتر هستند.کارایی بهتر: در بسیاری از موارد، Stream API از حلقه‌های سنتی کارآمدتر است.تابعی بودن: Stream API از سبک برنامه‌نویسی تابعی پشتیبانی می‌کند که منجر به کدهای تمیزتر و قابل نگهداری‌تر می‌شود.انعطاف‌پذیری بالا: با استفاده از Stream API می‌توانید عملیات پیچیده و متنوعی را روی مجموعه داده‌ها انجام دهید.موارد استفاده رایج Stream API:پردازش فایل‌هاجمع‌آوری داده‌هاساختارهای داده پیچیدهمحاسبات آماریو ...میخواستم راجب Queue بگم و یه چنتا مثال بزنم اما دیگه داره یکم طولانی میشه این موارد رو بعدا در یک مقاله دیگه میگم .خوب بیایم یه چنتا سوال ساده ولی توی مصاحبه میاد بگیم :سوال اول : فرض کنید هیچ کدوم از کالکشن های مربوط به map مثلا HashMap , Map , HashSet , TreeMap و امثال اینها رو نداشتیم چطوری میتونیم خودمون یه Map یا HashMap بسازیم ؟ (راهنمایی مثلا بیایم با استفاده از list یا ArrayList و ... ایجادش کنیم )سوال دوم : یه Itarator سفارشی ایجاد کنید سوال سوم : چه زمانی استفاده از TreeMap نسبت به HashMap مناسب تر است؟سوال چهارم : TreeMap چگونه عناصر را مرتب می‌کند؟ چه مقایسه‌کننده‌ای برای این کار استفاده می‌شود؟سوال پنجم : چگونه می‌توان یک HashMap را به یک TreeMap تبدیل کرد؟سوال ششم : اگر تعداد زیادی از عناصر با همان هش کد را به HashMap اضافه کنیم چه اتفاقی می‌افتد؟ چگونه می‌توان با این مشکل مقابله کرد؟سوال هفتم : چه زمانی از HashMap استفاده می‌کنیم و چه زمانی از TreeMap؟سوال هشتم : تفاوت بین intermediate operations و terminal operations در Stream API چیست؟سوال نهم : تفاوت بین reduce و collect در Stream API چیست؟سوال دهم : چگونه می‌توان از ایجاد intermediate collection ها در Stream API جلوگیری کرد؟سوال یازدهم : چگونه می‌توان از ایجاد boxing و unboxing در Stream API جلوگیری کرد؟سوال دوازدهم : functional interfaces چیست؟ و چه تاثیری توی Stream Api داره ؟اینا سوالاتی بود که توی مصاحبه ازم پرسیده بودند و خیلی خوب و مفید و جالبه منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 21:56:36 +0330</pubDate>
            </item>
                    <item>
                <title>Autoboxing in Java</title>
                <link>https://virgool.io/Javenture/autoboxing-in-java-yj5hpnyi1pz1</link>
                <description>اتوبوکسینگ (Autoboxing) در جاوادر این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingاتوبوکسینگ (Autoboxing) یک ویژگی در زبان برنامه‌نویسی جاوا است که به طور خودکار انواع داده اولیه (primitive types) را به اشیاء بسته‌بندی (wrapper classes) مربوطه تبدیل می‌کند. این ویژگی از نسخه 5 جاوا معرفی شده است و به برنامه‌نویسان این امکان را می‌دهد که بدون نیاز به نوشتن کد اضافی، بین انواع داده اولیه و اشیاء بسته‌بندی شده جابجا شوند.انواع داده اولیه و اشیاء بسته‌بندی شده:int و Integerdouble و Doubleboolean و Booleanchar و Characterو سایر انواع داده اولیه و بسته‌بندی شده مربوطهint x = 10;
Integer y = x; // اتوبوکسینگ: int به Integer تبدیل می‌شوددر این مثال، مقدار اولیه x از نوع int به طور خودکار به یک شیء از نوع Integer تبدیل شده و به متغیر y اختصاص داده می‌شود.چه زمانی اتوبوکسینگ اتفاق می‌افتد؟تخصیص به یک متغیر از نوع بسته‌بندی شده: وقتی یک مقدار اولیه به یک متغیر از نوع بسته‌بندی شده اختصاص داده شود، اتوبوکسینگ رخ می‌دهد.گذراندن یک آرگومان اولیه به یک متد که یک شیء بسته‌بندی شده را انتظار دارد: هنگام ارسال یک مقدار اولیه به عنوان آرگومان به یک متد که یک شیء بسته‌بندی شده را به عنوان پارامتر دریافت می‌کند، اتوبوکسینگ اتفاق می‌افتد.اضافه کردن یک مقدار اولیه به یک مجموعه از اشیاء بسته‌بندی شده: هنگام اضافه کردن یک مقدار اولیه به یک مجموعه مانند ArrayList&lt;Integer&gt;, اتوبوکسینگ رخ می‌دهد.چرا از اتوبوکسینگ استفاده می‌شود؟سادگی کد: با اتوبوکسینگ، نیازی به نوشتن کد اضافی برای تبدیل انواع داده اولیه به اشیاء بسته‌بندی شده نیست.یکپارچگی با مجموعه‌ها و سایر APIها: بسیاری از APIهای جاوا از اشیاء بسته‌بندی شده استفاده می‌کنند. با اتوبوکسینگ، می‌توان به راحتی انواع داده اولیه را با این APIها یکپارچه کرد.نکات مهم درباره اتوبوکسینگ:اتوباکسیگ یک ویژگی کامپایلری است: کامپایلر جاوا به طور خودکار کد لازم برای تبدیل انواع داده را تولید می‌کند.اتوباکسیگ برای هر مقدار جدید ایجاد می‌شود: اگر چندین بار یک مقدار اولیه به یک متغیر از نوع بسته‌بندی شده اختصاص داده شود، برای هر بار یک شیء جدید ایجاد می‌شود.برای مقایسه اشیاء بسته‌بندی شده از equals() استفاده کنید: برای مقایسه دو شیء بسته‌بندی شده، از متد equals() استفاده کنید. استفاده از عملگر == برای مقایسه اشیاء بسته‌بندی شده ممکن است نتایج غیرمنتظره‌ای را به همراه داشته باشد.مثال برای مقایسه با equals():Integer a = 100;
Integer b = 100;
System.out.println(a == b); // ممکن است true یا false باشد (بسته به پیاده‌سازی JVM)
System.out.println(a.equals(b)); // همیشه trueجمع‌بندی:اتوبوکسینگ یک ویژگی مفید در جاوا است که به برنامه‌نویسان اجازه می‌دهد به راحتی بین انواع داده اولیه و اشیاء بسته‌بندی شده جابجا شوند. با درک نحوه کار اتوبوکسینگ، می‌توانید کدهای جاوا تمیزتر و خواناتر بنویسید.اتوبوکسینگ (Autoboxing) در جاوااتوبوکسینگ (Autoboxing) یک ویژگی در زبان برنامه‌نویسی جاوا است که به طور خودکار انواع داده اولیه (primitive types) را به اشیاء بسته‌بندی (wrapper classes) مربوطه تبدیل می‌کند. این ویژگی از نسخه 5 جاوا معرفی شده است و به برنامه‌نویسان این امکان را می‌دهد که بدون نیاز به نوشتن کد اضافی، بین انواع داده اولیه و اشیاء بسته‌بندی شده جابجا شوند.انواع داده اولیه و اشیاء بسته‌بندی شده:int و Integerdouble و Doubleboolean و Booleanchar و Characterو سایر انواع داده اولیه و بسته‌بندی شده مربوطهint x = 10;
Integer y = x; //روش اول
y = Integer.valueOf(x); // روش دوم
x = y.intValue(); // روش سومدر این مثال، مقدار اولیه x از نوع int به طور خودکار به یک شیء از نوع Integer تبدیل شده و به متغیر y اختصاص داده می‌شود.چه زمانی اتوبوکسینگ اتفاق می‌افتد؟تخصیص به یک متغیر از نوع بسته‌بندی شده: وقتی یک مقدار اولیه به یک متغیر از نوع بسته‌بندی شده اختصاص داده شود، اتوبوکسینگ رخ می‌دهد.گذراندن یک آرگومان اولیه به یک متد که یک شیء بسته‌بندی شده را انتظار دارد: هنگام ارسال یک مقدار اولیه به عنوان آرگومان به یک متد که یک شیء بسته‌بندی شده را به عنوان پارامتر دریافت می‌کند، اتوبوکسینگ اتفاق می‌افتد.اضافه کردن یک مقدار اولیه به یک مجموعه از اشیاء بسته‌بندی شده: هنگام اضافه کردن یک مقدار اولیه به یک مجموعه مانند ArrayList&lt;Integer&gt;, اتوبوکسینگ رخ می‌دهد.چرا از اتوبوکسینگ استفاده می‌شود؟سادگی کد: با اتوبوکسینگ، نیازی به نوشتن کد اضافی برای تبدیل انواع داده اولیه به اشیاء بسته‌بندی شده نیست.یکپارچگی با مجموعه‌ها و سایر APIها: بسیاری از APIهای جاوا از اشیاء بسته‌بندی شده استفاده می‌کنند. با اتوبوکسینگ، می‌توان به راحتی انواع داده اولیه را با این APIها یکپارچه کرد.نکات مهم درباره اتوبوکسینگ:اتوباکسیگ یک ویژگی کامپایلری است: کامپایلر جاوا به طور خودکار کد لازم برای تبدیل انواع داده را تولید می‌کند.اتوباکسیگ برای هر مقدار جدید ایجاد می‌شود: اگر چندین بار یک مقدار اولیه به یک متغیر از نوع بسته‌بندی شده اختصاص داده شود، برای هر بار یک شیء جدید ایجاد می‌شود.برای مقایسه اشیاء بسته‌بندی شده از equals() استفاده کنید: برای مقایسه دو شیء بسته‌بندی شده، از متد equals() استفاده کنید. استفاده از عملگر == برای مقایسه اشیاء بسته‌بندی شده ممکن است نتایج غیرمنتظره‌ای را به همراه داشته باشد.مثال برای مقایسه با equals():Integer a = 100;
Integer b = 100;
System.out.println(a == b); // ممکن است true یا false باشد (بسته به پیاده‌سازی JVM)
System.out.println(a.equals(b)); // همیشه trueجمع‌بندی:اتوبوکسینگ یک ویژگی مفید در جاوا است که به برنامه‌نویسان اجازه می‌دهد به راحتی بین انواع داده اولیه و اشیاء بسته‌بندی شده جابجا شوند. با درک نحوه کار اتوبوکسینگ، می‌توانید کدهای جاوا تمیزتر و خواناتر بنویسید.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 17:07:30 +0330</pubDate>
            </item>
                    <item>
                <title>Ternary Operator in Java</title>
                <link>https://virgool.io/Javenture/ternary-operator-in-java-t872v8oohpkq</link>
                <description>چرا عملگرهای سه گانه (Ternary Operator) در جاوا توابع void را قبول نمی‌کنند؟در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingعملگرهای سه گانه در جاوا یک ساختار دستوری فشرده برای بیان عبارات شرطی هستند. آن‌ها به این صورت عمل می‌کنند که یک شرط را بررسی کرده و بر اساس نتیجه آن، یکی از دو مقدار را برمی‌گردانند.دلیل اصلی اینکه عملگرهای سه گانه توابع void را قبول نمی‌کنند، ماهیت بازگرداندن مقدار است.ماهیت عملگرهای سه گانه: عملگرهای سه گانه به طور ذاتی برای بازگرداندن یک مقدار طراحی شده‌اند. این مقدار می‌تواند از هر نوع داده‌ای باشد، به جز انواع void.توابع void: توابع void هیچ مقداری را برنمی‌گردانند. آن‌ها صرفاً یک سری عملیات را انجام می‌دهند و سپس خاتمه می‌یابند.int x = 10;
int y = 20;
int max = (x &gt; y) ? x : y; // عملگر سه گانه برای پیدا کردن مقدار بزرگتردر مثال بالا، عملگر سه گانه مقدار بزرگتر بین x و y را محاسبه کرده و آن را به متغیر max اختصاص می‌دهد.چرا این محدودیت وجود دارد؟سادگی و خوانایی: اگر عملگرهای سه گانه اجازه می‌دادند که توابع void را فراخوانی کنند، ساختار دستوری پیچیده‌تر و کمتر خوانا می‌شد.تضمین بازگرداندن مقدار: با این محدودیت، اطمینان حاصل می‌شود که عملگرهای سه گانه همیشه یک مقدار را برمی‌گردانند و از خطاهای احتمالی جلوگیری می‌شود.راه حل‌های جایگزین:اگر نیاز دارید که یک عمل شرطی را بر روی یک تابع void انجام دهید، می‌توانید از ساختارهای کنترلی مانند if-else استفاده کنید.if (condition) {
    // فراخوانی تابع void
    myVoidMethod();
} else {
    // انجام کار دیگری
}جمع‌بندی:محدودیت عملگرهای سه گانه در پذیرش توابع void به دلیل ماهیت بازگرداندن مقدار این عملگرها است. این محدودیت به سادگی و خوانایی کد کمک می‌کند و از خطاهای احتمالی جلوگیری می‌کند. در مواردی که نیاز به انجام یک عمل شرطی بر روی یک تابع void دارید، بهتر است از ساختارهای کنترلی مانند if-else استفاده کنید.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 16:51:32 +0330</pubDate>
            </item>
                    <item>
                <title>Integer Pool vs String Pool in Java</title>
                <link>https://virgool.io/Javenture/integer-pool-vs-string-pool-in-java-i0uraaa70tlx</link>
                <description>همه چی در مورد stringPool و IntegerPool (یعنی هرچی من بلد بودم :) ) :در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingدر جاوا، برای بهینه سازی مصرف حافظه و افزایش سرعت اجرای برنامه، از مکانیزمی به نام Pooling استفاده می‌شود. این مکانیزم به این صورت عمل می‌کند که اشیاء تکراری به جای ایجاد مجدد، به یک نسخه مشترک اشاره می‌کنند. در این بین، دو نوع Pool بسیار مهم به نام‌های String Pool و Integer Pool وجود دارند.String Poolتعریف: String Pool یک ناحیه خاص از حافظه Heap است که برای ذخیره رشته‌های لیترالی استفاده می‌شود. هنگامی که یک رشته لیترال در کد شما ایجاد می‌شود، ابتدا در String Pool جستجو می‌شود. اگر رشته‌ای با همان مقدار وجود داشته باشد، به جای ایجاد یک رشته جدید، به همان رشته موجود اشاره می‌شود.هدف:   صرفه‌جویی در حافظه: از ایجاد نسخه‌های تکراری از رشته‌ها جلوگیری می‌کند. افزایش سرعت: مقایسه رشته‌ها سریع‌تر انجام می‌شود زیرا نیازی به مقایسه کاراکتر به کاراکتر نیست.نحوه کار:هنگامی که یک رشته لیترال ایجاد می‌شود، ابتدا در String Pool جستجو می‌شود. اگر رشته وجود داشته باشد، ارجاعی به آن به متغیر اختصاص داده می‌شود. اگر رشته وجود نداشته باشد، در String Pool ایجاد شده و ارجاعی به آن به متغیر اختصاص داده می‌شود.Integer Poolتعریف: Integer Pool نیز مشابه String Pool عمل می‌کند، اما به جای رشته‌ها، اعداد صحیح را ذخیره می‌کند. البته، برخلاف String Pool، Integer Pool محدود به یک بازه خاصی از اعداد است.هدف:   صرفه‌جویی در حافظه: از ایجاد اشیاء Integer جدید برای اعداد صحیح متداول جلوگیری می‌کند.     افزایش سرعت: مقایسه اعداد صحیح سریع‌تر انجام می‌شود.محدودیت:معمولاً اعداد صحیح بین -128 تا 127 در Integer Pool ذخیره می‌شوند. برای اعداد خارج از این بازه، یک شیء Integer جدید ایجاد می‌شود.مثال:String s1 = &amp;quotسلام&amp;quot
String s2 = &amp;quotسلام&amp;quot
//    توی این حالت یدونه سلام جدید علاوه بر سلام قبلی ساخته میشود ، به شکل اول مقاله دقت کنید 
String h = new String(&amp;quotسلام&amp;quot); 
System.out.println(s1 == s2); // true
System.out.println(s1 == h); // false

Integer i1 = 100;
Integer i2 = 100;
System.out.println(i1 == i2); // true (اگر در محدوده Integer Pool باشد)

Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // false (خارج از محدوده Integer Pool)نکات مهمString Pool تغییرناپذیر است: رشته‌های موجود در String Pool تغییرناپذیر هستند. هرگونه تغییری در یک رشته باعث ایجاد یک رشته جدید می‌شود.Integer Pool ممکن است در پیاده‌سازی‌های مختلف جاوا متفاوت باشد: محدوده اعداد ذخیره شده در Integer Pool ممکن است در پیاده‌سازی‌های مختلف جاوا متفاوت باشد.استفاده از valueOf(): برای ایجاد اشیاء Integer، بهتر است از متد valueOf() کلاس Integer استفاده کنید. این متد ابتدا در Integer Pool جستجو می‌کند و در صورت وجود، به همان شیء موجود اشاره می‌کند.نتیجه‌گیری در آخر بگیم که String Pool و Integer Pool دو مکانیزم مهم در جاوا هستند که به بهینه‌سازی مصرف حافظه و افزایش سرعت اجرای برنامه کمک می‌کنند. درک این مفاهیم برای برنامه‌نویسان جاوا بسیار مهم است تا بتوانند کدهای کارآمدتری بنویسند.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 16:34:11 +0330</pubDate>
            </item>
                    <item>
                <title>Integer constant pool in java</title>
                <link>https://virgool.io/Javenture/integer-constant-pool-eowskbz7tigc</link>
                <description>همه چیز درباره Integer constant pool ( تا اونجایی که من بلدم :)  ) :در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingConstant Pool : یک ناحیه خاص در حافظه است که در فایل کلاس جاوا قرار دارد و شامل اطلاعات ثابت مورد نیاز برای اجرای کلاس می‌شود. این اطلاعات شامل رشته‌های لیترالی، اعداد ثابت، ارجاعات به متدها، کلاس‌ها و رابط‌ها است. به عبارت ساده‌تر، Constant Pool یک نوع جدول نمادین برای کلاس است که به کامپایلر و ماشین مجازی جاوا کمک می‌کند تا در زمان اجرا به اطلاعات مورد نیاز دسترسی پیدا کنند.Integer Constant Poolبخشی از Constant Pool که به اعداد صحیح اختصاص داده شده است، Integer Constant Pool نام دارد. هنگامی که یک عدد صحیح لیترالی (مانند 10، 20، ...) در کد جاوا استفاده می‌شود، این عدد در Integer Constant Pool ذخیره می‌شود.چرا از Integer Constant Pool استفاده می‌شود؟صرفه‌جویی در حافظه: اگر چندین متغیر با یک مقدار صحیح یکسان مقداردهی شوند، تنها یک نسخه از آن مقدار در Constant Pool ذخیره می‌شود و سایر متغیرها به همان نسخه اشاره می‌کنند.بهبود عملکرد: جستجو در Constant Pool بسیار سریع‌تر از جستجو در Heap است.تسهیل عملیات مقایسه: مقایسه دو عدد صحیح که در Constant Pool قرار دارند بسیار ساده و سریع است.مکانیزم کار Integer Constant Pool:ایجاد عدد صحیح: هنگامی که یک عدد صحیح لیترالی در کد نوشته می‌شود، کامپایلر آن را به یک ارجاع به Constant Pool تبدیل می‌کند.جستجو در Constant Pool: در زمان اجرا، ماشین مجازی جاوا ابتدا در Constant Pool به دنبال عددی با همان مقدار جستجو می‌کند.اگر عدد موجود باشد: اگر عدد مورد نظر در Constant Pool یافت شود، ارجاع به آن به متغیر اختصاص داده می‌شود.اگر عدد موجود نباشد: اگر عدد مورد نظر در Constant Pool وجود نداشته باشد، یک ورودی جدید برای آن در Constant Pool ایجاد می‌شود و سپس ارجاع به آن به متغیر اختصاص داده می‌شود.int x = 10;
int y = 10;در این مثال، هر دو متغیر x و y به همان عدد صحیح در Constant Pool اشاره می‌کنند.تفاوت بین Integer Constant Pool و String Constant Pool:نوع داده: Integer Constant Pool برای اعداد صحیح و String Constant Pool برای رشته‌ها استفاده می‌شود.محدودیت‌ها: در Integer Constant Pool، اعداد صحیح باید در محدوده خاصی باشند، در حالی که در String Constant Pool، طول رشته‌ها محدودیتی ندارد.نکات مهم:اتوکلاسینگ: در جاوا، اعداد صحیح اولیه (primitive) به طور خودکار به اشیاء Integer بسته‌بندی می‌شوند (boxing). این عمل ممکن است باعث شود که اعداد صحیح در Constant Pool قرار نگیرند.Integer Cache: در برخی پیاده‌سازی‌های جاوا، یک کش داخلی برای اعداد صحیح کوچک وجود دارد که به بهبود عملکرد دسترسی به اعداد صحیح متداول کمک می‌کند.تغییرناپذیری (Immutability): اشیاء Integer که در Constant Pool قرار دارند، تغییرناپذیر هستند.جمع‌بندی:در نهایت اینکه Integer Constant Pool یک ویژگی مهم در جاوا است که به بهبود عملکرد و مصرف حافظه کمک می‌کند. درک نحوه کار Constant Pool به شما کمک می‌کند تا کدهای جاوا بهتری بنویسید.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 16:11:36 +0330</pubDate>
            </item>
                    <item>
                <title>memoryHeap and memoryLeak in java</title>
                <link>https://virgool.io/Javenture/memoryheap-and-memoryleak-in-java-cscqnk2ap5ry</link>
                <description>درباره memoryHeap و memoryLeak ، مقایسه باهم ، و  چه مواردی رو در زمان استفاده از collection ها باید رعایت کنیم که مشکل memoryHeap نداشته باشیم؟در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingتفاوت بین Memory Heap و Memory Leak و نحوه جلوگیری از آن در Collectionها :Memory Heap : بخشی از حافظه است که برای تخصیص پویای حافظه به اشیا در زمان اجرای برنامه استفاده می‌شود. به عبارت دیگر، زمانی که یک شیء جدید در برنامه ایجاد می‌شود، فضایی برای آن در Heap رزرو می‌شود. Heap یک فضای بزرگ و مشترک است که توسط تمام اشیاء برنامه استفاده می‌شود.Memory Leak: زمانی رخ می‌دهد که برنامه‌ای حافظه‌ای را که دیگر به آن نیازی ندارد، آزاد نمی‌کند. این حافظه بلااستفاده در Heap باقی می‌ماند و در نهایت می‌تواند منجر به کاهش عملکرد برنامه، کند شدن سیستم و حتی کرش برنامه شود.جدول مقایسه :دلایل ایجاد Memory Leak در مجموعه‌هاارجاع‌های اشتباه: اگر به یک شیء  ، ارجاعی وجود داشته باشد که دیگر قابل دسترسی نباشد، Garbage Collector نمی‌تواند آن شیء را حذف کند.حلقه‌های ارجاع: زمانی که دو یا چند شیء به صورت دایره‌ای به هم ارجاع دهند، Garbage Collector نمی‌تواند هیچ‌کدام از آن‌ها را حذف کند.استفاده نادرست از Static متغیرها: اگر یک متغیر Static به یک شیء در مجموعه اشاره کند، تا زمانی که برنامه اجرا می‌شود، آن شیء از حافظه آزاد نمی‌شود.Listeners و Callbacks: اگر Listener یا Callback به یک شیء در مجموعه اضافه شود و هرگز حذف نشود، می‌تواند باعث ایجاد Memory Leak شود.نحوه جلوگیری از Memory Leak در مجموعه‌هامدیریت صحیح ارجاعات: پس از اینکه به یک شیء دیگر نیازی ندارید، ارجاع به آن را null کنید.استفاده از WeakReferences: برای ارجاع‌های ضعیف به اشیاء استفاده کنید تا Garbage Collector بتواند آن‌ها را به راحتی حذف کند.حذف Listenerها و Callbackها: پس از اینکه به Listener یا Callback‌ای دیگر نیازی ندارید، آن را حذف کنید.استفاده از Finalizers با احتیاط: Finalizers می‌توانند به جای Garbage Collector برای آزادسازی منابع استفاده شوند، اما استفاده نادرست از آن‌ها می‌تواند باعث ایجاد مشکل شود.استفاده از ابزارهای تحلیل حافظه: ابزارهایی مانند Memory Profiler می‌توانند به شما در شناسایی و رفع مشکلات Memory Leak کمک کنند.نکات مهم در استفاده از مجموعه‌هاانتخاب مجموعه مناسب: بر اساس نوع داده‌ها و عملیات مورد نظر، مجموعه مناسب را انتخاب کنید.حجم مجموعه‌ها را کنترل کنید: از ایجاد مجموعه‌های بسیار بزرگ و غیر ضروری خودداری کنید.از متدهای clear() و remove() استفاده کنید: برای حذف عناصر از مجموعه‌ها به صورت دستی استفاده کنید.از ابزارهای جمع‌آوری زباله استفاده کنید: از ابزارهایی مانند Garbage Collector برای مدیریت خودکار حافظه استفاده کنید.در نهایت، برای جلوگیری از Memory Leak در مجموعه‌ها، باید به مدیریت صحیح ارجاعات، استفاده از ابزارهای تحلیل حافظه و انتخاب مجموعه مناسب توجه کنید.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 16:00:00 +0330</pubDate>
            </item>
                    <item>
                <title>Heap and Stack in Java</title>
                <link>https://virgool.io/Javenture/heap-and-stack-in-java-kvyy6cnrd881</link>
                <description>راجب heap و stack و اینکه هر کدام از collection ها چطوری در heap و stack قرار میگیرند؟در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingدر برنامه‌نویسی جاوا، دو ناحیه اصلی از حافظه برای ذخیره داده‌ها استفاده می‌شود: Heap و Stack. درک تفاوت بین این دو ناحیه و نحوه قرارگیری مجموعه‌ها در آن‌ها برای درک بهتر مدیریت حافظه و عملکرد برنامه بسیار مهم است.اول : Stack (پشته)ویژگی‌ها:FIFO (First In, First Out):              داده‌ها به ترتیب وارد شدن و خارج شدن ذخیره می‌شوند. فضای محدود: اندازه Stack معمولاً نسبت به Heap کوچک‌تر است. محلی برای متغیرهای محلی: متغیرهای محلی یک متد، ارجاعات به اشیاء و داده‌های اولیه در Stack              ذخیره می‌شوند. خودکار: مدیریت Stack توسط کامپایلر به صورت خودکار انجام می‌شود.نحوه قرارگیری مجموعه‌ها:            ارجاعات: خود مجموعه (مانند ArrayList، HashSet و ...) در Heap ذخیره می‌شود. متغیرهای محلی: اما متغیرهایی که به این مجموعه‌ها اشاره می‌کنند (مانند ارجاعات به اشیاء) در            Stack ذخیره می‌شوند.دوم : Heapویژگی‌ها:Dynamic allocation:           فضای مورد نیاز برای اشیاء به صورت پویا در زمان اجرا تخصیص داده می‌شود.            فضای بزرگ: معمولاً بزرگ‌ترین ناحیه حافظه در یک برنامه است. Garbage collection:           اشیاء بلااستفاده به طور خودکار توسط Garbage Collector از Heap حذف می‌شوند.نحوه قرارگیری مجموعه‌ها:           اشیاء: خود اشیاء مجموعه‌ها (مانند عناصر یک ArrayList) در Heap ذخیره می‌شوند.            ساختار داده: ساختار داخلی مجموعه (مانند آرایه در ArrayList یا درخت در TreeMap) نیز در Heap قرار            می‌گیرد.خلاصهStack: برای متغیرهای محلی، ارجاعات به اشیاء و داده‌های اولیه استفاده می‌شود.Heap: برای اشیاء و ساختارهای داده‌ای بزرگ‌تر استفاده می‌شود.مثال خیلی ساده :public class Main {
    public static void main(String[] args) {
        List&lt;String&gt; list = new ArrayList&lt;&gt;(); // ارجاع به ArrayList در Stack، خود ArrayList در Heap

        list.add(&amp;quotHello&amp;quot); // رشته &amp;quotHello&amp;quot در Heap، ارجاع به آن در Stack
    }
}در این مثال:متغیر list از نوع ArrayList در Stack ذخیره می‌شود.خود شیء ArrayList و رشته &quot;Hello&quot; در Heap ذخیره می‌شوند.list یک ارجاع به آدرس شیء ArrayList در Heap است.نکات مهماندازه Stack: اندازه Stack معمولاً محدود است و ممکن است باعث ایجاد خطای StackOverflowError شود اگر تعداد زیادی فراخوانی متد به صورت تو در تو انجام شود.Garbage Collection:مدیریت حافظه Heap به عهده خود برنامه نویس است اما در جاوا Garbage Collector نیز به طور خودکار اشیاء بلا استفاده را از heap حذف میکند.انتخاب مجموعه مناسب: انتخاب نوع مجموعه (ArrayList، LinkedList، HashMap و ...) و نوع داده‌ها، به عملیات مورد نظر و محدودیت‌های حافظه بستگی دارد.درک این مفاهیم به شما کمک می‌کند تا برنامه‌های کارآمدتر و با مصرف حافظه کمتر بنویسید.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 15:09:22 +0330</pubDate>
            </item>
                    <item>
                <title>HashMap VS TreeMap VS Set</title>
                <link>https://virgool.io/Javenture/hashmap-vs-treemap-vs-set-bw88w5wphp85</link>
                <description>فرق بین hashMap , treeMap , set چیست ؟در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingدر جاوا، HashMap، TreeMap و Set همه برای ذخیره مجموعه‌ای از داده‌ها استفاده می‌شوند، اما هر کدام ویژگی‌ها و کاربردهای خاص خود را دارند. برای درک بهتر این تفاوت‌ها، بیایید هر یک را به طور جداگانه بررسی کنیم:HashMapتعریف: HashMap یک پیاده‌سازی از رابط Map است که از یک جدول هش برای ذخیره داده‌ها استفاده می‌کند.ویژگی‌ها:           سرعت: عملیات جستجو، درج و حذف در HashMap به طور متوسط زمان ثابت (O(1)) دارند که آن را            بسیار سریع می‌کند.            ترتیب: عناصر در HashMap به صورت نامنظم ذخیره می‌شوند.            کلیدها: کلیدها باید منحصر به فرد باشند و می‌توانند null باشند.            مقدارها: مقدارها می‌توانند تکراری باشند و می‌توانند null باشند.کاربرد: زمانی که به سرعت دسترسی به عناصر نیاز دارید و ترتیب ذخیره‌سازی اهمیت ندارد، از HashMap استفاده می‌شود.TreeMapتعریف: TreeMap یک پیاده‌سازی دیگر از رابط Map است که از یک درخت  برای ذخیره داده‌ها استفاده می‌کند.ویژگی‌ها:           سرعت: عملیات جستجو، درج و حذف در TreeMap زمان لگاریتمی (O(log n)) دارند.            ترتیب: عناصر در TreeMap بر اساس کلیدهای طبیعی یا یک مقایسه‌کننده سفارشی مرتب می‌شوند.                      کلیدها: کلیدها باید منحصر به فرد باشند و قابل مقایسه باشند.           مقدارها: مقدارها می‌توانند تکراری باشند و می‌توانند null باشند.کاربرد: زمانی که به یک مجموعه مرتب شده نیاز دارید و ترتیب ذخیره‌سازی مهم است، از TreeMap استفاده می‌شود.Setتعریف: Set یک رابط در جاوا است که مجموعه‌ای از عناصر منحصر به فرد را نمایش می‌دهد.ویژگی‌ها:            عناصر منحصر به فرد: هر عنصر فقط یک بار می‌تواند در یک Set وجود داشته باشد.            ترتیب: ترتیب عناصر در Set مشخص نیست (مگر اینکه از یک پیاده‌سازی خاص مانند TreeSet استفاده             شود).پیاده‌سازی‌ها:  HashSet: بر اساس HashMap ساخته شده و سریع‌ترین پیاده‌سازی Set است. TreeSet: بر اساس TreeMap ساخته شده و عناصر را به صورت مرتب شده ذخیره می‌کند.جدول مقایسه :چه زمانی از کدام یک استفاده کنیم؟HashMap: زمانی که به سرعت دسترسی به عناصر نیاز دارید و ترتیب ذخیره‌سازی اهمیت ندارد.TreeMap: زمانی که به یک مجموعه مرتب شده نیاز دارید و ترتیب ذخیره‌سازی مهم است.HashSet: زمانی که به یک مجموعه منحصر به فرد نیاز دارید و سرعت مهمترین عامل است.TreeSet: زمانی که به یک مجموعه منحصر به فرد و مرتب شده نیاز دارید.مثال خیلی ساده :// HashMap
Map&lt;String, Integer&gt; map = new HashMap&lt;&gt;();
map.put(&amp;quotapple&amp;quot, 1);
map.put(&amp;quotbanana&amp;quot, 2);

// TreeMap
Map&lt;String, Integer&gt; treeMap = new TreeMap&lt;&gt;();
treeMap.put(&amp;quotapple&amp;quot, 1);
treeMap.put(&amp;quotbanana&amp;quot, 2);

// HashSet
Set&lt;String&gt; set = new HashSet&lt;&gt;();
set.add(&amp;quotapple&amp;quot);
set.add(&amp;quotbanana&amp;quot);در نهایت، انتخاب بین HashMap، TreeMap و Set به نیازهای خاص برنامه شما بستگی دارد.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 14:43:56 +0330</pubDate>
            </item>
                    <item>
                <title>Integer vs int in java</title>
                <link>https://virgool.io/Javenture/integer-vs-int-in-java-qucz0toqebio</link>
                <description>در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingفرق بین Integer با int چیست ؟در جاوا، هر دو int و Integer برای نمایش اعداد صحیح استفاده می‌شوند، اما تفاوت‌های مهمی بین آن‌ها وجود دارد که درک این تفاوت‌ها برای برنامه‌نویسی موثر در جاوا ضروری است.int: نوع داده اولیه (Primitive Type)نوع داده پایه: int یک نوع داده اولیه در جاوا است که مستقیماً مقدار عددی را نگه می‌دارد.حافظه: به صورت مستقیم در حافظه ذخیره می‌شود و به یک آدرس حافظه اشاره نمی‌کند.عملیات: عملیات روی intها بسیار سریع هستند زیرا مستقیماً روی مقادیر انجام می‌شوند.تبدیل نوع : در برخی موارد، جاوا به صورت خودکار int را به Integer تبدیل می‌کند ، به ویژه در مواقعی که نیاز به یک شیء باشد.Integer: کلاس (Class)شیء: Integer یک کلاس است و هر متغیر از نوع Integer در واقع یک شیء است که یک مقدار عددی را در خود نگه می‌دارد.حافظه: در هپ (Heap) ذخیره می‌شود و به یک آدرس حافظه اشاره می‌کند.متدها: کلاس Integer دارای متدهای مختلفی برای انجام عملیات روی اعداد صحیح است، مانند تبدیل به رشته، مقایسه با سایر اعداد و غیره.تبدیل نوع : در برخی موارد، جاوا به صورت خودکار Integer را به int تبدیل می‌کند.جدول مقایسه:چه زمانی از کدام یک استفاده کنیم؟int:زمانی که به یک عدد صحیح ساده نیاز دارید و به متدهای اضافی نیازی ندارید. در حلقه‌ها، محاسبات عددی و سایر عملیات که به سرعت نیاز دارند. در آرایه‌ها، جایی که همه عناصر باید از یک نوع داده باشند.Integer:زمانی که به یک شیء نیاز دارید، مانند زمانی که می‌خواهید یک عدد صحیح را در یک مجموعه (Collection) قرار دهید. زمانی که به متدهای اضافی کلاس Integer نیاز دارید. در جاهایی که اتوکلاسینگ به طور خودکار رخ می‌دهد.مثال خیلی ساده :int x = 10; // یک عدد صحیح ساده
Integer y = new Integer(20); // یک شیء از نوع Integer

// Auto Classing
List&lt;Integer&gt; list = new ArrayList&lt;&gt;();
list.add(x); // int به طور خودکار به Integer تبدیل می‌شودخلاصهانتخاب بین int و Integer به نیازهای خاص برنامه شما بستگی دارد. اگر به یک عدد صحیح ساده نیاز دارید، int انتخاب بهتری است. اما اگر به یک شیء نیاز دارید یا به متدهای اضافی نیاز دارید، Integer انتخاب مناسب‌تری است.نکته مهم: در بسیاری از موارد، جاوا به صورت خودکار بین int و Integer تبدیل می‌کند، اما درک تفاوت‌های بین این دو برای نوشتن کد تمیز و کارآمد بسیار مهم است.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 14:01:39 +0330</pubDate>
            </item>
                    <item>
                <title>StringBuilder vs StringBuffer vs String in java</title>
                <link>https://virgool.io/Javenture/stringbuilder-vs-stringbuffer-vs-string-in-java-dlof7gytwsck</link>
                <description>در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingدر جاوا، سه کلاس اصلی برای کار با داده‌های متنی وجود دارد: String، StringBuilder و StringBuffer. هر یک از این کلاس‌ها ویژگی‌ها و کاربردهای خاص خود را دارند.Stringغیرقابل تغییر (Immutable): هنگامی که یک شیء از نوع String ایجاد می‌شود، مقدار آن نمی‌تواند تغییر کند. هر عملیاتی که به نظر می‌رسد یک رشته را تغییر می‌دهد، در واقع یک رشته جدید ایجاد می‌کند و مرجع آن را به متغیر اصلی اختصاص می‌دهد.String Pool: رشته‌های لیترالی (مانند &quot;Hello&quot;) در یک ناحیه خاص از حافظه به نام String Pool ذخیره می‌شوند. اگر رشته‌ای با همان مقدار قبلاً در String Pool وجود داشته باشد، مرجع همان شیء به متغیر جدید اختصاص می‌یابد. این ویژگی باعث صرفه‌جویی در حافظه و افزایش کارایی می‌شود.کاربرد: برای نمایش داده‌های متنی که نیازی به تغییر ندارند، مانند نام‌ها، آدرس‌ها و غیره.StringBuilderقابل تغییر (Mutable): برخلاف String، اشیاء از نوع StringBuilder را می‌توان پس از ایجاد تغییر داد. این ویژگی باعث می‌شود که StringBuilder برای عملیات الحاق و دستکاری رشته‌ها بسیار کارآمد باشد.بدون همگام‌سازی: StringBuilder برای استفاده در محیط‌های تک‌نخی بهینه شده است.کاربرد: برای ساخت رشته‌های طولانی یا زمانی که نیاز به تغییر مکرر یک رشته دارید، از StringBuilder استفاده می‌شود.StringBufferقابل تغییر (Mutable): مانند StringBuilder، اشیاء از نوع StringBuffer نیز قابل تغییر هستند.همگام‌سازی: StringBuffer برای استفاده در محیط‌های چندنخی طراحی شده است و عملیات آن همگام‌سازی می‌شوند تا از مشکلات همزمانی جلوگیری شود.کاربرد: زمانی که نیاز به تغییر رشته‌ها در یک محیط چندنخی دارید، از StringBuffer استفاده می‌شود.جدول مقایسهخلاصهString: برای داده‌های متنی ثابت و مقایسه رشته‌ها استفاده می‌شود.StringBuilder: برای ساخت و دستکاری رشته‌ها در محیط‌های تک‌نخی بهینه شده است.StringBuffer: برای ساخت و دستکاری رشته‌ها در محیط‌های چندنخی استفاده می‌شود.مثال خیلی ساده :String s1 = &amp;quotHello&amp;quot
String s2 = &amp;quotWorld&amp;quot
String s3 = s1 + &amp;quot &amp;quot + s2; // ایجاد یک رشته جدید

StringBuilder sb = new StringBuilder();
sb.append(&amp;quotHello&amp;quot);
sb.append(&amp;quot &amp;quot);
sb.append(&amp;quotWorld&amp;quot);

String s4 = sb.toString();در مثال بالا، s3 یک رشته جدید ایجاد می‌کند، در حالی که sb یک رشته را به صورت تدریجی می‌سازد.چه زمانی از کدام کلاس استفاده کنیم؟اگر نیاز به یک رشته ثابت دارید، از String استفاده کنید.اگر نیاز به ساخت یا تغییر رشته‌های طولانی دارید و در یک محیط تک‌نخی کار می‌کنید، از StringBuilder استفاده کنید.اگر نیاز به ساخت یا تغییر رشته‌های طولانی دارید و در یک محیط چندنخی کار می‌کنید، از StringBuffer استفاده کنید.نکته: در اکثر موارد، StringBuilder به دلیل کارایی بالاتر، ترجیح داده می‌شود. مگر اینکه به طور مشخص به همگام‌سازی نیاز داشته باشید.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 13:53:06 +0330</pubDate>
            </item>
                    <item>
                <title>Mutable VS Immutable in java</title>
                <link>https://virgool.io/Javenture/mutable-vs-immutable-in-java-zn67x1hp0ylr</link>
                <description>کدام یک از collection ها در جاوا mutable و کدام یک immutable است؟در این مقاله فرض میکنیم که شما اطلاعات حدودی از Java Collections دارید.این سلسله مقالات که برای تکمیل مقاله Java Collections - Everything You MUST Know نوشته شده برای بهبود و درک بهتر collectionها و مواردی که به طور روزمره دارید استفاده میکنید نوشته شده لطفا تمام این دسته بندی رو برای درک بهتر مطالعه کنید .Mutable VS Immutable in javaStringBuilder vs StringBuffer vs StringInteger vs intHashMap vs TreeMap vs SetHeap And StackMemory Heap vs Memory LeakInteger Constant PoolInteger Pool vs String PoolTernary OperatorAutoboxingقابلیت تغییر (Mutability) در مجموعه‌های جاوادر جاوا، مجموعه‌ها (Collections) به دو دسته اصلی قابل تغییر (Mutable) و غیرقابل تغییر (Immutable) تقسیم می‌شوند. این تقسیم‌بندی بر اساس امکان تغییر محتویات مجموعه پس از ایجاد آن صورت می‌گیرد.مجموعه‌های قابل تغییر (Mutable Collections)مجموعه‌های قابل تغییر به شما اجازه می‌دهند پس از ایجاد، عناصر را به آن‌ها اضافه، حذف یا تغییر دهید. این ویژگی در بسیاری از سناریوها بسیار مفید است، اما باید با احتیاط استفاده شود، زیرا تغییرات در یک مجموعه می‌تواند بر روی قسمت‌های دیگر برنامه نیز تأثیر بگذارد.به طور معمول، متدی برای ویرایش مقدار فیلد در خود دارد، و object می تواند گسترش پیدا کند.مثال‌هایی از مجموعه‌های قابل تغییر:List: ArrayList، LinkedListSet: HashSet، TreeSetMap: HashMap، TreeMapچرا از مجموعه‌های قابل تغییر استفاده می‌کنیم؟انعطاف‌پذیری: توانایی تغییر محتویات مجموعه در طول اجرای برنامهکارایی: در بسیاری از عملیات، مجموعه‌های قابل تغییر کارایی بالاتری دارندمثال :public class MutableExample {
    private String name;
    MutableClass(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    // this setter can modify the name 
    public void setName(String name) {
        this.name = name;
    }
    public static voidmain(String[] args) {
        MutableExample obj =newMutableExample(&amp;quottest&amp;quot);
        System.out.println(obj.getName());
        // update the name, this object is mutable      
        obj.setName(&amp;quotnewTest&amp;quot);
        System.out.println(obj.getName());
    }
}  // خروجی :  test  newTestمجموعه‌های غیرقابل تغییر (Immutable Collections)مجموعه‌های غیرقابل تغییر پس از ایجاد، نمی‌توانند تغییر کنند. هرگونه تغییر در این مجموعه‌ها منجر به ایجاد یک مجموعه جدید می‌شود. این ویژگی به بهبود امنیت و پایداری برنامه کمک می‌کند، زیرا از تغییرات ناخواسته در داده‌ها جلوگیری می‌کند.برای ایجاد یک object تغییر ناپدیر (immutable)، کلاس را به صورت final تعریف کرده، و هیچ متدی برای ویرایش فیلدها ایجاد نکنید.مثال‌هایی از مجموعه‌های غیرقابل تغییر:Stringغیرقابل تغییر (Immutable): هنگامی که یک شیء از نوع String ایجاد می‌شود، مقدار آن نمی‌تواند تغییر کند. هر عملیاتی که به نظر می‌رسد یک رشته را تغییر می‌دهد، در واقع یک رشته جدید ایجاد می‌کند و مرجع آن را به متغیر اصلی اختصاص می‌دهد.StringBuilderقابل تغییر (Mutable): برخلاف String، اشیاء از نوع StringBuilder را می‌توان پس از ایجاد تغییر داد. این ویژگی باعث می‌شود که StringBuilder برای عملیات الحاق و دستکاری رشته‌ها بسیار کارآمد باشد.StringBufferقابل تغییر (Mutable): مانند StringBuilder، اشیاء از نوع StringBuffer نیز قابل تغییر هستند.Collections.unmodifiableList: این متد یک نمای غیرقابل تغییر از یک List ایجاد می‌کند.Collections.unmodifiableSet: این متد یک نمای غیرقابل تغییر از یک Set ایجاد می‌کند.Collections.unmodifiableMap: این متد یک نمای غیرقابل تغییر از یک Map ایجاد می‌کند.مثال :// make this class final, no one can extend this class 
public final classImmutableExample {
    private String name;
    ImmutableExample (String name) {
        this.name = name;
    }
    public String getName(){
        return name;
    }

    //no setter 

    public static void main(String[] args) {
        ImmutableExample obj = new ImmutableExample(&amp;quottest&amp;quot);
        System.out.println(obj.getName());

        // there is no way to update the name after the object is created. 
        // obj.setName(&amp;quotnewTest&amp;quot);
        //System.out.println(obj.getName()); 
    }
} // خروجی  testچرا از مجموعه‌های غیرقابل تغییر استفاده می‌کنیم؟امنیت: جلوگیری از تغییرات ناخواسته در داده‌هاپایداری: اطمینان از اینکه داده‌ها در طول برنامه ثابت می‌مانندبه اشتراک‌گذاری: می‌توان به صورت ایمن مجموعه‌های غیرقابل تغییر را بین چندین بخش از برنامه به اشتراک گذاشتچه زمانی از کدام نوع استفاده کنیم؟مجموعه‌های قابل تغییر: زمانی که نیاز به تغییر دینامیکی محتویات یک مجموعه دارید.مجموعه‌های غیرقابل تغییر: زمانی که می‌خواهید داده‌ها را ایمن نگه دارید و از تغییرات ناخواسته جلوگیری کنید.نکته مهم:بسیاری از کلاس‌های مجموعه در جاوا متدهایی را ارائه می‌دهند که یک نمای غیرقابل تغییر از یک مجموعه قابل تغییر ایجاد می‌کنند. این کار به شما اجازه می‌دهد تا از مزایای هر دو نوع مجموعه استفاده کنید.در جاوا 8 و نسخه‌های بالاتر، کلاس‌های Stream نیز برای کار با مجموعه‌ها به صورت غیرقابل تغییر استفاده می‌شوند.جمع‌بندی:انتخاب بین مجموعه‌های قابل تغییر و غیرقابل تغییر به نیازهای خاص برنامه شما بستگی دارد. در حالت کلی، اگر به انعطاف‌پذیری نیاز دارید، از مجموعه‌های قابل تغییر استفاده کنید و اگر به امنیت و پایداری نیاز دارید، از مجموعه‌های غیرقابل تغییر استفاده کنید.منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Sat, 24 Aug 2024 13:13:12 +0330</pubDate>
            </item>
                    <item>
                <title>Spring Boot Redis Messaging</title>
                <link>https://virgool.io/Javenture/spring-boot-redis-messaging-gakmtgkecrlc</link>
                <description>مدیریت صف با استفاده از Redis در Spring Boot1- اول از همه بگیم کلا Message Broker چیه  و چیکار میکنه برامون ؟یک Message Broker  یک نرم افزار است که برنامه ها و اپلیکیشن ها رو قادر میسازه که بتونن اطلاعات خودشون رو در قالب یک پروتکل استاندارد بین یکدیگر جابه جا کنند و مستقیما با یکدیگر صحبت کنند.حتی اگر هر سرویس یا اپلیکیشن به زبان متفاوتی نوشته شده باشه. (Java - .net - php - ...)پیاده سازی ساختار مایکروسرویس بین برنامه نویس ها خیلی باب شده که یکی از جاهایی که میشه از Message Broker  ها استفاده کرد بین مایکروسرویس هامون هست.وقتی از Message Broker ها استفاده میکنیم درواقع داریم میزان قابل اعتماد بودن و پایداری رو تضین میکنیم و همچنین اینکه میتونیم پیام ها رو مدیریت و نظارت کنیم تا اطمینان حاصل بشه که پیام ها گم نمیشوند.در حال حاضر Message Broker های زیادی وجود دارد که میتونیم از هرکدوم از اونها استفاده کنیم.اما در اینجا بحث اصلی ما روی Redis یا Remote Dictionary Server که یک NoSQL  بر مبنای کلید/دیتا میباشد. که به عنوان کش ، پایگاه داده و Message Broker استفاده میشود.از صف Redis  در برنامه های با مقیاس پذیری و کارایی بالا استفاده میشود.ردیس قابلیت انتقال پیام به صورت Point To Point  و همچنین publish/subscribe   را دارد.نحوه کارکرد MessageBroker :تولید کننده (Producer): اپلیکیشن یا برنامه ای است که پیام را تولید کرده و در صف مربوطه قرار میدهد.مصرف کننده (Consumer) : مقصد پیام است ، در واقع اپلیکیشن یا برنامه است که پیام های مربوط به خود یعنی پیام هایی با پترن خاص را از صف مربوط به خود دریافت میکند.صف (Queue) : فایل سیستمی است که صف برای نگداری پیام ها از آن استفاده میکند.نکته : در Redis  نوع ارسال پیام بر اساس Topic  میباشد. حالا Topic  چیه : (publish/subscribe )این نوع از کانال ارتباطی برای پیاده سازی الگوهای  publish/subscribe مناسب است.همچنین اینکه برای مسیریابی های multicast پیام‌ها مناسب است. حالتی را تصور کنید که برای یک پیام چندین مصرف کننده وجود دارد که می‌توان انتخاب کرد که پیام را به کدام داد، برای این کار از این الگو استفاده می شود.همانطور که گفتیم مصرف کننده ها پیام هایی با پترن یا درواقع در اینجا Topic Name  خاص خود را دریافت میکنند.هر چند که میتونید از هر Message Broker  که دوست دارید استفاده کنید (RabbitMQ , Apache Kafka , Apache ActiveMQ , RedisMQ ,... ) اما Redis  هم جذابیت ها و استفاده های خودش رو داره مثلا من ازش توی پیاده سازی پنل اس ام اس استفاده کردم .3- یه مثال بزنیم خوب میخوایم یه پروژه نمونه بنویسیم که بتونید ازش توی کارتون استفاده کنید :نیازمندی هامون :&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-data-redis&lt;/artifactId&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;redis.clients&lt;/groupId&gt;
    &lt;artifactId&gt;jedis&lt;/artifactId&gt;
&lt;/dependency&gt;موارد لازم در application.propertis:server.port=2222
spring.data.redis.host=localhost
spring.data.redis.port=6379بخش کانفیگ Redis :اگر به این قسمت دقت کنید ما موقع ایجاد کردن یه Topic  اومدیم یه UUID رندم ایجاد کردیم شما میتونید این کار رو نکنید و یه پترن خاص قرار بدید و بعد در بخش مصرف کننده اون پترن خاص رو مقایسه کنید و اگر با پترن مصرف کننده برابر بود اون پیام رو دریافت کنید.@Configuration
public class RedisConfiguration {
    @Bean
    JedisConnectionFactory connectionFactory(){
        JedisConnectionFactory factory = new JedisConnectionFactory();
        return factory;
    }
    @Bean
    public RedisTemplate&lt;String, String&gt; redisTemplate() {
        RedisTemplate&lt;String, String&gt; template = new RedisTemplate&lt;&gt;();
        template.setConnectionFactory(connectionFactory());
        template.setValueSerializer(new GenericToStringSerializer&lt;String&gt;(String.class));
        return template;
    }
    @Bean
    ChannelTopic topic() {
        return new ChannelTopic(UUID.randomUUID().toString());
    }
    @Bean
    RedisMessageListenerContainer redisContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory());
        container.addMessageListener(new MessageListenerAdapter(new RedisReciever()), topic());
        container.setTaskExecutor(Executors.newFixedThreadPool(4));
        return container;
    }
}بخش Producer :@Service
public class RedisSender {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisSender.class);
    @Autowired
    private RedisTemplate&lt;String, String&gt; redisTemplate;
    @Autowired
    private ChannelTopic topic;
    public void sendDataToRedisQueue(String input) {
        redisTemplate.convertAndSend(topic.getTopic(), input);
        LOGGER.info(&amp;quotData - &amp;quot + input + &amp;quot sent through Redis Topic - &amp;quot + topic.getTopic());
    }
}بخش Costumer : @Service
public class RedisReciever implements MessageListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisReciever.class);
    @Override
    public void (Message message, byte[] pattern) {
        LOGGER.info(&amp;quotReceived data - &amp;quot + message.toString() + &amp;quot from Topic - &amp;quot + new String(pattern));
    }
}حالا یه کنترولر مینویسیم که یه متن پیام رو برای Producer   میفرسته و Producer اون رو میزاره توی صف تا مصرف کننده اون رو برداره :@RestController
@RequestMapping(&amp;quot/redis&amp;quot)
public class RedisController {
   @Autowired
   private RedisSender sender;
   @GetMapping
   public String sendDataToRedisQueue(@RequestParam(&amp;quotredis&amp;quot) String input) {
      sender.sendDataToRedisQueue(input);
      return &amp;quotsuccessfully sent&amp;quot
   }
}اینم تستش و نتیجه به صورت لاگ در کنسول :Data - HELLO WORLD sent through Redis Topic - df59e344-a70c-4e79-973f-8f6f2d109e84Received data - HELLO WORLD from Topic - df59e344-a70c-4e79-973f-8f6f2d109e84منتظر نگاه های زیباتون هستم .موفق و پیروز باشید.</description>
                <category>صادق خانزادی</category>
                <author>صادق خانزادی</author>
                <pubDate>Mon, 24 Jul 2023 01:50:39 +0330</pubDate>
            </item>
            </channel>
</rss>