<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های پارسا کاویان پور</title>
        <link>https://virgool.io/feed/@Parsakav</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-16 18:43:28</pubDate>
        <image>
            <url>https://static.virgool.io/images/default-avatar.jpg</url>
            <title>پارسا کاویان پور</title>
            <link>https://virgool.io/@Parsakav</link>
        </image>

                    <item>
                <title>Non-Blocking IO</title>
                <link>https://virgool.io/@Parsakav/non-blocking-io-o8hc41htvki2</link>
                <description>فرض کنید میخوایم یه سرور بنویسیم که بتونه کانکشن هارو هندل کنهچه راه هایی جلوی پای ماست؟Simple blocking server ( پردازش همه چیز با یک نخ)Threaded blocking server (پردازش هر درخواست توسط نخ جداگانه)Threaded pool blocking servers(استفاده از ExecuterService)Java NIO blocking(پردازش همه چیز با یک نخ البته کتابخانه ی جدید )Java NIO non-blocking pooling Java NIO non-blocking selectorدر ادامه انواع روش های بالا به همراه مزایا و معایب آنها را بررسی میکنیم.Simple Blocking Serverکد سرور:import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress(8080));
        while (true) {
            Socket client = serverSocket.accept();
            System.out.println(&amp;quotA new client accepted.&amp;quot);
            int data;
            while ((data = client.getInputStream().read()) != -1) {
                {
                    System.out.print((char) data);
                }
            }
            client.close();
        }
    }
}کد کلاینت:import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class Client {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket(&amp;quotlocalhost&amp;quot, 8080);
            Scanner scanner = new Scanner(System.in);
            PrintWriter pw = new PrintWriter(socket.getOutputStream());

            while (true) {
                String msg = scanner.nextLine();
                if (msg.equals(&amp;quotclose&amp;quot)) {
                    scanner.close();
                    pw.close();
                    socket.close();
                    break;
                }
                pw.println(msg);
                pw.flush();
            }
            socket.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}(برای تست سرور بجز کد کلاینت میتونید از دستور telnet localhost 8080 استفاده کنید)همانطور که ملاحظه میفرمایید, سرور تنها همزمان یک کلاینت رو پردازش میکنه. به محض اینکه کلاینت فعلی close شد , سرور توانایی پردازش کلاینت بعدی رو پیدا میکنه.ضمنن متد accept() بلاک هست (blocking) درواقع سرور هیچکاری نمیتونه بکونه بجز اینکه کل توانش رو بذاره روی انتظار برای کانکت شدن کلاینت جدید.اگر برنامه رو ران کنید میبینید که اگر چندین کلاینت وصل بشن تنها اولی میتونه داده بفرسته . زمانی که close رو نوشت تازه حالا میره سراغ کلاینت دومی و الی آخر !سرور وحشتناکیه نه؟ اگر مثلا تلگرام اینطوری بود تا زمانی که اولین نفری که کانکت شده کارش تموم نشه ما نمیتونیم پیام بدیم (:Threaded blocking serverimport java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class MultiServer extends Thread {
  private static final List&lt;PrintWriter&gt; clients = new ArrayList&lt;&gt;();
 public static void main(String[] args) {
       if (args.length != 1) {
         System.err.println(&amp;quotMISSING PORT NUMBER!!!!&amp;quot);
            System.err.println(&amp;quotUsage: java MultiServer &lt;Port Number&gt;&amp;quot);
            System.exit(1);
       }
      try {
            int portNumber = Integer.parseInt(args[0]);
          ServerSocket ss = new ServerSocket(portNumber);
          System.err.println(String.format(&amp;quotServer with port number %d ready to start&amp;quot, portNumber));
 new MultiServer().start();
  System.out.println(&amp;quotWaiting for the client to connect&amp;quot);
  while (true) {
 Socket sock = ss.accept();
  synchronized (clients) {
  clients.add(new PrintWriter(sock.getOutputStream(), true));
  }
 System.err.println(&amp;quotA new client accepted on the port &amp;quot.concat(String.valueOf(portNumber)));
  new IOThread(sock.getInputStream(), System.out).start();
 }
 } catch (Exception e) {
 System.out.println(e);
e.printStackTrace();
 }
  }
@Override
 public void run() {
 Scanner in = new Scanner(System.in);
 String line;
 while (in.hasNextLine()) {
 line = in.nextLine();
  if (line.isEmpty()) {
     continue;
 }
        doBroadCast(&amp;quotserver&amp;quot, line);
   }
    }
    public static void doBroadCast(String sender, String input) {
        for (PrintWriter pw : clients) {
            String response = String.format(&amp;quot%s: %s&amp;quot, sender, input);
            System.out.println(&amp;quotServer Terminal -&gt; &amp;quot.concat(response));
            pw.println(response);
        }
    }
}همانطور که ملاحظه میکنید این کلاس داره کارها ی زیر رو انجام میده:1- منتظر کانکشن جدید میمونه.هروقت کانکشن جدید برقرار شد دیگه با ترد خودش نمیاد منتظر داده بشینه! واگذارش میکنه به کلاسی به نام IOThread که کدش رو زیر قرار دادم.اینطوری میتونه فقط وظیفه ی منتظر کانکشن موندن رو برعهده بگیره. یعنی میتونه هر کانکشنی اومد رو اکسپت کنه و توی یک نخ دیگه بپردازه به داده هایی که میفرستند.2-یه سری قابلیت اضافه هم نوشتم مثلا  یک ترد جدا ایجاد میشه برای ورودی هایی که سرور میخواد بفرسته برای همه.شاید سوال پیش بیاد براتون چرا synchronized(clients)? بخاطر اینکه یه ترد نویسنده(تولید کننده) داریم و یه ترد خواننده (مصرف کننده)حالا فرض کنید کلاینت کانکت شده ولی قبل ازینکه به لیست clients اددش کنیم یکی مسیج فرستاده و doBroadCast فراخوانی شده(این متد توسط کلاس IOThread که در زیر میبینید فراخوانی شده).اینجا باید بگیم clients قفل باشه وقتی یکی خواست کانکت شه ,وقتی کانکت شد(accept شد و اضافه شد به لیست کلاینت ها),اونوقت فرستاده بشه که همه بتونن دریافتش کنن!درواقع میخوایم کلاینت اخری که تازه کانکت شده جا نمونه!import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
public class IOThread extends Thread {

   private BufferedReader input;
    private PrintWriter output;
    private String name;
    public IOThread(InputStream input, OutputStream output) {
        this.input = new BufferedReader(new InputStreamReader(input));
        this.output = new PrintWriter(output, true);
    }
    @Override
    public void run() {
       try {
            String line;
            while ((line = input.readLine()) != null) {
                if (line.contains(&amp;quotMY NAME IS:&amp;quot)) {
                   name = line.split(&amp;quot:&amp;quot)[1].trim();
                }else
                    MultiServer.doBroadCast(name, line);
            }
        } catch (Exception e) {
         e.printStackTrace();
        }
    }
}کلاس بالا تنها وظیفه اش گوش دادن به پیام ها و ارسالش برای همه  ی کلاینت هاستمثل یه چتروم!حالا وقتشه بریم سراغ کلاس کلاینت:import java.io.*;
import java.net.*;
import java.util.Date;
import java.util.UUID;
public class MyClient {
    public static void main(String[] args) {
        Date m = new Date();
        System.out.println(m.toString());
       if (args.length != 3 &amp;&amp; args.length != 2) {
            System.err.println(&amp;quotUsage: java MyClient &lt;host name&gt; &lt;port number&gt; &lt;Optional: Client name&gt;&amp;quot);
           System.exit(1);
        }
        try {
            Socket s = new Socket(&amp;quotlocalhost&amp;quot, 8888);
          new Thread(new Runnable() {
                final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                @Override
                public void run() {
                  String fromServer;
                    try {
                        while ((fromServer = in.readLine()) != null) {
                          System.out.println(fromServer);
                            if (fromServer.equals(&amp;quotShab Bekheir&amp;quot)) {
                                break;
                             }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                   }
                }
            }).start();
            new Thread(new Runnable() {
               PrintWriter out = new PrintWriter(s.getOutputStream(), true);
                BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
               String fromUser;
               @Override
                public void run() {
                String name = (args.length != 3) ? UUID.randomUUID().toString().substring(0, 5) : args[2];
                    out.println(&amp;quotMY NAME IS: &amp;quot + name);
                   try {
                        while ((fromUser = stdIn.readLine()) != null) {
                            out.println(fromUser);
                            if (fromUser.equals(&amp;quotShab Bekheir&amp;quot)) {
                                 break;
                            }
                        }
                    } catch (IOException e) {
                          e.printStackTrace();
                    }
               }
            }).start();
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}خب اینجا دقیقا چندتا ترد داریم؟واضح و مبرهن هست که کلا دوتا ترد نیازه یکی که داده بگیره و بفرسته به سرور و یکی که  داده از سرور بگیره و نشون بده به کلاینت!مشکلات پیاده سازی به روش بالا: فرض کنید 3000 تا کلاینت میان کانکت میشن !public class SimulateHeavyLoad {
    public static void main(String[] args) throws InterruptedException {
        final Socket[] sockets = new Socket[3000]; // Create 3000 connections
        for (int x = 0; x &lt; sockets.length; x++) {
            try {
                sockets[x] = new Socket(&amp;quotlocalhost&amp;quot, 8080);
            } catch (final IOException e) {
                System.err.println(e);
            }
        }
        // To enable the sockets to live. for awhile
        Thread.sleep(Long.MAX_VALUE);
    }
}یعنی حدودا 6000 تا ترد باید ایجاد بشه توی سرور و بسته هم نشن. یا خدا!احتمالا آتیش میگیره سرور.به هرحال احتمالا ارور های مختلفی میده. Crash میکنه. OutOfMemory میده و یا...اگر هم منابع هم به طرز ایده آلی زیاد باشه به هرحال تعداد ترد هایی که میتونیم ایجاد کنیم محدودیت داره!با این وجود برنامه ای مثل تلگرام که ممکنه میلیون ها کاربر بهش وصل شن از چه مکانیزمی استفاده میکنه؟ قطعا //از این روش نه!شاید یه روش به ذهنمون برسه* برای مدیریت روش بالا.روشی که به ذهنمون میرسه:بیایم تعداد ترد هارو مدیریت کنیم! مثلا بگیم فقط 50 تا ترد ساخته بشه و بیشتر دیگه ساخته نشه اینطوری به Crash / OutOfMemoryError و... بر نمیخوریم!پس بریم سراغ روش سوم.3-Threaded pool blocking serversimport java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress(8080));
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        while (true) {
            Socket client = serverSocket.accept();
            System.out.println(&amp;quotA new client accepted.&amp;quot);
            executorService.submit(() -&gt; {
                        int data;
                        try {
                            while ((data = client.getInputStream().read()) != -1) {
                                System.out.print((char) data);
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }finally {
                            try {
                                client.close();
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        }
            });
        }
    }
}کد کلاینت رو همون کد کلاینت اولین مثال در نظر بگیرید و یا از telnet استفاده کنید.برنامه ی اولی رو جوری تغییر دادیم که بتونه با چندتا کلاینت همزمان کار کنه ولی صرفا به تعدادی که ما مشخص کردیم, دوتا ترد که یعنی فقط دو نفر همزمان میتونن وصل شن.اینطوری دیگه ترد های اضافی زیادی ایجاد نمیشه و خب Cpu نمیترکه!اما مشکل اصلی:کاربر سوم باید  منتظر بمونه تا یکی از ترد ها ازاد شه . چطوری آزاد میشه؟ با close شدن کلاینت!4-NIO(New IO) Blocking Serverimport java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(8080));
        ByteBuffer buffer = ByteBuffer.allocate(80);
        while(true){
         SocketChannel client= serverSocketChannel.accept();
            for(int data;(data=client.read(buffer))!=-1;){
                buffer.flip();
                String s = StandardCharsets.UTF_8.decode(buffer).toString();
                System.out.print(s);
                buffer.clear();
            }
        }
    }
}این مثل همون اولی هست صرفا بوسیله ی Api جدید جاوا که NIO(منظور اینجا Non-blocking io نیست بلکه java.nio هست) نام داره نوشته شده!کد کلاینت هم همون کد اولی هست و مثل همیشه میتونید از دستور telnet هم استفاده کنید.حواستون باشه توی java.nio ما دیگه InputStream و OutputStream نداریم بلکه با ByteBuffer برای خواندن و نوشتن کار میکنیم.یه سری توضیحات ریز درمورد ByteBuffer:باید بهش سایز بدیم که توی کلاس ByteBuffer تحت متغیری به نام limit ذخیره میشه. الان ما Limit رو روی 80 ست کردیم.یعنی  هر ریکوئست با هر سایزی ما هشتاد  بایت هشتاد بایت میخونیمش.حالا اگر 80 تا خوندیم ولی فقط یه کاراکتر اومده بود چی؟ خب متغیری وجود داره در این کلاس به نام position که میگه چند بایت اشغال شده.کار متد flip اینه که Position رو مجددا روی 0 تنظیم کنه و limit رو روی Position اینطوری موقع خوندن اون بیت های خالی در نظر گرفته نمیشن!.برای اینکه چندتا کلاینت رو بتونه هندل کنه . باید non blocking باشه. پس بیاید ببینیم چطوری پیاده سازی میشهJava NIO non-blocking pooling import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class NIONonBlockingPollingServer {
    public static void main(String[] args) throws IOException {
        final ServerSocketChannel serverSocket = ServerSocketChannel.open(); // Creating the server on port 8080
        // Binding this server on the port
        serverSocket.bind(new InetSocketAddress(8080));
        serverSocket.configureBlocking(false); // Make Server nonBlocking
        final Map&lt;SocketChannel, ByteBuffer&gt; sockets = new ConcurrentHashMap&lt;&gt;();
        while (true) {
            // Accept means it will accept the incoming connection
            final SocketChannel socket = serverSocket.accept();
            // It may return null, as since its Non-Blocking, there may not be anything on this socket everytime.
            if (socket != null) {
                socket.configureBlocking(false); // Required, socket should also be NonBlocking

                // Every socket will have its own byte buffer
                sockets.put(socket, ByteBuffer.allocateDirect(80));
            }
            sockets.keySet().removeIf((socketChannel) -&gt; !socketChannel.isOpen());
            // Remove socketChannel which is not opened
            // Iterate through sockets to see f any socket has anything to say
            sockets.forEach((socketCh, byteBuffer) -&gt; {
                try {
                    int data = socketCh.read(byteBuffer);
                    if (data == -1) {
                        closeSocket(socketCh);
                    } else if (data != 0) { // 0 means socket has nothing to say
                        byteBuffer.flip();
                        String s = StandardCharsets.UTF_8.decode(byteBuffer).toString();
                        System.out.println(s);
                        byteBuffer.compact();
                    }
                } catch (IOException e) {
                    closeSocket(socketCh);
                    throw new UncheckedIOException(e);
                }
            });
        }
    }

    private static void closeSocket(final SocketChannel socket) {
        try {
            socket.close();
        } catch (IOException ignore) {
        }
    }
}نکته : متد read اگر مقداری کمتر از صفر برگرداند به معنای بسته شدن سوکت از طرف کلاینت است.توی io میتونید اینطوری بفهمید که بسته شده یا خیر:if(socket.getInputStream().read(bytearray) &lt; 0);برای تست از کلاس کلاینت که برای اولین مثال نوشتیم یا از telnet استفاده کنید.خب این کار میکنه ولی یه مشکل ریز داره!وقتی میگیم non blocking هست یعنی چی؟یعنی دیگه روی متد accept نباید گیر کنه!توی blocking سرور منتظر میموند که یه کلاینت بیاد وصل شه درسته؟و درواقع ترد همونجا نگه داشته میشدولی non blocking  ترد رو نگه نمیداره. پس ممکنه accept چیزی که برمیگردونه null باشه!(بدیهی هست که اگر کلاینتی کانکت شه null نمیده و فقط وقتی میده که تو اون لحظه کلاینتی کانکت نشده و خیلی اتفاق میوفته این حالت). پس باید چک کنیم نال نباشه.در ضمن هر لحظه باید تمام کلاینت هارو پیمایش کنیم و ببینیم ایا کسی چیزی فرستاده؟که با forEach این کارو انجام دادیم.برای کانکشن های زیاد کار میکنه با یک Thread ولی خب حالت جالبی نیست.در نهایت باید به این سوال پاسخ بدیم. Blocking IOبهتر است یا Non-blocking IO? Blocking IO  Vs Non blocking IOبا توجه به این لینک , اگر تعداد کانکشن ها بسیار زیاد است(هزاران) و هرکدام از کانکشن ها داده های نه چندان زیادی ارسال میکنند(مثلا سرور چت) استفاده از Non blocking به صرفه تر است زیرا Single thread است. اما اگر کانکشن ها انچنان زیاد نیست و پهنای باند بالاست بهتر است از IO استفاده شود.NIO non-blocking selectorبهترین حالت موجود. در این حالت دیگه متد accept خروجی null به ما نمیده.پیاده سازی این حالت رو در نوشته ای دیگر بررسی میکنیم.</description>
                <category>پارسا کاویان پور</category>
                <author>پارسا کاویان پور</author>
                <pubDate>Sat, 24 Dec 2022 18:57:49 +0330</pubDate>
            </item>
                    <item>
                <title>Static Factory Method</title>
                <link>https://virgool.io/@Parsakav/static-factory-method-wmushpcl4o3w</link>
                <description>تا اینجای کار یکی از روش هایی که باهاش کلاسمون رو مقداردهی اولیه میکردیم  و یا حتی Dependency Injection  رو باهاش پیاده سازی میکردیم(اگر این رو نمیدونید مشکلی نیست ولی اگر مقداردهی اولیه کردن رو هم هنوز نمیدونید این نوشته به کارتون نمیاد) Constructor (سازنده) بود. اما حالا میخوایم یه روش دیگه که مزایا و معایب خودشو داره. اولین سوالی که پیش میاد اینه که مگه چه مشکلی هست اگر از سازنده استفاده کنیم؟ خب راستش هیچی ولی یکسری معایب ریز داره:1- سازنده ها یک نام با معنی ندارند. با استفاده از Static factory method میتونید یک نام با معنی استفاده کنید.2-سازنده ها نمیتونن چیزی Return کنن.ولی Static factory method میتونه Return داشته باشه. پس در این مورد هم انعطاف پذیری بیشتری داریم3- میتونیم باهاش ساخته شدن شی ء رو محدود کنیم درحالی که در سازنده حتما شی جدید ساخته میشه. این بهمون قدرت استفاده از مکانیزم های Caching رو میده(مثل متد Integer.valueOf که درواقع از بازه ی -128 تا +127 رو کش شده داره و اگر در این بازه بهش عدد بدید یک شیء جدید از Integer نمیسازه). یکی از عینی ترین نمود هاش الگوری Singleton هست که درواقع داخلش ما از Static factory method  استفاده میکنیم(همون متد getInstance که همه داخل سینگلتون دیدیمش).4-بعضی حرکت هارو نمیشه داخل سازنده زد مثلا مقدار دهی متغیر های نمونه استاتیک. در چنین حالتی باید از static block استفاده کنیم که به محض Load شدن کلاس در حافظه اجرا میشه. ولی با Static factory method میتونیم به صورت Lazy initialization این فیلد هارو مقدار دهی کنیم.دقیقا کجاها استفاده شده؟ چند مثال :1-متد valueOf در کلاس String و Integer و...2-متد های Of,ofNullable,empty کلاس Optional .3-تمام متد های کلاس Collections. که هیچ جوره نمیشه ازش شیء ساخت.حالا تعریفش چطوریه؟؟اول فرض کنید که یک کلاس User داریم و میخوایم هرموقع شیء جدیدی ایجاد شد زمانش رو لاگ کنیم.ایا درسته که در سازنده کد لاگ کردن رو بنویسیم؟ در این صورت اصل Single Responsibility Principle(SRP) رو نقض کردیم. این اصل به صورت ساده و مختصر بیان میکنه که هر متد  یا هر کلاس قراره فقط یک وظیفه ی خاص رو انجام بده و این یعنی وقتی سازنده قراره مقدار دهی اولیه کنه نباید لاگ بندازه!!!پس برای رعایت این اصل میایم از Static factory method استفاده میکنیم:public class User {
    private static final LoggerLOGGER =Logger.getLogger(User .class.

    private final String name;
    private final String email;
    private final String country;

    public User(String name, String email, String country) {
        this.name = name;
        this.email = email;
        this.country = country;
    }
    // getters
    public static User createWithLoggedInstantiationTime(String name, String email, String country) {
        LOGGER.log(Level.INFO, &amp;quotCreating User instance at : {0}&amp;quot, LocalTime.now());
        return new User(name, email, country);
    }
}البته بر حسب نیاز میتونید سازنده رو private یا public تعریف کنید.امیدوارم به دردتون خورده باشه... موفق باشید!منبع : Effective java</description>
                <category>پارسا کاویان پور</category>
                <author>پارسا کاویان پور</author>
                <pubDate>Tue, 22 Nov 2022 01:18:21 +0330</pubDate>
            </item>
                    <item>
                <title>بلاک ها در جاوا</title>
                <link>https://virgool.io/@Parsakav/%D8%A8%D9%84%D8%A7%DA%A9-%D9%87%D8%A7-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7-nzl0vrsnd8g8</link>
                <description>امروز میخوایم انواع بلاک هارو در جاوا توضیح بدیم و بگیم دقیقا به چه کار میان خب اول از همه باید بریم سراغ مقدار دهی اولیه ی مقادیر در جاوا.میدونیم که اگر یک کلاس مثل این داشته باشیم:public class Sample{
 private int i;private boolean b;private String s;}جاوا میاد خودکار برای ما این متغیر هارو مقدار دهی اولیه میکنه:تمام مقادیر عددی با صفر , مقادیر بولی با false و ابجکت ها (مثل String و سایر کلاس ها) با null .اما اگر بخوایم خودمون مقدار دهی کنیم چی؟ میخوایم مقادیر پیشفرض رو تغییر بدیم. باید از سازنده ها استفاده کنیم :public class Sample{int i;String s;boolean b;public Sample(){i=1;s=&amp;quotempty&amp;quotb=true;  }}الان دیگه تغییر کرد . حالا یکسری بلاک های دیگه هم داریم برای مقدار دهی اولیه :static blocknon-static blockconstructorخب اخری رو  فکر کنم همه باهاش اشنایید . اما فرض کنید ما سازنده رو overload کردیم(یعنی  چند سازنده داریم با امضا های متفاوت).همچنین فرض کنید کلاسی داریم برای نگهداری اطلاعات دانشجو.  دانشجو یه کد دانشجویی داره و یه شماره ملی. اگر شماره ملی  به کلاس ما داده شد دیگه نیازی نیست کد دانشجویی رو هم بگیریم چون با همون شماره ملی میتونیم کد دانشجوییش هم پیدا کنیم از طریق پایگاه دادمون(فرض کنید دیگه) و برعکس. همچنین سن دانشجو رو پیشفرض ۱۸ در نظر گرفتیم:public class Student{private int studentCode;private int nationalId;private int age;public Register(int studentCode){this.studentCode=studentCode;age=18;}public Register(int nationalId){this.nationalId=nationalId;age=18;}}تا اینجا کد درسته..مشکلی هم نداره . اما صبر کنید. انگار مقدار دهی اولیه ی متغیر  age  دوجا صورت گرفته  و خب این برای تمیزی کد مناسب نیست.فرض کنید فقط سن نبود و متغیر های زیاد تر دیگه ای هم بود.روش جایگزین و تمیز تر چیه؟ استفاده از non-static block ها:public class Student{private int studentCode;private int nationalId;private int age;{age=18;}public Register(int studentCode){this.studentCode=studentCode;}public Register(int nationalId){this.nationalId=nationalId;}}نکته: non-static block همیشه قبل از سازنده اجرا میشه و کاربردش جلوگیری از کد های تکراری در سازنده های overload شده ست .نکته: میتونیم هرچند تا که دلمون خواست non-static block داشته باشیم!خب بریم سراغ static block . این یکی یکم قضیه اش فرق داره ولی فلسفه ی همینم مثل سازنده و مثل non static block برای مقدار اولیه دادنه . ولی به متغیر های static:فرض کنید یک کلاس داریم که داره یک کانکشن به پایگاه داده باز میکنه. مسلما بهینه نیست هر بار که شی از اون کلاس ساخته شد ما بیایم یه کانکشن جدید باز کنیم! کار پر هزینه ایه. باید چیکار کنیم؟ با استفاده از static block یک کد رو فقط یکبار اونم موقع لود شدن کلاس در حافظه اجرا میکنیم(از همین جمله باید بفهمیم استاتیک بلاک قبل از کانستراکتر و non static block اجرا میشه چون قبل ازینکه بتونیم شی بسازیم از یک کلاس باید اول اون کلاس در حافظه لود بشه)!public class DatabaseConnector{public static Connection conn;static{// init conn}} اگر یه کلاس داشته باشیم (مثل همین بالا ) و بخوایم بدون شی ساختن ازش فقط اونو در حافظه لود کنیم (که مثلا بلوک استاتیکش اجرا شه) به شکل زیر عمل میکنیم:Class.forName(&quot;DatabaseConnector&quot;);و اما کاربردش چیه؟ بعضی کلاس ها یک سری کانفیگ ها دارن و قبل ازینکه شی ازشون ساخته شه باید اون کانفیگ ها انجام بشه مثل Jdbc Driver ها. راستی..دوباره میتونیم هرچند تا که دلمون خواست static block در کلاسمون داشته باشیم(در این صورت به ترتیب از اولی تا اخری اجرا میشن).نکته : متغیر های غیر استاتیک رو نمیتونیم در بلاک استاتیک مقدار دهی کنیم!! دلیلش هم واضحه. متغیر های غیر استاتیک وابسته به اشیای کلاس هستند و هربار که شی ایجاد شد یک کپی از اونا میره داخل حافظه. درواقع فقط یکبار قرار نیست ساخته و مقدار دهی بشن! اما متغیر استاتیک فقط موقع لود شدن کلاس در حافظه ساخته میشن و تا اخر برنامه پا برجا میمونن.نکته: متغیر های static final باید حتما در بلوک استاتیک مقدار دهی بشن(در سازنده و بلوک های غیر استاتیک امکانش وجود نداره).نکته : در مکانیزم ارث بری جاوا , اولویت اجرا به ترتیب با static block پدر, non static block پدر و constructor پدره. سپس نوبت به همین ترتیب برای کلاس فرزند میرسه.</description>
                <category>پارسا کاویان پور</category>
                <author>پارسا کاویان پور</author>
                <pubDate>Sat, 16 Apr 2022 03:27:18 +0430</pubDate>
            </item>
                    <item>
                <title>معرفی  (JSR 376)JPMS</title>
                <link>https://virgool.io/@Parsakav/%D9%85%D8%B9%D8%B1%D9%81%DB%8C-jsr-376jpms-nmm8ym5lneya</link>
                <description>تو این مقاله میخوایم ببینیم JPMS یا همون  Java Platform Module System که در جاوا 9 معرفی شد دقیقا چیه.طبق گفته ی oracle یکی از مهمترین فناوری مهندسی نرم افزار در جاواست که نتیجه ای از پروژه ی Jigsaw بوده و کمک میکنه بهره وری پروژه بیشتر بشه.پروژه ی ماژولار کردن Java از نسخه ی 7 کلید خورد و نهایتا در نسخه ی 9 اضافه شد.هدف JPMS رفع دو مشکل بزرگ در جاوا بود classpath ها وmonolithic jdk :در حالت عادی هنگامی که کتابخونه (Jar file) هایی که در خود Jdk موجود نیستند استفاده میکنیم باید با -classpath هنگام ران کردن برنامه ادرسیش رو بدیم. حالا اگر اشتباهی دو تا لایبری با ورژن های متفاوت ادد کرده باشیم چی؟مشکلی به وجود میاد به اسم  Jar Hellخب  حالا مشکل این Jar hell چیه؟وقتی یه متدی مثلا از کتابخونه ی x رو فراخوانی کردیم که در ورژن 1 هست ولی در ورژن 2 حذف شده و هر دو توی classpath ادد شدن یکیشون رندوم استفاده میشن! درواقع هنگام کامپایل هیچ خبری نیست ولی موقع ران شدن توی یکسری شرایط به ارور بر میخورید.وmonolithic  jdk چیه؟ کلاس های جاوا به شدت به هم وابستگی داشتن و وقتی یک برنامه ی ساده که مثلا میخواستیم چیزی رو فقط پرینت کنیم (مثلا hello world) باید کل JRE رو روی سیستممون نصب میکردیم مثلا چیزی حدود 50مگابایت فقط برای hello world و حالا اگر برنامه ی سخت افزاری میخواستیم بنویسیم با محدودیت حافظه هم مواجه میشدیم و...نتیجه ی ماژولار کردن Java بهبود عملکرد خود Jvm هم هست .JSR 376 (Java Specification Requests)نشون داده که عملکرد بهینه سازی Jvm وقتی که ماژول ها تفکیک شدن و فقط اونایی که لازم هستن اضافه شدن بهبود پیدا کردهیکی دیگه از مواردی که با JPMS به ارمغان اومده و درواقع از مهمترین اهداف JPMS بود  کپسوله سازی قدرتمند تر هست (Strong encapsulation):پکیج های یک ماژول فقط در صورتی در اختیار دیگر ماژول ها قرار میگیرن که در ماژول به صراحت اعلام بشه میخواد فلان پکیج رو در اختیار دیگر ماژول ها قرار بده ! تازه اوناهم فقط وقتی میتونن ازش استفاده کنن که به صراحت اعلام کنن بهش نیاز دارن.این حرکت کپسوله سازی رو قوی تر میکنه برای مثال کلاس هایی در خود جاوا هست (internal Api ) که فقط برای APIداخلی JDK طراحی شدن ولی توسط کلاس های خارجی مورداستفاده قرار میگرفتن این قضیه میتونه باعث کاهش امنیت بشه ولی با JPMS این مشکل هم مرتفع شده.مشاهده ی لیست ماژول های جاوا در سیستم های مختلف :java --list-modulesو اگه بخوایم اطلاعات یک ماژول رو به دست بیاریم :java --describe-module java.sqlنحوه ی تعریف module :ابتدا باید یک فایل به نام module-info.java ایجاد کنید و اون رو در root folder قرار بدید (مثلا پکیج اصلی برنامه هست com.example.myprogram باید خارج از این پکیج و دقیقا کنار پوشه ی com باشه .. درونش نباشه ها فقط توی مسیری باشه که پوشه ی com هست):module modulename {  }فایل باید به صورت بالا شروع باشه با نام ماژول.کلمات کلیدی رزرو شده در تعریف ماژول هم اینها هستند:exports, module, open, opens, provides, requires, uses, with, to transitive.بریم سراغ توضیح کلمات کلیدی بالا :(کد هارو رو درون اکولادی که بالا تعریف کردیم مینویسیم) requires modulename;همینطور که از اسمش مشخصه داره میگه اقای jvm این ماژول من وابستگی داره به فلان ماژول و تو اددش کن به classpath من.البته برای ماژول هایی که فقط موقع کامپایل نیازشون داریم از حرکت زیر استفاده میکنیم:requires static modulename;اما خب دقیقا منظورمون از ماژول هایی که فقط زمان کامپایل نیازشون داریم چیه؟ خیلی از کتابخونه ها فقط زمان کامپایل به کار میان و اصلا قرار نیست زمان رانتایم استفاده بشن (مثل  Lombok که درواقع بر اساس annotation هایی که زدیم میاد سورس کد رو تولید میکنه نکته ی مهم اینکه تمام انوتیشن هایی که فقط زمان کامپایل باید در دسترس باشن RetentionPolicy  شون CLASS یا SOURCE هست  ) این ماژول ها برای زمان رانتایم اختیاری هستن.یه چیز دیگه داریم به اسم :requires transitive modulename;اینم میاد میگه ای کسایی که دارید از ماژول من استفاده میکنید و ای منی که خودم دارم از یه ماژول دیگه استفاده میکنم که کار شمارو انجام بدم.. پس شما بصورت ضمنی داری از اون ماژول منم استفاده میکنی.فرض کنید یک ماژول Bar دارید که اون داره از ماژول Drink استفاده میکنه و یه همچین کدی هم در نظر بگیرید :// in module _bar_
public class Bar {

    // `Drink` comes from the module _drink_,
    // which _bar_ requires
    public Drink buyDrink() { /* ... */ }

}حالا اگر ماژولی به نام customer که داره از Bar استفاده میکنه بیاد متد buyDrink رو کال کنه خطای کامپایل رخ میده  با این منطق که ماژول customer به ماژول Drink دسترسی نداره و باید با استفاده از requiers Drink; توی فایل Module-info خودش مشخص کنه . اما راه حل منطقی تر اینه :مایی که کتابخونه نوشتیم باید تمام این داستانارو گردن بگیریم و بگیم هرکس از ما استفاده کرد درواقع از فلان ماژول هم استفاده کرده. پس توی فایل module-info ای که در ماژول Bar هست مینویسیم: requires transitive drink; حالا دیگه ماژول customer میتونه راحت buyDrink رو کال کنه.کلمه کلیدی exports مشخص میکنه ماژول ما میتونه برای دیگر ماژول ها قابل دسترسی باشه:exports modulename;حالا اگر بخوایم مشخص کنیم ماژول ما فقط برای بعضی ماژولای دیگه قابل مشاهده باشه چی ؟(بهش میگن qualified export) خیلی راحت میایم از exports...to استفاده میکنیم :exports mymodulename to othermodulename;exports mymodulename to othermodulename2;exports mymodulename to othermodulename3;و الی اخر..میدونیم که توسط رفلکشن (reflection) اعضای private کلاس و... قابل دسترسیه ولی توی jpms این خبرا نیست باید اجازه بدیم که ماژول دیگری ایا میتونه توسط رفلکشن از ماژول ما استفاده کنه یا نه:opens mymodulename;و اگر بخوایم فقط برای یک ماژول خاص باشه مثل exports...to از opens...to استفاده میکنیم.مثال opens رو میتونیم توی یک پروژه ی جاوا اف ایکسی که داخل fxml اومدیم برای یک ویو fx:id تنظیم کردیم و توی کنترل با انوتیشن @FXML اون رو گرفتیم. این حرکت با reflection انجام میشه و باید حتما ماژولمون برای javafx.fxml  چی باشه؟افرین ! opens باشه:opens mymodule to javafx.fxml;اگر کمی دقت کنید دیگه ما برای کپسوله سازی فقط با private, protected ,public, package طرف نیستیم بلکه با پابلیکی که فقط برای ماژول ما پابلیکه. پابلیکی که برای همه ی ماژول ها پابلیکه و پابلیکی که برای بعضی ماژول ها پابلیک هم طرف هستیم که این دقیقا میشه همون Strong encapsulationدو مورد دیگه میمونه به نام uses و provides..with که مربوط میشه به ServiceLoader که خواندنش رو به خودتون واگذار میکنم .در مطلب بعدی اینکه چطور با ماژولاریتی کردن پروژه میتونیم یک JDKسفارشی بسازیم که حجمش فقط بر اساس ماژول های مورد نیاز ما باشه صحبت میکنیم.منابع :Openjfx jigsawUnderstanding Java 9 ModulesJavaland</description>
                <category>پارسا کاویان پور</category>
                <author>پارسا کاویان پور</author>
                <pubDate>Thu, 07 Apr 2022 03:47:01 +0430</pubDate>
            </item>
                    <item>
                <title>ویژگی های معرفی شده در JAVA 17</title>
                <link>https://virgool.io/@Parsakav/%D9%88%DB%8C%DA%98%DA%AF%DB%8C-%D9%87%D8%A7%DB%8C-%D9%85%D8%B9%D8%B1%D9%81%DB%8C-%D8%B4%D8%AF%D9%87-%D8%AF%D8%B1-java-17-q1tptsznwoze</link>
                <description>استفاده ی همیشگی از  کلید واژه ی  strictfpدر جاوا برای اطمینان از یکسان بودن نتایج محاسبات بر مقادیر اعشاری در پلتفرم های مختلف از کلید واژه ی strictfp استفاده میشد (درواقع ممکن است مثلا دقت اعداد اعشاری در پلتفرم های مختلف یکسان نباشد)در نسخه ی 17 جاوا نیاز به استفاده از این کلیدواژه نبوده زیرا بصورت پیشفرض  اعمال میشودعلامت گذاری Applet برای حذف نهایی:همونطور که میدونید Applet ها خیلی وقته از دور خارج شدن و در Java 9 به صورت کامل منسوخ شدند ولی هنوز از Jdk حذف نشدند.در حال حاضر Applet علامت گذاری شده برای حذف شدن در نسخه های بعدی.در جاوا 9 :@Deprecated(since=9)public class Applet extends Panel{}در جاوا 17 :@Deprecated(since=9)@SuppressWarnings(&amp;quotremoval&amp;quot)public class Applet extends Panel{}Pattern matching  for switch:جاوا خیلی وقته داره قول  چنین حرکتی رو میده. اما بیاید ببینیم دقیقا چیه:یک متد رو در نظر بگیرید که داره یک شی از ورودی میگیره و توی یک قالب رشته ای نشونش میده.اول باید چک کنیم اون ابجکت(شی) از چه جنسیه و بصورت معمول همچین حرکتی میزنیم(استفاده از عملگر instance of):public static String formatter(Object o) {       String formatted = &amp;quotunknown&amp;quot       if (o instanceof Integer i) {  formatted = String.format(&amp;quotint %d&amp;quot, i);    } else if (o instanceof Long l) {           formatted = String.format(&amp;quotlong %d&amp;quot, l);  } else if (o instanceof Double d) {           formatted = String.format(&amp;quotdouble %f&amp;quot, d);       } else if (o instanceof String s) {           formatted = String.format(&amp;quotString %s&amp;quot, s);     }       return formatted;   }میبینیم که کد یکم طولانی و خرچنگ قورباغه ای شده: public  static String formatterJava17(Object o) {     return switch (o) { case Integer i -&gt; String.format(&amp;quotint %d&amp;quot, i);      case Long l    -&gt; String.format(&amp;quotlong %d&amp;quot, l);     case Double d  -&gt; String.format(&amp;quotdouble %f&amp;quot, d);     case String s  -&gt; String.format(&amp;quotString %s&amp;quot, s);       default        -&gt; o.toString();         };     }اینم از معجزه ی جاوا 17 ! خیلی تر و تمیز تر.حالا بریم سراغ حرکت بعدی که به سوییچ اضافه شده. اگه یادتون باشه برای اینکه بخوایمnull بودن رو چک کنیم توی سوییچ امکانش نیست و باید از if استفاده کنیم:  public static void main(String[] args) {      testString(&amp;quotJava 16&amp;quot);  // Ok      testString(&amp;quotJava 11&amp;quot);  // LTS      testString(&amp;quot&amp;quot);         // Ok      testString(null);       // Unknown!  }  static void testString(String s) {      if (s == null) {          System.out.println(&amp;quotUnknown!&amp;quot);          return;      }      switch (s) {          case &amp;quotJava 11&amp;quot, &amp;quotJava 17&amp;quot   -&gt; System.out.println(&amp;quotLTS&amp;quot);          default                     -&gt; System.out.println(&amp;quotOk&amp;quot);      }  }خب حالا دیگه میتونیم null بودن رو هم به این صورت در سوییچ چک کنیم:    public static void main(String[] args) {        testStringJava17(&amp;quotJava 16&amp;quot);  // Ok        testStringJava17(&amp;quotJava 11&amp;quot);  // LTS        testStringJava17(&amp;quot&amp;quot);         // Ok        testStringJava17(null);       // Unknown!    }    static void testStringJava17(String s) {        switch (s) {            case null                   -&gt; System.out.println(&amp;quotUnknown!&amp;quot);            case &amp;quotJava 11&amp;quot, &amp;quotJava 17&amp;quot   -&gt; System.out.println(&amp;quotLTS&amp;quot);            default                     -&gt; System.out.println(&amp;quotOk&amp;quot);        }    }ویژگی جالب دیگه ای که به سوییچ اضافه شده شرط گذاشتن توی کیس هاستدر حالت معمول بازم باید از if condition استفاده میکردیم:class Shape {}  class Rectangle extends Shape {}  class Triangle  extends Shape {      int calculateArea(){          //...      } }  static void testTriangle(Shape s) {      switch (s) {          case null:              break;          case Triangle t:              if (t.calculateArea() &gt; 100) {                  System.out.println(&amp;quotLarge triangle&amp;quot);                  break;              }else{                  System.out.println(&amp;quotTriangle&amp;quot);              }          default:              System.out.println(&amp;quotUnknown!&amp;quot);      }  }درواقع توی یک کیس یه if و یه else گذاشتیم برای حالت های مختلف برنامه ولی از الان دیگه نمیخواد اینکار رو هم انجام بدیم :  static void testTriangle2(Shape s) {      switch (s) {          case null -&gt;                  {}          case Triangle t &amp;&amp; (t.calculateArea() &gt; 100) -&gt;                  System.out.println(&amp;quotLarge triangle&amp;quot);          case Triangle t -&gt;                  System.out.println(&amp;quotTriangle&amp;quot);          default -&gt;                  System.out.println(&amp;quotUnknown!&amp;quot);      }  }خب معجزه ی سوییچ همینجا تموم میشه . امیدوارم خسته نشده باشید که میخوایم سراغ یه چیز خفن بریم که شی گرایی جاوا رو تکمیل تر میکنه:کلاس های مهر و موم شده (sealed class):در جاوا هنگام ارث بری نمیتونستیم مشخص کنیم که Parent ها کی باشن .. ولی الان دیگه میتونیم مشخص کنیم که دقیقا Child ها کیا  میتونن باشن . شاید بپرسید خب این به چه دردی میخوره؟ سعی شی گرایی نزدیک کردن مفاهیم کد نویسی به دنیای واقعیه. فرض کنید یک کلاس وسیله ی نقلیه دارید . خب چه کلاسایی میتونن فرزند این باشن؟ واضحه که دو نوع وسیله ی نقلیه بیشتر نداریم.. موتوری و غیر موتوری .در واقع جاوا اصل رو بر توسعه ی مجدد گذاشته بود و با این فرض که ممکنه یه روزی یه وسیله ی نقلیه بیاد که نه موتوری باشه نه غیر موتوری(ولی با مفاهیم دنیای واقعی جور نیست).الان دیگه مشخصا اعلام میکنیم فقط دو تا کلاس موتوری و غیر موتوری میتونن از کلاس وسیله ی نقلیه ارث بری کنن.مثال دیگه خونه هست (فقط ویلایی و غیر ویلایی داریم)یه مثال ریز :public sealed interface Command    permits LoginCommand, LogoutCommand, PluginCommand{    //...}با permits کلاس های child رو مشخص میکنیم.یکسری ویژگی های تخصصی تر هم اضافه شده که خوندنش رو به خودتون واگذار میکنم.. موفق باشید منبع:ویژگی های جدید جاوا</description>
                <category>پارسا کاویان پور</category>
                <author>پارسا کاویان پور</author>
                <pubDate>Mon, 04 Apr 2022 12:27:05 +0430</pubDate>
            </item>
                    <item>
                <title>کلاس های انتزاعی (abstract class)</title>
                <link>https://virgool.io/@Parsakav/%DA%A9%D9%84%D8%A7%D8%B3-%D9%87%D8%A7%DB%8C-%D8%A7%D9%86%D8%AA%D8%B2%D8%A7%D8%B9%DB%8C-abstract-class-ptdwxozz2qzv</link>
                <description>اشاره ای به مفهوم انتزاع(Abstraction):انتزاع به معنای مفهوم کلی است … فرض کنید به مجلسی وارد شده اید,کسی را نمیشناسید و اطلاعی از وجوه مشترک میان افراد ندارید,در این حالت میگوییم تمام افراد ان مجلسه انسان هستند ,انسانیت مفهوم کلی است که بر همه ی انها صدق میکند در حالی که برای مثال سن و قد شخص خاصی در ان مجلس را نمیتوان به عنوان وجه مشترک میان افراد ان مجلس به حساب اورد ;چرا که شخص دیگر ,قد و وزن این شخص را ندارد .اشکال هندسی را تصور کنید ;مثلث و مربع و دایره… هرکدام تفاوت هایی با یکدیگر دارند,به عنوان مثال مجموع اندازه ی زاویه های مربع با مثلث یکسان نیست بنابراین به مجرد آنکه سعی میکنیم وجه مشترک میان انهارا در یابیم با کمی فکر به این نکته میرسیم که هر سه شکل هستند(این گفته بسیار کلی گویی هست و منظور از انتزاع هم همین میباشد). در این حالت میگوییم شکل و انسان مفاهیمی انتزاعی هستند .مفاهیم بالا در برنامه نویسی هم بسیار مورد استفاده قرار میگیرند,توابع انتزاعی زمانی مورد استفاده قرار میگیرند که ما از نحوه ی تعریف ان اطلاع  نداریم اما میدانیم یک ویژگی مشترک بین شی های ما میباشد,برای مثال ویژگی مشترک بین حیوانات در اوردن صدا میباشد ,متدی که برای به صدا در اوردن حیوان مورد استفاده قرار میگیرد ,برای حیوانات مختلف صدا یکسان نیست و هر حیوان به شیوه ی خود متد مورد نظر را پیاده سازی میکند ,یا برای مثال تمام اشکال هندسی دارای زاویه هستند اما تعداد و اندازه ی آنها یکسان نیستهنگامی که در مورد ساخت یک کلاس در جاوا فکر میکنیم ,اولین چیزی که به ذهن ما خطور میکند این است که ان کلاس با هدف ساخت شی و استفاده در کلاس های دیگر ایجاد میشود. با این همه , گاهی اوقات فقط کلاس ها تعریف میشوند و برنامه نویسان هرگز قصد ندارند هیچ شی را نمونه سازی کنند. چنین کلاس هایی که کلاس  انتزاعی نامیده میشوند تنها برای رساندن مفهوم کلیت و وجه های مشترک بین اشیا هستند .  این کلاس ها معمولا به عنوان سوپرکلاس ها (کلاس های پدر)  در سلسه مراتب توارث بکار گرفته میشوند, از این رو معمولا با عنوان سوپر کلاس های انتزاعی شناخته می شوند.هدف از کلاس های انتزاعیهدف از یک کلاس انتزاعی ایجاد یک سوپر کلاس مناسب  است که قرار است بین کلاس ها طرح مشترکی را به اشتراک بگذارد. کلاس هایی که میتوانند در نمونه سازی شی ها بکار گرفته شوند , کلاس های مقید (غیر انتزاعی) نام دارند.با اینکه کلاس های غیر انتزاعی نیز قابلیت سوپر کلاس بودن را دارند اما کلاس های فرزند اجباری به پیاده سازی متد های ان ها ندارند و درواقع  کلاس های انتزاعی کلاس های فرزند را اجبار به پیاده سازی متد های مورد نظر میکنندچنین کلاس هایی تدارک بیننده پیاده سازی هر متد هستند که اعلان می کنند (برخی از پیاده سازی ها را می توان به ارث برد).برای مثال میتوانیم یک سوپر کلاس انتزاعی بنام TwoDimensionalShape ‌و زیر کلاس های مقید همانند Square و Triangle داشته باشیم. همچنین میتوانیم یک سوپر کلاس انتزاعی بنام ThreeDimensionalShape و زیر کلاس های مقید همانند Cube, Sphere, Testrahedron داشته باشیم. سوپر کلاس های انتزاعی برای تعریف شی های واقعی بسیار کلی هستند , از اینرو قبل از اینکه شی را نمونه سازی کنیم باید با دقت در مورد ان فکر کنیم.برای مثال اگر شخصی به شما بگوید شکلی دو بعدی ترسیم کنید باید بپرسید چه شکلی؟نحوه تعریف کلاس انتزاعیتعریف یک کلاس همراه با کلمه کلیدی abstract آن را بصورت یک کلاس انتزاعی ایجاد میکند. معمولا یک کلاس انتزاعی حاوی یک یا چند متد انتزاعی است. متد انتزاعی متدی است که با کلمه کلیدی abstract در اعلان خود همراه شده باشد , همانند :public abstract class Shape{

public  void method1(){// non abstract method

}
public abstract void draw(); // abstract method}متد های انتزاعی قابل پیاده سازی در خود کلاس نیستند. هر کلاسی که حاوی هر متد انتزاعی است باید به صورت یک کلاس انتزاعی تعریف شود حتی اگر کلاس حاوی متد های مقید(همان متد های غیر انتزاعی) باشد. همچنین هر زیر کلاس  از یک سوپر کلاس انتزاعی باید پیاده سازی ای از متد های انتزاعی سوپر کلاس را فراهم اورد (در مثال بالا زیر کلاسی که از کلاس Shape ارث بری کرده است الزاما باید متد draw را پیاده سازی کند اما الزامی به پیاده سازی method1 نمیباشد چرا که ان متد ,متدی abstract نمیباشدو خود یک متد مقید محسوب میشود و در کلاس Shape پیاده سازی شده است  , در صورت تمایل کلاس فرزند میتواند آن را بازنویسی کند) . سازنده ها و متد های استاتیک نمی توانند بصورت abstract اعلان شوند. سازنده ها ارث بری ندارند از این رو هرگز نمیتوان یک سازنده abstract را پیاده سازی کرد. به همین ترتیب زیر کلاس ها نمیتوانند متد های استاتیک را override یا تعریف مجدد کنند و از اینرو نمیتوان یک متد استاتیک abstract را پیاده سازی کرداحتمالا این سوال برای شما پیش امده که به چه دلیل نمیتوان متد های استاتیک را override کرد…به دلیل اینکه متد های استاتیک در جاوا به اشیاء ساخته شده از یک کلاس تعلق ندارند و اصطلاحا متد های در سطح کلاس هستند و نمی توان آنها را در کلاس فرزند override کرد و اگر یک متد استاتیک در کلاس فرزند دقیقا با همان امضای متد کلاس پدر وجود داشته باشد خطایی رخ نمی دهد و برنامه بدرستی کامپایل می شود.در این موارد گفته می شود کد متد فرزند متد پدر را hide کرده است و به این کار override گفته نمی شود چون هنوز متد کلاس پدر در سطح همان کلاس قابل دسترسی است.با توجه به اینکه اینترفیس ها از نسخه ی Jdk 8 به بعد می‌توانند متد هایی با پیاده سازی داشته باشند (default method) چه زمانی از abstract class و چه زمانی از interface استفاده کنیم ؟تفاوت بنیادین اینترفیس و کلاس abstract  در این است که اولا کلاس آبسترکت میتواند constructor (سازنده) داشته باشد و این بدین معناست که میتواند مقادیری درون خود نگه دارد و بعد ها بنا به دلایلی از آن استفاده کند.. همچنین اعلام میدارد یک شی نمی‌تواند بوجود آید مگر با فلان مقادیر : مثلا فرض کنید  Human نیاز به جنسیت دارد .. پر واضح است  که یک انسان وجود ندارد مگر اینکه جنسیت آن مشخص باشد .انسانی بدنیا نمی آید که فاقد جنسیت باشدبنابراین در abstract class ما یک سازنده میذاریم و جنسیت رو از کلاس فرزند میگیریم (فرضا فرزند می‌تونه کلاس مونث و مذکر باشد)اما اگر Human را اینترفیس تعریف میکردیم درواقع چنین مفهومی را نقض میکردیم چرا که اینترفیس ها فاقد سازنده هستند. به بیان ساده یک ابسترکت کلاس میگوید آن آبجکت دقیقا کی(چی) استاما اینترفیس میگوید  آن آبجکت دقیقا چه میتواند بکند مثلا  ما میتونیم ابسترکت کلاسی برای پرنده ها تعریف کنیماما همه ی پرنده ها پرواز نمیکننو یک اینترفیس Flyable تعریف کنیم فقط آنهایی که قابلیت پرواز دارند آن را پیاده سازی کنند .به این جمله ی کلیدی توجه کنید :اینترفیس نمی‌تواند توضیح دهد که دوبرمن نوعی سگ است .. تنها میتواند توضیح دهد که دوبرمن میتواند راه رود (یا مثلا هنگام مواجه با دشمن ,او را گاز گیرد )برای اینکه بگوییم دوبرمن نوعی سگ است ناچار به تعریف کلاس پدر برای آن  هستیم </description>
                <category>پارسا کاویان پور</category>
                <author>پارسا کاویان پور</author>
                <pubDate>Sun, 03 Apr 2022 00:32:33 +0430</pubDate>
            </item>
                    <item>
                <title>انواع استثناء در جاوا</title>
                <link>https://virgool.io/@Parsakav/%D8%A7%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D8%B3%D8%AA%D8%AB%D9%86%D8%A7%D8%A1-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7-fn8bb2zumi3d</link>
                <description>سلسله مراتب استثنا در جاوااستثناء چیست ؟ استثناء دلالت بر وجود مشکلی دارد که در زمان اجرای برنامه رخ میدهد. نام استثناء از این حقیقت بر امده است که اگر چه مشکل میتواند همیشه رخ دهد اما استثناء بندرت و در شرایطی خاص رخ میدهد.اگر قاعده ای بر این اصل استوار باشد که عبارتی به طرز صحیح اجرا میشود اما رویدادی میتواند موجب رخ دادن مشکلی گردد پس استثنائی در این قاعده وجود دارد.چرا باید استثناء را مدیریت کنیم؟به کمک مدیریت استثناء میتوانیم از قطع جریان برنامه توسط استثنای رخ داده جلوگیری کرده و به اجرا ادامه دهیم . در مواردی که امکان اجرای برنامه وجود ندارد نیز با پیغام مناسب کاربر را اگاه کنیم.سلسله مراتب استثناء در جاوا :تمام کلاس های استثناء در جاوا از کلاس Exception ارث بری دارند . کلاس های Error و زیر کلاس های ان مانند ThreadDeath, OutOfMemoryException,VirtualMachineError و... نشاندهنده ی حالات غیر عادی هستند که میتوانند در سطح ماشین مجازی جاوا (JVM) رخ دهند . این خطاها به ندرت اتفاق می افتند و توسط مکانیزم مدیریت استثناء نمیتوان آنها را مدیریت کرد . استثناء های چک نشده در برابر چک شده:تمایز مابین این دو از اهمیت ویژه ای برخوردار است چرا که رفتار کامپایلر جاوا با این دو متفاوت است. تمام کلاس هایی که از RuntimeExceptionارث بری میکنند چک نشده و تمام کلاس هایی که از Exception ارث بری میکنند چک شده(Checked) هستندلازم به ذکر است زیر کلاس های Error همگی چک نشده هستند(Unchecked)در استثناء های چک شده کامپایلر باید  اطمینان یابد که استثناء چک شده در بلوک catch گرفتار میشود .با استفاده از کلمه ی کلیدی throws در هنگام تعریف متد, استثناء های چک شده ای که ممکن است متد سبب انها شود اعلام میشوند :public class ExceptionExample{
public void method1() throws Exception{
} 
public void method2(){ 
try{
method1();
 } catch(Exception e){ // handle 
}
 }
 }رویکرد جاوا در استثناء های چک شده برنامه نویس را مجبور میکند تا در مورد مشکلی که ممکن است رخ دهد فکری کنداما در استثناء های چک نشده کامپایلر چنین فرایندی را طی نمیکند  چرا که عموما میتوان با کدنویسی مناسب و صحیح مانع رخ دادن استثناء های چک نشده شدبرای مثال هنگام تقسیم بر صفر میتوانیم قبل از تقسیم اطمینان یابیم که مقسوم علیه صفر نیست . و در این صورت استثنای ArithmeticException به راه نمی افتد .همچنین در استثناء های چک نشده احتیاجی به استفاده از کلمه کلیدی throws در هنگام تعریف متد نیست:public class ExceptionExample{public double divide(int i1,int i2){if(i2!=0) return i1/i2;}}اما در حالت عادی اگر صفر میدادیم و متد را به صورت بالا ننوشته بودیم گرفتار استثنا میشدیم:public class ExceptionExample{public double divide(int i1,int i2){return i1/i2;}}بررسی بلوک finally:برنامه ها بطور مکرر تقاضای دریافت و رها سازی منابع را دارند . برای مثال برنامه ای که فایلی از دیسک میخواند ابتدا تقاضای بازکردن فایل را بعمل می اورد سپس در صورت موافقت برنامه محتویات را خواهد خواند. به طور کلی سیستم عامل از دستکاری مکرر چندین برنامه در یک فایل و بصورت همزمان جلوگیری میکند  از این رو زمانیکه پردازش پایان می یابد فایل باستی توسط برنامه بسته شود (منبع ازاد شود)فرض کنید در حین خواندن فایل استثنایی رخ داده است. برای جلوگیری از فقدان منابع و بسته نشدن فایل, باید به نحوی بتوانیم منبع اشغال شده را ازاد کنیم. اینجاست که finally به ما کمک میکند.این بلوک اختیاری ست و بعد از اخرین بلوک catch قرار میگیرد (میتوان بدون وجود catch بلافاصله بعد از try این بلوک را قرار داد)همیشه پس از اجرای بلوک های catch بلوک  finally اجرا میگرددشاید بپرسید چرا در همان بلوک catch منابع را ازاد نکننیم؟ بخاطر اینکه  اجرای catch وابسته به نوع استثنای رخ داده است و اگر فرضا ماIOException را هندل کردیم و NullponterException رخ  داده است دیگر catch ای که حاوی IOException است اجرا نمیشود و از این رو منبع ازاد نمیگردد:public void method{
Scanner in = null;
try{
in = new Scanner(System.in);
}catch(IOException e){
System.out.println(e.getMessage());
} finally{
in.close();
}
}در نسخه ی java 7 به بعد میتوان از try-with-resources استفاده کرد . در این صورت دیگر نیازی به استفاده از finally نیست . کد بالا را به صورت زیر بازنویسی میکنیم:try(Scanner in = new Scaner(System.in)){// use the Scanner here} catch(IOException e){// catch Exception that occur while using the resourceSystem.out.println(e.getMessage());}نکته : بدون catch نیز میتوانستیم از try-with-resources صرفا برای ازاد سازی خودکار منابع استفاده کنیم.try(Scanner in =new Scanner(System.in)){// use the Scanner here}سایر مطالب مرتبط:کلاس Optional در جاوامنابع : https://docs.oracle.com/en/java/javase/17/Java how to program? 8th edition</description>
                <category>پارسا کاویان پور</category>
                <author>پارسا کاویان پور</author>
                <pubDate>Fri, 01 Apr 2022 21:37:53 +0430</pubDate>
            </item>
                    <item>
                <title>کلاس Optional در جاوا</title>
                <link>https://virgool.io/@Parsakav/%DA%A9%D9%84%D8%A7%D8%B3-optional-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7-izeg5tbqdi7a</link>
                <description>کلاس Optional چیست و چرا باید از آن استفاده کنیم؟کلاسی است که در جاوا ۸ معرفی شده و هدف ان  جلوگیری از خطای معروف nullpointerexception  میباشد(هرچند گویا به طور کامل  از چنین خطایی  نتوانسته جلوگیری کند)میتوان گفت بیشتر ابزاری ست برای راحت تر چک کردن مقادیر تهی و راحت تر گریختن از خطای nullpointerexception بیگمان هرکس که با جاوا کد زده باشد با خطای nullpointerexception اشنا میباشد.فرض کنید کلاسی به نام Person داریم و در ان یک فیلد به نام name و یک گتر برای آن داریم:public class Person {  private String name;  public String getName() {    return name;  }}حال در کلاس main  برنامه ی خود یک متد داریم به این صورت:(فرض کنید این متد بر اساس یکسری عملیات به مقدار null رسیده است..مثلا Person را از دیتابیس خوانده و هیچ مقداری پیدا نکرده است)  public static  Person getPerson() {    return null;  }طبعا هنگامی که در main چنین خط کدی را بنویسیم :  public static void main(String[] args) {getPerson().getName();  }به خطای  nullpointerexception برمیخوریم.حال راه حل جاوا هشت برای گریز از این خطا چیست؟ابتدا توضیحاتی اندک ولی کارامد درمورد متد های کلاس Optional میدهیم:کلاس اپشنال از دیزاین پترن Factory استفاده میکند(اجازه ی ساخت شی با کلید new از ان را نداریم):Optional.empty();Optional.of(T t);Optional.ofNullable();متد اول به جای همان مثال بالا که  null  برگشت دادیم استفاده میشود.متد دوم یک مقدار میپذیرد با این شرط که تهی نباشد و متد سوم میتواند مقداری تهی نیز بپذیرد.حال مثال اول را اینگونه بازنویسی میکنیم:در اغاز بایستی نوع بازگشتی متد را از جنس Optionalتعریف کنیم:  public static  Optional&lt;Person&gt; getPerson() {    return Optional.empty();  }حال در متد main متد getPerson را call میکنیم:public static void main(String[] args) {    Optional&lt;Person&gt; op=getPerson();    System.out.println(op);  }خواهیم دید که دیگر خبری از ارور nullpointerexception نیست بلکه چنین چیزی در خروجی مشاهده میکنیم:Optional.emptyسایر متد های سودمند کلاس اپشنال:orElse(T t);اگر مقدار وجود داشت...مقدار  Tرا برگشت میدهد وگرنه مقداری که در ورودی متد داده اید را برگشت میدهد(دیگر مقدار null درکار نخواهد بود)isPresent();اگر مقداری داخل اپشنال بود true برگشت میدهد اگر نبود falseget();اگر مقدار وجود داشت برگشت میدهد و اگر نبود nosuchelementexception برگشت میدهد(و بازهم خبری از ارور null نیست)ifPresent(Consumer&lt;? super T&gt; consumer) اگر مقدار وجود داشت عملیات مورد نظرمان انجام شودifPresentOrElse(Consumer&lt;? super T&gt; consumer,Runnable run) اگر مقدار وجود داشت عملیات مورد نظر انجام شود و اگر تهی بود متد run از اینترفیس runnable صدا زده میشودو بسیار متد های  سودمند دیگرتوجه داشته باشید runnable در بالا ربطی به ترد ندارد و صرفا بخاطر متد run از ان استفاده شده است</description>
                <category>پارسا کاویان پور</category>
                <author>پارسا کاویان پور</author>
                <pubDate>Sun, 13 Mar 2022 09:32:31 +0330</pubDate>
            </item>
            </channel>
</rss>