October 10, 2017

JShell - Quick Start

ဒီအခန်းမှာတော့ JShell ကို ဘယ်လို စပြီး အသုံးပြုသွားမလဲဆိုတာကို လေ့လာသွားကြပါမယ်။ JShell ရဲ့ အခြေခံအသုံးပြုပုံတွေ၊ ပြီးတော့ Help ကို အသုံးပြုပုံတွေနဲ့ Shortcuts တွေအကြောင်းကို ဖေါ်ပြသွားပါမယ်။


Basic Usages


JShell ဟာ JDK ရဲ့ Tool တစ်ခုဖြစ်တဲ့ အတွက် jdk 9 ကို Install လုပ်လိုက်တာနဲ့ JDK Install Directory ရဲ့ bin အောက်မှာ ပါဝင်ပြီး ဖြစ်နေပါတယ်။ JDK 9 ရဲ့ bin directory ကို Environment Variable Path အောက်မှာ ဖြည့်စွက်လိုက်တာနဲ့ JShell ကို စပြီး အသုံးပြုလို့ရမှာ ဖြစ်ပါတယ်။


Start JShell


JShell ကို စတင် အသုံးပြုဖို့ Terminal (Console) ကနေ jshell command ကို ရိုက်ထည့်ပြီး tools ကို invoke လုပ်ရမှာ ဖြစ်ပါတယ်။ ဒီလို Invoke လုပ်နိုင်အောင်လဲ jshell.exe file ရှိတဲ့ jdk installed Directory အောက်က bin directory ကို PATH environment variable ထဲမှာ သွားရောက်ဖြည့်စွက်ထားရင် ရပါပြီ။

PATH ထဲမှာ လမ်းကြောင်းထည့်ပုံကိုတော့ JDK Installation မှာကထဲက ဖေါ်ပြထားပြီး ဖြစ်တဲ့ အတွက် အဲ့ဒီအတိုင်း ဆောင်ရွက်လိုက်မယ်ဆိုရင်ရမှာ ဖြစ်ပါတယ်။



ဒီအတိုင်း jshell> လို့ပေါ်လာခဲ့ရင် JShell ရဲ့ REPL Mode ကို စတင် အသုံးပြုလို့ရမှာ ဖြစ်ပါတယ်။


Writing Variable


ဆက်လက်ပြီး Variable တွေကို အသုံးပြုကြည့်ပါမယ်။ အရင်ဆုံး Variable တွေကို Declare လုပ်ကြည့်ပါမယ်။ ပြီးရင် သတ်မှတ်ထားတဲ့ Variable ကို တန်ဖိုးတစ်ခု Assign လုပ်ကြည့်ပါမယ်။ ပြီးတော့ အဲ့ဒီ Variable ကို ပြန်ပြီး Access လုပ်ပြီး အသုံးပြုကြည့်ပါမယ်။



JShell ကို အသုံးပြုတဲ့ နေရာမှာ Statement တစ်ကြောင်းရေးပြီးတိုင်းမှာလဲ Semi Comma ကို ပိတ်စရာမလိုအပ်ပါဘူး။ Variable ကို Declare လုပ်တဲ့နေရာမှာလဲ အထက်ပါအတိုင်း String school လို့ ရေးသားလိုက်တာနဲ့ school ဆိုတဲ့ String Type Variable ကို Default တန်ဖိုးဖြစ်တဲ့ null နဲ့ သတ်မှတ်ပေးသွားမှာ ဖြစ်ပါတယ်။

တဖန် ရေးသားထားတဲ့ Variable နေရာကို တန်ဖိုးတစ်ခုခု Assign လုပ်လိုချင်တဲ့ အခါမှာလဲ school = “Java Developer Class” ဆိုပြီး ရေးသားနိုင်ပါတယ်။ အဲ့ဒီလို ရေးသားလိုက်တဲ့ အခါမှာလဲ တန်ဖိုးပြောင်းသွားတယ်ဆိုတာကို school ==> “Java Developer Class” ဆိုပြီး ဖေါ်ပြပေးမှာ ဖြစ်ပါတယ်။

အထက်ပါအတိုင်း မိမိရေးသားထားတဲ့ Variable ကို Method တစ်ခုခုရဲ့ Argument အနေနဲ့ အသုံးပြုလိုတဲ့ အခါမှာလဲ System.out.println(school) ဆိုပြီးရေးသား အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။


Writing Enum


Enum ဆိုတာဟာ Java 5 မှာ စတင်ပါဝင်ခဲ့တဲ့ Static Class အမျိုးအစားတစ်ခုဖြစ်ပါတယ်။ ဒီတစ်ခေါက်တော့ JShell ကို အသုံးပြုပြီး Enum တစ်ခုကို Declare လုပ်ကြည့်ပြီး ရေးသားထားတဲ့ Enum ကို ပြန်ပြီး အသုံးပြုကြည့်ပါမယ်။



Enum တွေကို Declare လုပ်မယ်ဆိုရင်လဲ အထက်ပါအတိုင်း enum Course {} ဆိုပြီး ရေးသားရပါမယ်။ တဖန် enum ရဲ့ Member တွေကိုလဲ {} အတွင်းမှာ ရေးသားနိုင်ပါတယ်။ အထက်ပါအတိုင်း ရေးသားပြီး Enter Key ကို Press လုပ်လိုက်ရင် create enum Course ဆိုပြီး enum တစ်ခုကို Create လုပ်ပြီးကြောင်းကို ဖေါ်ပြပေးမှာ ဖြစ်ပါတယ်။

တဖန် မိမိရေးသားထားတဲ့ Enum ကိုလဲ ပြန်ပြီး Course.values() ဆိုပြီး ပြန်ပြီး အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ အထက်ဖေါ်ပြပါထဲကလို Line အများကြီးကို အသုံးပြုပြီး ရေးသားရတဲ့ for statememt လို နေရာမျိုးမှာလဲ Line တစ်ကြောင်းဆုံးရင် Enter ကို နှိပ်ပြီး ဆက်တိုက်ရေးသားနိုင်မှာ ဖြစ်ပါတယ်။

Line အများကြီးပါတဲ့ Statement တွေဆိုရင်တော့ Statement ပြီးဆုံးသွားမှသာ ရေးသားထားတဲ့ Code တွေကို Evaluate လုပ်ပြီး အဖြေကို ပြန်ပြပေးမှာ ဖြစ်ပါတယ်။ ဒါ့ကြောင့် for statement ရဲ့ အဆုံးဖြစ်တဲ့ } ကို ရိုက်နှိပ်ပြီးတော့မှသာ အဖြေတွေကို ပြန်ပြပေးနေတာဖြစ်ပါတယ်။


Writing Methods


ဆက်လက်ပြီး JShell နဲ့ Method တွေကို ဘယ်လိုရေးမယ်ဆိုတာကို လေ့လာသွားကြပါမယ်။ Method တွေကို ရေးတဲ့ နေရာမှာ Method တွေကို ဘယ်လို ရေးမလဲ၊ ပြီးတော့ Method တွေကို ဘယ်လို Invoke လုပ်မလဲဆိုတာကို လေ့လာသွားပါမယ်။ တဖန် Method တွေလို့ ပြောတဲ့ နေရာမှာလဲ Argument မပါတဲ့ Method တွေ ပြီးတော့ Argument ပါတဲ့ Method တွေ၊ ပြီးတော့ Return ပြန်တဲ့ Method တွေ၊ Return မပြန်တဲ့ Method တွေ ဆိုပြီး ရှိပါတယ်။

Method တွေကို Invoke လုပ်တဲ့ နေရာမှာလဲ Return ပြန်တဲ့ Method တွေဆိုရင် Return ပြန်လာတဲ့ တန်ဖိုးတွေကို Variable တစ်ခုမှာ ဘယ်လို Assign လုပ်မယ်ဆိုတာကို လက်တွေ့ ရေးသားလေ့လာကြည့်ပါမယ်။



အထက်ပါ နမူနာထဲမှာတော့ sayHello() ဆိုတဲ့ Argument လဲမပါ Return လဲ မပြန်တဲ့ Method တစ်ခုကို ရေးသားပါတယ်။ အထက်ပါအတိုင်း Method ကို ရေးသားပြီးတဲ့ အခါမှာ created method sayHello() ဆိုပြီး Method ကို ရေးသားပြီးပြီဖြစ်ကြောင်းကို ပြန်ပြီး ဖေါ်ပြပါတယ်။

ထိုနောက် sayHello() ဆိုပြီး ရေးသားခဲ့တဲ့ sayHello() method ကို Invoke လုပ်လိုက်တဲ့ အခါမှာ အဲ့ဒီ Method ထဲမှာ ရေးသားခဲ့တဲ့ လုပ်ဆောင်ချက်တွေကို ပြန်ပြီး ဖေါ်ပြပေးနိုင်မှာ ဖြစ်ပါတယ်။



အထက်ပါနမူနာကတော့ String name ဆိုတဲ့ Argument တစ်ခုကို ယူတဲ့ sayHello Method ကို ရေးသားကြည့်တာပါ။ အရှေ့မှာ ရေးခဲ့တဲ့ Method နဲ့ Method Name ချင်းတူပါတယ်။ ဒါပေမဲ့ Argument List တွေမတူကြပါဘူး။ ပထမ sayHello မှာက Argument မပါပေမဲ့ ဒုတိယ တစ်ကြိမ်ရေးတဲ့ sayHello Method မှာတော့ String တစ်ခုကို Argument အနေနဲ့ ရယူပါတယ်။

Java Compiler က ဒီလိုမျိုး နာမည်တူပြီး Argument မတူတဲ့ Method တွေကို မတူညီတဲ့ Method တွေလို့ သတ်မှတ်ပါတယ်။ ဒါ့ကြောင့် sayHello() ဆိုပြီး ဘာ Parameter မှ မပါပဲ ရေးသားခဲ့ရင် Argument မပါတဲ့ sayHello() method ကို Invoke လုပ်မှာ ဖြစ်ပြီး၊ sayHello(school) ဆိုပြီး String Type Variable school ကို Parameter အနေနဲ့ ပေးပြီး invoke လုပ်တဲ့ အခါမှာ Argument ပါတဲ့ sayHello(String name) method ကို Invoke လုပ်မှာ ဖြစ်ပါတယ်။

ဒီလိုမျိုး method name တူပြီး Argument List မတူတဲ့ Method တွေကို ရေးသားခြင်းကို Method Overload လုပ်တယ်လို့ ခေါ်ပါတယ်။



အထက်နမူနာမှာတော့ Argument နှစ်ခုကိုရယူပြီး၊ return ပြန်တဲ့ add(int a, int b) method ကို ရေးသားထားတာဖြစ်ပါတယ်။ အဲ့ဒီ Method ထဲမှာတော့ int variable နှစ်ခုကို Argument အနေနဲ့ ရယူပြီး a နဲ့ b ကို ပေါင်းပြီး ရလဒ်ကို Return ပြန်ပေးနေပါတယ်။ တဖန် add method ကို invoke လုပ်တဲ့ နေရာမှာလဲ int result = add(10, 3) ဆိုပြီး 10 နဲ့ 3 ကို a နဲ့ b နေရာကို ပေးပြီး ခေါ်ပါတယ်။ ရလာတဲ့ တန်ဖိုးကို int variable result မှာ အစားထိုးပါတယ်။ အဲ့ဒီ Statement ကို Evaluate လုပ်ပြီးတဲ့ အခါမှာ result ==> 13 ဆိုပြီး result ရဲ့ တန်ဖိုးဟာ 13 ဖြစ်သွားပါပြီဆိုပြီး ဖေါ်ပြနေတာ ဖြစ်ပါတယ်။


Writing Class


ကျွန်တော်တို့ ဒီတစ်ခေါက်တော့ Class တွေကို ရေးကြည့်ပါမယ်။ Class ထဲမှာ Instance Variable တွေပါမယ်။ ပြီးတော့ Method တွေ၊ ပြီးတော့ Constructor ပါပါမယ်။ ပြီးတော့ ရေးထားတဲ့ Class ကနေ Object တစ်ခုကို တည်ဆောက်ကြည့်ပြီး အဲ့ဒီ Object ရဲ့ Method တွေကို Invoke လုပ်ကြည့်ပါမယ်။



အထက်ပါ နမူနာထဲမှာတော့ name ဆိုတဲ့ Instance Variable တစ်ခုရယ်၊ Argument တစ်ခုယူတဲ့ Constructor တစ်ခုရယ်၊ greet() ဆိုတဲ့ Method တစ်ခုပါတဲ့ Student Class တစ်ခုကို ရေးသားထားပါတယ်။ အဲ့ဒီ အတိုင်းရေးပြီးရင် created class Student ဆိုပြီး Student Class ကို ရေးသားပြီးပြီဖြစ်ကြောင်း ဖေါ်ပြမှာ ဖြစ်ပါတယ်။

ဒါဆိုရင် ဒီ Student Class နဲ့ ဘာလုပ်လို့ရမလဲ။ Student အမျိုးအစား Object တွေကို တည်ဆောက်လို့ရမှာ ဖြစ်ပြီး၊ အဲ့ဒီ Student Object ကနေ greet() ဆိုတဲ့ လုပ်ဆောင်မှု့တွေကို ဆောင်ရွက်ပေးနိုင်မှာ ဖြစ်တယ်။



အထက်ပါ ကုဒ်တွေထဲမှာတော့ အရင်ဆုံး aung ဆိုတဲ့ Student Type Variable နေရာကို new Student(“Aung Aung”) ဆိုပြီး Object တစ်ခုကို တည်ဆောက်ပြီး အစားထိုးပါတယ်။ ဒါ့ကြောင့် aung ဆိုတဲ့ Variable နေရာရဲ့ တန်ဖိုးဟာ Student Object က အစားထိုးသွားပါပြီဆိုပြီး ဖေါ်ပြပေးနိုင်တာ ဖြစ်ပါတယ်။

အဲ့ဒီနောက်မှာ aung.greet() ဆိုပြီး Student Object ရဲ့ greet() method ကို လှမ်းပြီး Invoke လုပ်ခိုင်းပါတယ်။ ဒါ့ကြောင့် Hello! My name is Aung Aung ဆိုပြီး greet() method ထဲက လုပ်ဆောင်မှု့တွေကို ဆောင်ရွက်ပေးနိုင်တာ ဖြစ်ပါတယ်။


Writing Interface


ဒီနေရာမှာတော့ JShell ကို အသုံးပြုပြီး Interface ကို ရေးသားကြည့်ပါမယ်။ Interface ဆိုတာက 100% Abstract Class တွေဖြစ်ပြီး Object တစ်ခုကနေ အသုံးပြုနိုင်တဲ့ Method တွေကို စုစည်းဖေါ်ပြပေးနိုင်ပါတယ်။ Interface ကို Object တွေရဲ့ Type အနေနဲ့ အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

ဒီနမူနာထဲမှာတော့ Interface တစ်ခုကို အရင် ရေးသားကြည့်ပါမယ်။ ထိုနောက် Interface ကို Implement လုပ်ထားတဲ့ Class တစ်ခုကို ရေးသားပါမယ်။ ပြီးကာမှ Interface Object ကို Implement လုပ်ထားတဲ့ Class ကနေ တဆင့် Object ဆောက်ကြည့်မယ်။ ဆက်လက်ပြီး Anonymous Class ကနေလဲ Object ဆောက်ကြည့်ပါမယ်။ နောက်ထပ် Lambda Expression ကို အသုံးပြုပြီးလဲ Interface Object ကို တည်ဆောက် အသုံးပြုကြည့်ပါမယ်။



အထက်ပါ နမူနာမှာတော့ add method တစ်ခုပါတဲ့ Addable Interface တစ်ခုကို တည်ဆောက်လိုက်ပါတယ်။ Abstract Method တစ်ခုသာပါတဲ့ Interface ဖြစ်တဲ့ အတွက် Addable ကို Lambda Expression နဲ့လဲ အစားထိုးရေးသားနိုင်မှာ ဖြစ်ပါတယ်။

ဆက်လက်ပြီး Adder Interface ရဲ့ Object တွေကို ပုံစံအမျိုးမျိုးနဲ့ တည်ဆောက် ရေးသားသွားပါမယ်။



ဒီနေရာမှာတော့ ရှေ့က ရေးခဲ့တဲ့ Addable Interface ကို implement လုပ်ထားတဲ့ Adder Class ကို အရင်ဆုံး ရေးသားပါတယ်။ Inerface ကို Implement လုပ်လိုက်ပြီဆိုတာနဲ့ Interface ထဲမှာ ရေးသားထားတဲ့ abstract method ဖြစ်တဲ့ add method ကို Override လုပ်ပြီးရေးသားရပါတော့မယ်။

Addable ထဲမှာ ရေးသားထားတဲ့ add method ကို ကြည့်ပါ။ public လဲ​မရေးထားသလို abstract လဲ မရေးထားပါဘူး။ ပြီးတော့ method body လဲမပါတဲ့ အတွက် Abstract Method ဖြစ်ပါတယ်။ Interface တွေဟာ default abstract နဲ့ public ဖြစ်တဲ့ အတွက် abstract နဲ့ public ကို မရေးထားလဲ public abstract ဖြစ်နေပါတယ်။

ဒါပေမဲ့ Implement လုပ်တဲ့ Adder Class ထဲမှာတော့ public ကိုမဖြစ်မနေ ရေးသားရမှာ ဖြစ်ပြီး၊ Method Body ကိုလဲ ရေးသားရမှာ ဖြစ်ပါတယ်။

ဆက်လက်ပြီး Addable Type ဖြစ်တဲ့ a1 နေရာကို Adder Class ကနေ တဆင် new Adder() ဆိုပြီး Object ကို ဆောက်ပြီး အစားထိုးပါတယ်။ Interface Type Variable တွေကနေ အဲ့ဒီ Interface ကို Implement လုပ်ပြီး ရေးသားထားတဲ့ Class  ရဲ့ Object တွေကို Reference လုပ်နိုင်တဲ့ အတွက် ဖြစ်ပါတယ်။

ဒီနေရာမှာ a1 ရဲ့ Type ဟာ Addable Interface ဖြစ်ပေမဲ့ နောက်ကွယ်မှာ ရှိတဲ့ Object ကတော့ Adder Class ရဲ့ Object ဖြစ်ပါတယ်။ ဆက်လက်ပြီး d1 နေရာကို a1.add(10, 11) ကို Invoke လုပ်ပြီး ရလာတဲ့ ရလဒ်နဲ့ အစားထိုးပါတယ်။ a1 ရဲ့ add(10,11) ကို ခေါ်လိုက်တာဖြစ်ပေမဲ့ တကယ် အလုပ်လုပ်သွားတာကတော့ Adder Class ကနေ တည်ဆောက်ထားတဲ့ Object ရဲ့ add method က အလုပ်လုပ်သွားတာဖြစ်ပါတယ်။ ဒါ့ကြောင့် d1 ရဲ့ တန်ဖိုးဟာ 21.0 ဖြစ်သွားပါပြီလို့ ပြန်ပြောပြနိုင်တာဖြစ်ပါတယ်။

ဒီတစ်ခေါက်ကတော့ Addable Interface ရဲ့ Object ကို Anonymous Class ကနေ တည်ဆောက် အသုံးပြုကြည့်ပါမယ်။



Interface Object တွေကို Anonymous Class တွေကနေလဲ ရေးသား နိုင်ပါတယ်။ အထက်ပါအတိုင်း new Addable() ဆိုပြီး Interface ကိုခေါ်ပြီး လိုအပ်တဲ့ Abstract တိုက်ရိုက်ဒီနေရာမှာပဲ Implement လုပ်ပြီး ရေးသားရပါတယ်။ ဒီနေရာမှာကြည့်မယ်ဆိုရင် a2 ရဲ့ တန်ဖိုးနေရာမှာ Class Name မပါပဲ ရှိနေတာကို တွေ့ရပါမယ်။ ဒါ့ကြောင့်ဒီလို Class မျိုးကို Anonymous Class လို့ခေါ်တာဖြစ်ပါတယ်။

a2.add(10, 11) လို့ Invoke လုပ်လိုက်ရင်လဲ တန်ဖိုးဟာ 21 ဖြစ်တယ်လို့ ဖေါ်ပြနိုင်တာဖြစ်ပါတယ်။



Addable Interface ဟာ Single Abstract Method Interface ဖြစ်တဲ့ အတွက် Lambda Expression  နဲ့လဲ ရေးသားနိုင်ပါတယ်။ ဒါ့ကြောင့် a3 Variable ကို (a,b) -> a + b ဆိုပြီး Lambda Expression နဲ့ အစားထိုးရေးသားနိုင်ခြင်း ဖြစ်ပါတယ်။

a3.add(10, 11) လို့ Invoke လုပ်လိုက်တဲ့အခါမှာလဲ တန်ဖိုးဟာ 21 ဖြစ်တယ်လို့ ဖေါ်ပြနိုင်တာဖြစ်ပါတယ်။



Lambda Expression နဲ့ ရေးသားလို့ရတဲ့ နေရာတိုင်းကို Method Reference နဲ့လဲ ရေးသားနိုင်ပါတယ်။ အထက်ပါ နမူနာကတော့ Method Reference ကို အသုံးပြုပြီး ရေးသားထားတာ ဖြစ်ပါတယ်။ a4 ရဲ့ add method ကို Invoke လုပ်ကြည့်တဲ့ အခါမှာလဲ မှန်ကန်တဲ့ အဖြေကို ဖေါ်ပြနိုင်တာကို တွေ့ရပါတယ်။


Using Helps & Commands


JShell ကို အသုံးပြုရင် Java Statement တွေကို Evaluate လုပ်ပြီး အဖြေကို ချက်ချင်းပြန်ပြပေးနိုင်တယ်ဆိုတာကို လက်တွေ့ လေ့လာခဲ့ပါတယ်။ ဒါပေမဲ့ JShell ကို အသုံးပြုတဲ့ နေရာမှာ ပိုပြီး အသုံးပြုရတာလွယ်ကူစေရန် ပြင်ဆင်ထားတဲ့ Commands တွေနဲ့ Help Feature တွေလဲပါဝင်ပါတယ်။

JShell မှာ အသုံးပြုနိုင်တဲ့ Function တွေကိုတော့ /help command ကို အသုံးပြုပြီး သိရှိစေနိုင်ပါတယ်။



တဖန် မိမိရှာဖွေလိုတဲ့ Command ရဲ့ အသုံးပြုပုံကို သိရှိလိုပါက /? ကို အသုံးပြုပြီး ရှာဖွေနိုင်ပါတယ်။



Listing Sources


ဆက်လက်ပြီး အသုံးများတဲ့ Command တွေကို လေ့လာသွားပါမယ်။ အရင်ဆုံးမိမိ ရေးသားထားခဲ့တဲ့ Source တွေကို ပြန်ကြည့်လိုပါက /list ဆိုတဲ့ Command ကို အသုံးပြုနိုင်ပါတယ်။



JShell ပေါ်မှာ မိမိရေးသားခဲ့တဲ့ Source တွေကို ID နံပါတ်နဲ့ အတူ ဖေါ်ပြပေးနိုင်မှာ ဖြစ်ပါတယ်။



တဖန် ID ကို ရွေးချယ်ပြီး Execute လုပ်ချင်တယ်ဆိုရင်လဲ /[ID] ကို အသုံးပြုပြီး ရေးသားနိုင်မှာ ဖြစ်ပါတယ်။


Listing Variables


မိမိရေးသားခဲ့တဲ့ Variables တွေကို ပြန်ပြီး ကြည့်လိုပါက /vars Command ကို အသုံးပြုနိုင်ပါတယ်။




Listing Methods


မိမိရေးသားခဲ့တဲ့ Methods တွေကို ပြန်ပြီး ကြည့်လိုပါက /methods Command ကို အသုံးပြုနိုင်ပါတယ်။




Listing Types


တဖန် မိမိရေးသားခဲ့တဲ့ Type အဖြစ် အသုံးပြုနိုင်တဲ့ Class, Interface နဲ့ Enum တို့ကို /types Command ကို အသုံးပြုပြီး ပြန်ကြည့်နိုင်ပါတယ်။




Edit with External Editor


တဖန် မိမိရေးသားထားခဲ့တဲ့ Type တွေကို External Editor ကို အသုံးပြုပြီး ပြုပြင်လိုတဲ့အခါမျိုးမှာ /edit [source] Command ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

/edit sayHello လို့ ရေးလိုက်တာနဲ့ sayHello Method တွေကို External Editor နဲ့ ဖွင့်ပေးမှာ ဖြစ်ပါတယ်။



ပြင်ဆင်လိုတဲ့ နေရာကို ပြင်ဆင်ပြီး Accept ကို နှိပ်လိုက်ပါက Source ထဲမှာလဲ ပြောင်းပေးမှာ ဖြစ်ပါတယ်။



အထက်ပါအတိုင်း Hello JShell ကို We Love JDC လို့ပြောင်းပြီး Accept ကို နှိပ်လိုက်ပါမယ်။


အထက်ပါအတိုင်း sayHello() ဆိုပြီး Method ကို Invoke လုပ်လိုက်ရင် We Love JDC ဆိုပြီး ပြောင်းသွားမှာ ကိုတွေ့ရပါမယ်။



Listing Imports


JShell ထဲမှာ Default အတိုင်းပါဝင်တဲ့ imports တွေနဲ့ မိမိရေးသားထားတဲ့ imports တွေကို သိရှိလိုပါက /imports Commands ကို အသုံးပြုနိုင်ပါတယ်။


အထက်မှာ မြင်ရတဲ့ အတိုင်း JShell ထဲမှာ အသုံးများတဲ့ Package တွေကိုပဲ Import လုပ်ထားတာ ဖြစ်ပါတယ်။ ဒါဟာ Java 9 မှာ စတင်ပါဝင်လာတဲ့ Modularity ကို အသုံးပြုပြီး Basic Module ကိုပဲ Import လုပ်ထားတဲ့ အတွက် ဖြစ်ပါတယ်။ နောက်အခန်းများမှာ Modularity နဲ့ ပတ်သက်ပြီး ဆက်လက် ဖေါ်ပြသွားပါမယ်။


Date And Time API ထဲက Class တွေကို အသုံးပြုလိုပါက ဒီအတိုင်းရေးမယ်ဆိုရင် import ထဲမှာ မပါဝင်တဲ့ အတွက် Error တက်မှာ ဖြစ်ပါတယ်။ အသုံးပြုချင်တယ်ဆိုရင်တော့ မိမိကိုယ်တိုင် import လုပ်ပြီး ရေးသားရမှာ ဖြစ်ပါတယ်။


အထက်ပါအတိုင်း java.time.LocalDate ကို import လုပ်ပြီး ရေးသားပါမှ​ အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။



Shortcuts


Console Program အတော်များများမှာ Shortcuts တွေဟာ မရှိမဖြစ် လိုအပ်တဲ့ Feature တစ်ခုဖြစ်ပါတယ်။ JShell မှာလဲ Code Snippest တွေကို အလွယ်တကူရေးသားနိုင်အောင် Shortcuts တွေကို ပြင်ဆင်ထားတာကို တွေ့ရပါတယ်။

ဘယ်လို Shortcuts တွေကို အသုံးပြုနိုင်တယ်ဆိုတာကို သိရှိလိုပါက /help shortcuts ဒါမှမဟုတ် /? shortcuts command ကို အသုံးပြုနိုင်ပါတယ်။



အထက်ပါအတိုင်း JShell မှာ အသုံးပြုနိုင်တဲ့ Shortcuts ၃ မျိုးရှိတာကို တွေ့ရပါတယ်။ OS အပေါ်မှာ မူတည်ပြီး အသုံးပြုနိုင်တဲ့ Key တွေ မတူညီနိုင်တာ ဖြစ်တဲ့ အတွက် အသုံးပြုခါနီးမှာ /help နဲ့ ပြန်ကြည့်သင့်ပါတယ်။


Tab Key


Tab Key ဟာ အမတန် အသုံးဝင်တဲ့ Shortcut တစ်မျိုးဖြစ်ပါတယ်။ Code Complete လို Function မျိုးကိုလဲရရှိနိုင်သလို၊ method တွေရဲ့ Argument တွေနဲ့ Constructor Overload တွေကိုလဲ သိရှိနိုင်ပါတယ်။


အထက်ပါအတိုင်း String လို့ရိုက်ပြီး Tab Key ကို နှိပ်လိုက်ပါက String နဲ့စတဲ့ Type တွေကို ဖေါ်ပြပေးနိုင်တာကို တွေ့ရပါမယ်။


တဖန် String. ဆိုပြီး Tab Key ကို နှိပ်လိုက်ပါက String Class နဲ့ အသုံးပြုနိုင်တဲ့ static Method တွေကို ဖေါ်ပြပေးနိုင်တာကို တွေ့ရပါတယ်။


အထက်ပါအတိုင်း new StringBuffer( လို့ရိုက်ပြီး Tab Key ကို နှိပ်လိုက်ပြန်ရင်လဲ StringBuffer ရဲ့ Override လုပ်ထားတဲ့ Constructor တွေကို ဖေါ်ပြပေးနိုင်တာကို တွေ့ရပါမယ်။


တဖန် sb.append( ဆိုပြီး Tab Key ကိုနှိပ်ရင်လဲ Overload လုပ်ထားတဲ့ Method တွေကို ဖေါ်ပြပေးမှာ ဖြစ်တဲ့ အတွက် မိမိရေးသားလိုတဲ့ Method ကို အသုံးပြုပြီး အလွယ်တကူရေးသားနိုင်မှာ ဖြစ်ပါတယ်။



Shift + Tab + i


အထက်ပါ Short Cut ကတော့ import တွေကို အကူအညီပေးနိုင်တဲ့ Shortcut ဖြစ်ပါတယ်။



အထက်ပါအတိုင်း import မလုပ်ရသေးတဲ့ LocalDate ကို ရိုက်ပြီးတာနဲမ Shft + Tab ကို တွဲပြီး နှိပ်ပါမယ်။ လွှတ်ပြီးတာနဲ့ i ကို ရိုက်လိုက်ရင် ဘာရွေးမလဲဆိုတာကို ဖေါ်ပြပေးမှာ ဖြစ်ပါတယ်။

အဲ့ဒီနေရာမှာ 0 ကို ရွေးခဲ့ရင် ဘာမှ လုပ်မှာ မဟုတ်ပဲ၊ 1 ကို ရွေးခဲ့ရင် java.time.LocalDate ကို import လုပ်မှာ ဖြစ်ပါတယ်။ ထိုကဲ့သို့ Shortcut ကို အသုံးပြုပြီးလဲ import တွေကို အလွယ်တကူ အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။


Shift + Tab + v


Variable တွေကို Create လုပ်ပေးနိုင်တဲ့ Shortcut ဖြစ်ပါတယ်။ Expression တစ်ခုကို ရေးသားပြီး အဖြေကို ကြည့်ပြီးမှ Variable တစ်ခုမှာ Assign လုပ်လိုတဲ့ အခါမျိုးမှာ အသုံးဝင်ပါတယ်။



အထက်ပါအတိုင်း LocalDate.now() ရဲ့ ရလဒ်ကိုစစ်ပြီးတော့မှ Up Arrow ကို အသုံးပြုပြီး LocalDate.now() ကို ပြန်ပြီး Console မှာ ဖေါ်ထားပါမယ်။ ပြီးတော့ ချက်ချင်းဆိုသလိုပဲ Shift + Tab ကိုနှိပ်ပါမယ်။ ချက်ချင်းပြန်လွှတ်ပြီး v ကို နှိပ်ပါမယ်။

အထက်ပါအတိုင်း LocalDate = LoalDate.now() ဆိုပြီး LocalDate နဲ့ = ရဲ့ကြား Variable Name နေရာမှာ Cursor ကို ချထားပေးမှာ ဖြစ်ပါတယ်။ အဲ့ဒီနေရာမှာ နှစ်သက်တဲ့ Variable Name ကိုပေးပြီး Variable အသစ်တစ်ခုကို ရေးသားနိုင်မှာ ဖြစ်ပါတယ်။

Expression ရဲ့ ရလဒ်ကို စစ်ဆေးပြီးမှ Variable အသစ်တစ်ခုကို ရေးသားလိုတဲ့ အခါမျိုးမှာ အသုံးဝင်မှာ ဖြစ်ပါတယ်။


/exit or Ctl + d


နောက်ဆုံး JShell ကို အဆုံးသတ်လိုတဲ့ အခါမျိုးမှာ /exit Command ဒါမှမဟုတ် CTL + d Shortcut ကို အသုံးပြုပြီး JShell REPL ကို အဆုံးသတ်စေနိုင်မှာ ဖြစ်ပါတယ်။

ဆက်ပါဦးမည်
မင်းလွင်

October 9, 2017

JShell

လူပြောများနေတဲ့ Java 9  ဟာ၂၀၁၇ ခု လပိုင်း ၂၁ ရက်နေ့မှာ တရားဝင် ထွက်ပေါ်ခဲ့ပါပြီ။ Modular Java, HTTP 2 Client, Security Update အစရှတဲ့ အထင်ကရ Feature တွေများလွန်းလို့ ဘယ်ကနေ ဘယ်လို စပြီး လေ့လာရမှန်းမသိခဲ့ပါဘူး။ 


ဒီလိုနဲ့ Java မှာ အခုမှပါလာတဲ့ REPL (Read - Eval - Print - Loop) ဖြစ်တဲ့ JShell ကနေ စပြီး လေ့လာသွားပါမယ်။ REPL ဆိုတာကတော့ နာမည်အတိုင်း ရေးသားလိုက်တဲ့ ကုဒ်တွေကို ဖတ်မယ်၊ ပြီးရင် ဘယ်လိုလုပ်ရမယ်ဆိုတာကို ဆုံးဖြတ်ပြီးတော့ အဖြေကို ပြန်ထုတ်ပြ၊ ဒါကို အကြိမ်ကြိမ်ဆောင်ရွက်နိုင်တဲ့ Interactive Tools တစ်မျိုးဖြစ်ပါတယ်။


အခြားသော Programming Language တွေမှာတော့ အတော်များများ REPL Tools တွေကို Support လုပ်ထားပေမဲ့ Java မှာတော့ ဒီတစ်ခေါက် Java 9 ရောက်မှာ ပါဝင်လာခဲ့တာဖြစ်ပါတယ်။ JShell ကို Open JDK ရဲ့ Sub Project တစ်ခုဖြစ်တဲ့ Project Kulla ကနေ တီထွင် ရေးသားခဲ့တာဖြစ်ပါတယ်။

JShell ကိုလေ့လာတဲ့ နေရာမှာ အောက်ပါအတိုင်း လေ့လာသွားမှာ ဖြစ်ပါတယ်။

  • Quick Start JShell
    JShell
    ကို အသုံးပြုနိုင်ဖို့ အခြေခံသိထားသင့်တဲ့ အကြောင်းအရာတွေကို ဒီနေရာမှာ ဖေါ်ပြသွားပါမယ်
  • Rules of JShell
    JShell
    ကို အသုံးပြုပြီး ဘာတွေလုပ်လို့ရတယ် ဘာတွေ လုပ်လို့မရဘူးဆိုတာတွေကို ဒီနေရာမှာ ဖေါ်ပြသွားပါမယ်
  • Usecases of JShell
    JShell
    ကို လက်တွေ့ ဘယ်လိုနေရာတွေမှာ အသုံးပြုသင့်တယ်ဆိုတယ်ဆိုတာတွေကို ဖေါ်ပြသွားပါမယ်

ဆက်ပါဦးမယ်။
မင်းလွင်

February 15, 2017

I/O Streams

အရင်တစ်ခေါက် File အကြောင်းရေးသားခဲ့စဉ်က File တွေ Directory တွေကို Create လုပ်နိုင်တယ်။ ပြီးတော့လဲ Delete လုပ်နိုင်တယ်။ အမည်ပြောင်းတာတို့လဲ လုပ်နိုင်ခဲ့ပါတယ်။ ဒါပေမဲ့ အဲ့ဒီ File တွေထဲက Data တွေကို Read လုပ်တာတို့ Write လုပ်တာတို့ကို မလုပ်နိုင်ခဲ့ပါဘူး။

File ထဲက Data တွေကို Input Output လုပ်နိုင်ဖို့အတွက် I/O Stream တွေကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။ Java Language မှာ I/O Stream တွေကို အသုံးပြုမည့် Data Type အပေါ်မူတည်ပြီး အမျိုးမျိုးပြင်ဆင်ထားပါတယ်။ ပြီးတော့ I/O Stream တွေကို ရေးသားတဲ့နေရာမှာလဲ Design Pattern တွေကို အသုံးပြုရေးသားထားပါတယ်။ အရင်ဆုံး I/O Stream တွေကို လေ့လာတဲ့နေရာမှာ အသုံးပြုနိုင်တဲ့ I/O Stream တွေနဲ့ အသုံးပြုပုံတွေကို လေ့လာပြီး၊ နောက်ပိုင်းမှ I/O Stream တွေမှာ အသုံးပြုထားတဲ့ Design Patterns တွေကို လေ့လာသွားပါမယ်။


What are Streams?

Stream တွေဟာ Java Program ထဲမှာအသုံးပြုမည့် Input Source တွေနဲ့ Output Destination တွေကိုကိုယ်စားပြုတဲ့ Interface Object တွေဖြစ်ကြပါတယ်။ Source တွေကော Destination တွေပါ ပုံစံအမျိုးမျိုးရှိနိုင်ကြပြီး Input Output လုပ်ကြမည့် Data တွေလဲ​အမျိုးမျိုးဖြစ်နိုင်ပါတယ်။

Input Source လိုပြောတဲ့နေရာမှာ File တစ်ခုလဲဖြစ်နိုင်သလို System Console ကလာတဲ့ Input လဲ ဖြစ်နေနိုင်ပါတယ်။ ဒါမှမဟုတ် အခြားသော Program တစ်ခုခုလဲ ဖြစ်နိုင်ပါတယ်။ ဒီလိုပဲ Output Destination လို့ပြောတဲ့နေရာမှာလဲ File တစ်ခုခု၊ System Console ဒါမှမဟုတ် အခြားသော Program တစ်ခုခုလဲ ဖြစ်နေနိုင်ပါတယ်။ ဒါပေမဲ့ အခြေခံအားဖြင့်တော့ I/O Stream တွေကို Input Stream တွေနဲ့ Output Streams တွေဆိုပြီး သတ်မှတ်ထားပါတယ်။


Input Streams


Java Program ထဲကအသုံးပြုရန် Data များအား Source တစ်နေရာရာမှ ဖတ်ယူနိုင်ဖို့အတွက် Input Stream များကို အသုံးပြုရပါတယ်။ အသုံးပြုလိုတဲ့ Data Type အပေါ်မူတည်ပြီး Streams အမျိုးမျိုးကိုလဲ ပြင်ဆင်ထားပါတယ်။ အသုံးပြုနိုင်တဲ့ Data Type တွေကတော့ bytes, primitive type data, localize character များနဲ့ Object တွေပဲ ဖြစ်ကြပါတယ်။


Output Streams


Java Program ထဲကနေ Destination တစ်ခုဆီကို Data များကို Output လုပ်ချင်တဲ့အခါ Output Stream တွေကို အသုံးပြုနိုင်ပါတယ်။ Destination အနေနဲ့ File တစ်ခုခုဖြစ်နိုင်သလို၊ System Console လဲ ဖြစ်နိုင်သလို အခြားသော Program တစ်ခုခုလဲ ဖြစ်နိုင်ပါတယ်။ ပြီးတော့ byte အနေနဲ့သော်၎င်း၊ primitive data type အနေနဲ့သော်၎င်း၊ localize character များအနေနဲ့သော်၎င်း၊ Object များအနေနဲ့သော်၎င်း Outputလုပ်နိုင်ပါတယ်။

Input Stream တုန်းကလိုပဲ အသုံးပြုလိုတဲ့ Data Type တွေအလိုက် Stream တွေကို ရွေးချယ် အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။


Data Types and Streams


Java IO ရဲ့ Stream Class တွေအားလုံးဟာ InputStream နဲ့ OutputStream Class တွေကနေ ဆင်းသက်လာကြတဲ့ Class တွေဖြစ်ပါတယ်။ Input Output အနေနဲ့ အသုံးပြုလိုတဲ့ Data Type အလိုက် Stream တွေကို ခွဲခြားအသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

Data Types Input Streams Output Streams
Byte FileInputStream FileOutputStream
Characters FileReader FileWriter
String Line BufferedReader PrintWriter
Primitive Data DataInputStream DataOutputStream
Objects ObjectInputStream ObjectOutputStream


Byte Streams


File တစ်ခုထဲက Data တွေကို Binary Data တွေဖြစ်တဲ့ 8-bit bytes ပုံစံနဲ့ Read Write လုပ်လိုတဲ့အခါ Byte Streams တွေကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။ Byte Stream တွေအားလုံးဟာ InputStream နဲ့ OutputStream Class တွေရဲ့ Sub Class တွေဖြစ်ကြပြီး အသုံးများတာကတော့ FileInputStream နဲ့ FileOutputStream Class တို့ပဲ ဖြစ်ကြပါတယ်။

FileInputStream ကတော့ File တစ်ခုကနေ Byte တွေကို Read လုပ်ချင်တဲ့အခါမှာ အသုံးပြုနိုင်တဲ့ Stream တစ်ခုဖြစ်ပြီး၊ FileInputStream Object ကို တည်ဆောက်ရန် Constructor ၃ မျိုးပြင်ဆင်ထားပါတယ်။

Constructor Description
FileInputStream(File file) Input လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileInputStream(FileDescription fdObj) Input လုပ်မည့် File ကို ဖေါ်ပြပေးနိုင်တဲ့ FileDescriptor Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileInputStream(String name) Input လုပ်မည့် File ရဲ့ အမည် String Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်

FileInputStream Object ကနေ byte တွေကို 1 byte ချင်း Read လုပ်လိုတဲ့အခါ read() ဆိုတဲ့ Method ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

FileOutputStream ကတော့ File တစ်ခုဆီကို Byte တွေ အနေနဲ့ Output လုပ်ပေးနိုင်တဲ့ Stream Object တစ်ခု ဖြစ်ပါတယ်။ FileOutputStream Object ကို တည်ဆောက်ဖို့အတွက် ပြင်ဆင်ထားတဲ့ Constructor တွေကတော့ အောက်ပါ အတိုင်းဖြစ်ကြပါတယ်။

Constructor Description
FileOutputStream(File file) Output လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileOutputStream(File file, boolean append) Output လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object နဲ့ boolean တန်ဖိုးတစ်ခုကို Argument အနေနဲ့ ပေးရပါမယ်။
boolean ရဲ့ တန်ဖိုးဟာ true ဖြစ်မယ်ဆိုရင် လက်ရှိရှိပြီးသား File မှာ Output လုပ်လာတဲ့ Data တွေကို ဆက်ပြီးထည့်ပေးနိုင်မှာ ဖြစ်ပါတယ်
FileOutputStream(FileDescription fdObj) Output လုပ်မည့် File ကို ဖေါ်ပြပေးနိုင်တဲ့ FileDescriptor Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileOutputStream(String name) Output လုပ်မည့် File ရဲ့ အမည် String Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileOutputStream(String name, boolean append) Output လုပ်မည့် File ရဲ့ အမည်ကို String Object နဲ့ boolean တန်ဖိုးတစ်ခုကို Argument အနေနဲ့ ပေးရပါမယ်။
boolean ရဲ့ တန်ဖိုးဟာ true ဖြစ်မယ်ဆိုရင် လက်ရှိရှိပြီးသား File မှာ Output လုပ်လာတဲ့ Data တွေကို ဆက်ပြီးထည့်ပေးနိုင်မှာ ဖြစ်ပါတယ်

Output လုပ်လိုတဲ့ Byte Data တွေကို ရေးသားနိုင်ဖို့အတွက် write(int b), write(byte [] b) နဲ့ write(byte [] b, int off, int len) method တို့ကို ပြင်ဆင်ထားပါတယ်။ 1 byte ချင်း Write လုပ်ချင်ရင်တော့ write(int b) ကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။

Stream Object တွေဟာ Resource တွေကို အသုံးပြုနေတဲ့ Object အမျိုးအစား ဖြစ်တဲ့အတွက် အသုံးပြုပြီးတဲ့အခါမှာ ပြန်ပြီး ပိတ်ပေးဖို့လိုအပ်တဲ့အတွက် close() ဆိုတဲ့ Method ကိုလဲ ပြင်ဆင်ပေးထားပါတယ်။ ဒါပေမဲ့ Java SE 7 ရဲ့ ရေးသားပုံအသစ်ဖြစ်တဲ့ try-with-resource ရေးသားပုံနဲ့ ရေးသားမယ်ဆိုရင်တော့ အလိုအလျောက် ပိတ်ပေးနိုင်မှာ ဖြစ်ပါတယ်။
package com.jdc.io.stream.ep1;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyByte {

    public static void main(String[] args) {
        
        try (FileInputStream in = new FileInputStream("from.txt");
                FileOutputStream out = new FileOutputStream("to.txt")){
            
            int i = 0;
            
            while((i = in.read()) != -1) {
                out.write(i);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

အထက်ပါနမူနာကတော့ from.txt ဆိုတဲ့ File ထဲမှာရှိတဲ့ Data တွေကို 1 byte ချင်း read လုပ်ပြီး to.txt ဆိုတဲ့ဖိုင်ထဲကို 1 byte ချင်း write လုပ်နေတဲ့ နမူနာဖြစ်ပါတယ်။

FileInputStream နဲ့ FileOutputStream Object တွေကို try with resource နဲ့ ရေးသားထားတဲ့အတွက် နောက်ဆုံးမှာ အလိုအလျောက်ပိတ်ပေးသွားမှာ ဖြစ်တယ်။ အဲ့ဒီအတွက် တကူးတက close လုပ်ပေးစရာမလိုတော့ ပါဘူး။ တဖန် while clause ထဲမှာ i = in.read() ဆိုပြီး FileInputStream ကနေ 1 byte ချင်း Read လုပ်နေပါတယ်။ နောက်ဆုံး Read လုပ်စရာမရှိတော့တဲ့အခါ -1 ကို Return ပြန်မှာ ဖြစ်ပြီး While loop ထဲကနေ ထွက်သွားမှာ ဖြစ်ပါတယ်။

While Loop ထဲမှာတော့ Read လုပ်လာတဲ့ တန်ဖိုးကို 1 byte ချင်း FileOutputStream ကို သုံးပြီး write လုပ်ပေးနေပါတယ်။ ဤနည်းအားဖြင့် from.txt ဖိုင်ထဲက Data တွေကို to.txt ဖိုင်ထဲကို 1 byte ချင်း Write လုပ်ပေးသွားနိုင်မှာ ဖြစ်ပါတယ်။


Character Streams

Text File တစ်ခုအတွင်းရှိ Data များကို Character ပုံစံနဲ့ Read / Write လုပ်ချင်ရင် Character Streams များကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။ Character Streams တွေဟာ InputStreamReader နဲ့ OutputStreamWriter တို့ရဲ့ Sub Class တွေ ဖြစ်ကြပြီး FileReader နဲ့ FileWriter တို့ဟာ အသုံးများပါတယ်။

FileReader နဲ့ FileWriter တို့ဟာ Default Encoding နဲ့ Character တွေကို အလွယ်တကူ Read / Write လုပ်နိုင်အောင်ပြင်ဆင်ထားတဲ့ Class တွေဖြစ်ကြပြီး၊ Character Set တို့ကို ကိုယ်တိုင် သတ်မှတ်ပြီး Read / Write လုပ်ချင်ရင်တော့ InputStreamReader နဲ့ OutputStreamWriter တို့ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

FileReader ကို Character များကို Read လုပ်တဲ့နေရာမှာ အသုံးပြုပြီး ရေးသားနိုင်တဲ့ Constructor များကတော့ အောက်ပါ အတိုင်းဖြစ်ကြပါတယ်။

Constructor Description
FileReader(File file) Input လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileReader(FileDescription fdObj) Input လုပ်မည့် File ကို ဖေါ်ပြပေးနိုင်တဲ့ FileDescriptor Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileReader(String name) Input လုပ်မည့် File ရဲ့ အမည် String Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်

FileWriter ကို Character များကို Write လုပ်တဲ့နေရာမှာ အသုံးပြုပြီး ရေးသားနိုင်တဲ့ Constructor များကတော့ အောက်ပါ အတိုင်းဖြစ်ကြပါတယ်။

Constructor Description
FileWriter(File file) Output လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileWriter(File file, boolean append) Output လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object နဲ့ boolean တန်ဖိုးတစ်ခုကို Argument အနေနဲ့ ပေးရပါမယ်။
boolean ရဲ့ တန်ဖိုးဟာ true ဖြစ်မယ်ဆိုရင် လက်ရှိရှိပြီးသား File မှာ Output လုပ်လာတဲ့ Data တွေကို ဆက်ပြီးထည့်ပေးနိုင်မှာ ဖြစ်ပါတယ်
FileWriter(FileDescription fdObj) Output လုပ်မည့် File ကို ဖေါ်ပြပေးနိုင်တဲ့ FileDescriptor Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileWriter(String name) Output လုပ်မည့် File ရဲ့ အမည် String Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileWriter(String name, boolean append) Output လုပ်မည့် File ရဲ့ အမည်ကို String Object နဲ့ boolean တန်ဖိုးတစ်ခုကို Argument အနေနဲ့ ပေးရပါမယ်။
boolean ရဲ့ တန်ဖိုးဟာ true ဖြစ်မယ်ဆိုရင် လက်ရှိရှိပြီးသား File မှာ Output လုပ်လာတဲ့ Data တွေကို ဆက်ပြီးထည့်ပေးနိုင်မှာ ဖြစ်ပါတယ်
FileReader နဲ့ FileWriter တို့ရဲ့ အသုံးပြုပုံဟာ အခြေခံအားဖြင့် FileInputStream နဲ့ FileOutputStream တို့နဲ့အတူတူပဲ ဖြစ်ပါတယ်။
package com.jdc.io.stream.ep2;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyChar {
    
    public static void main(String[] args) {
        
        try(FileReader in = new FileReader("from.txt");
                FileWriter out = new FileWriter("out.txt")) {
            
            int c = 0;
            
            while((c = in.read()) != -1) {
                out.write(c);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

FileReader ကို အသုံးပြုပြီး Text File အတွင်းမှ Character များကို Read လုပ်ရာမှာ read() method ကို အသုံးပြုနိုင်မှာဖြစ်ပါတယ်။ Return Type မှာ int ဖြစ်ပြီး Character တစ်လုံးကို ကိုယ်စားပြုမှာ ဖြစ်ပါတယ်။ နောက်ဆုံး Read လုပ်စရာမရှိတော့တဲ့အခါ -1 ကို Return ပြန်မှာဖြစ်ပါတယ်။

Character စာလုံးများကို Write လုပ်လိုတဲ့အခါ FileWriter Object ရဲ့ write(int char) method ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ Write Method ကို အသုံးပြုပြီး Character တစ်လုံးချင်းစီကို Output လုပ်ပေးနိုင်မှာ ဖြစ်ပါတယ်။

အထက်ပါနမူနာထဲံမှာတော့ from.txt file ထဲမှ Character များကို while statement ဖြင့် တစ်လုံးစီဖတ်ပြီး out.txt file ထဲကို Character တစ်လုံးစီ Output လုပ်ပေးနိုင်မှာ ဖြစ်ပါတယ်။


Line Oriented IO


Character I/O ကို အသုံးပြုတဲ့အခါမှာ Character တစ်လုံးခြင်း Read / Write လုပ်တာထက် ဒီထက်ပိုပြီး ကြီးမားတဲ့ Unit နဲ့ Read / Write လုပ်လေ့ရှိပါတယ်။ အသုံးများတာက စာကြောင်း တစ်ကြောင်းစီကို Read / Write လုပ်တဲ့ပုံစံပဲ ဖြစ်ပါတယ်။ Line တစ်ခုချင်းစီကို Read / Write လုပ်ဖို့အတွက် BufferedReader, BufferedWriter နဲ့ PrintWriter တို့ကို အသုံးပြုနိုင်ပါတယ်။


BufferedReader

BufferedReader တွေဟာ Text File တွေကနေ Character တွေကို သတ်မှတ်ထားတဲ့ Buffered Size အလိုက် Character Array အဖြစ်သော်၎င်း၊ စာကြောင်းတစ်ကြောင်းစီလိုက်သော်၎င်း Read လုပ်နိုင်အောင်ပြင်ဆင်ထားတဲ့ Class တွေ ဖြစ်ပါတယ်။

BufferedReader Class ကို Object ဆောက်နိုင်တဲ့ Constructor တွေကတော့ အောက်ပါ အတိုင်းဖြစ်ပါတယ်။

Constructor Description
BufferedReader(Reader in) Reader Object တစ်ခုကို Argument အနေနဲ့ပေးရပါမယ်။​ Buffer Size ကိုတော့ Default Size အတိုင်း အသုံးပြုသွားမှာ ဖြစ်ပါတယ်။
BufferedReader(Reader in, int size) Reader Object တစ်ခုနဲ့ Buffer Size ကို Argument အနေနဲ့ ပေးပြီး BufferedReader Object တစ်ခုကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Buffer Size ကို သတ်မှတ်ပြီး အသုံးပြုလိုပါက ဤ Constructor ကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။

package com.jdc.io.stream.ep3;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class LineReader {
    
    public static void main(String[] args) {
        
        try(BufferedReader in = new BufferedReader(new FileReader("line.txt"))) {
            
            String line = null;
            
            while((line = in.readLine()) != null) {
                System.out.println(line);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BufferedReader ကနေ စာကြောင်း တစ်ကြောင်းစီ Read လုပ်လိုပါက readLine() method ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ အထက်ပါ နမူနာမှာတော့ in.readLine() ကို အသုံးပြုပြီး line variable မှာ အစားထိုးနေပါတယ်။ ပြီးတော့ While Statement မှာ line ဟာ null မဖြစ်မခြင်း loop ပတ်နေမှာ ဖြစ်ပြီး စာကြောင်းတွေ ဖတ်စရာကုန်သွားရင် null ကို Return လုပ်မှာ ဖြစ်တဲ့အတွက် looping ထဲကနေ ထွက်သွားပါလိမ့်မယ်။

ဒါ့ကြောင့် line.txt ထဲက စာကြောင်းတွေကို အစ စာကြောင်းကနေ တစ်ကြောင်းချင်း ကုန်သွားသည် အထိ Read လုပ်သွားနိုင်မှာ ဖြစ်ပါတယ်။


PrintWriter


Java Program ထဲကနေ Character တွေကို String အနေနဲ့ Write လုပ်လိုတဲ့အခါမှာ PrintWriter ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ PrintWriter ကို အသုံးပြုပြီး String တွေလို ဒီအတိုင်း Write လုပ်နိုင်သလို၊ Format ချပြီးလဲ Write လုပ်နိုင်ပါတယ်။ ထို့အပြင် Locale အလိုက်သတ်မှတ်ပြီးလဲ Format လုပ်နိုင်မှာ ဖြစ်ပါတယ်။ PrintWriter Object ကို တည်ဆောက်နိုင်တဲ့ Constructor တွေကတော့ အောက်ပါ အတိုင်းဖြစ်ကြပါတယ်။

Constructor Description
PrintWriter(File file) Output File ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(File file, String csn) Output File နဲ့ Character Set ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(OutputStream out) OutputStream ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(OutputStream out, boolean autoFlush) OutputStream နဲ့ Auto Flush Mode ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။
PrintWriter(String fileName) File Name ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(String fileName, String csn) File Name နဲ့ Character Set ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(Writer out) Writer ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(Writer out, boolean autoFlush) Writer နဲ့ Auto Flush Mode ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။

package com.jdc.io.stream.ep3;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class LineWriter {

    private static final String [] ARRAY = {
            "Hello Java",
            "Hello Java IO",
            "Learn java Programming."
    };
    
    public static void main(String[] args) {
        
        try(PrintWriter out = new PrintWriter(new FileWriter("line.txt"))) {
            
            for (String line : ARRAY) {
                out.println(line);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

String တွေကို Write လုပ်ဖို့အတွက် print(String str) ဒါမှမဟုတ် write(String str) ကို အသုံးပြုနိုင်ပါတယ်။ ဒါအပြင် Line တွေကို Write လုပ်ဖို့အတွက် println(String str) ကို အသုံးပြုနိုင်ပါတယ်။ Format လုပ်ချင်ရင်တော့ printf(String format, String … param) ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။


Data Streams

Primitive Data နဲ့ String တန်ဖိုး တွေကို Read / Write လုပ်ချင်တဲ့အခါ DataInputStream နဲ့  DataOutputStream တို့ကို အသုံးပြုနိုင်ပါတယ်။

Constructor Description
DataOutputStream(OutputStream out) OutputStream Object တစ်ခုကို အသုံးပြုပြီး DataOutputStream ကို တည်ဆောက်ရန် ပြင်ဆင်ထားတဲ့ Constructor ဖြစ်ပါတယ်။
DataInputStream(InputStream in) InputStream Object တစ်ခုကို အသုံးပြုပြီး DataInputStream ကို တည်ဆောက်ရန် ပြင်ဆင်ထားတဲ့ Constructor ဖြစ်ပါတယ်။

အသုံးပြုလိုတဲ့ Data Type အလိုက် Method တွေကိုလဲ ခွဲခြားပြင်ဆင်ထားပါတယ်။

Data Type DataInputStream DataOutputStream
boolean readBoolean() writeBoolean(boolean v)
char readChar() writeChar(int v)
byte readByte() writeByte(int v)
short readShort() writeShort(int v)
int readInt() writeInt(int v)
long readLong() writeLong(long v)
float readFloat() writeFloat(float v)
double readDouble() writeDouble(doble v)
String readUTF() writeUTF(String str)

မိမိအသုံးပြုလိုတဲ့  Data Type အလိုက် သက်ဆိုင်ရာ Method ကို အသုံးပြုပြီး ရေးသားရမှာ ဖြစ်ပါတယ်။


Write Data

package com.jdc.io.stream.ep4;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataOutput {
    
    private static final String name = "Aung Aung";
    private static final int age = 20;
    private static final boolean isMan = true;
    
    public static void main(String[] args) {
        
        System.out.println("Starting Output");

        try(DataOutputStream out = new DataOutputStream(new FileOutputStream("data.dat"))) {
            
            out.writeUTF(name);
            out.writeInt(age);
            out.writeBoolean(isMan);
            
            System.out.println("End Output");
        } catch (IOException e) {
            System.out.println("Output Error");
        }
        
    }

}

အထက်ပါနမူနာမှာတော့ name variable ဟာ String ဖြစ်တဲ့အတွက် writeUTF ကို အသုံးပြုပြီး၊ age ဟာ int ဖြစ်တဲ့အတွက် writeInt ကို အသုံးပြုပါတယ်။ တဖန် isMan ဆိုတဲ့ Variable ဟာ boolean type ဖြစ်တဲ့အတွက် writeBoolean ကို အသုံးပြရမှာ ဖြစ်ပါတယ်။


Reading Data

package com.jdc.io.stream.ep4;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class DataInput {

    public static void main(String[] args) {
        
        try(DataInputStream in = new DataInputStream(
                new FileInputStream("data.dat"))) {
            
            System.out.println("Name : " + in.readUTF());
            System.out.println("Age  : " + in.readInt());
            System.out.println("Male : " + in.readBoolean());
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

အထက်ပါ နမူနာကတော့ DataOutput ဖြင့် Write လုပ်ထားတဲ့ data.dat file ထဲက Data တွေကို ပြန်ပြီး Read လုပ်နေတာဖြစ်ပါတယ်။ String Data တွေကို readUTF ကိုအသုံးပြုပြီး၊ int ကိုတော့ readInt ကို အသုံးပြုပါတယ်။ တဖန် boolean ကိုတော့ readBoolean method ကို အသုံးပြုပါတယ်။


Serialization

အရှေ့တွင်ဖေါ်ပြခဲ့သလို Java ဘာသာရပ်တွင် Byte, Character, Primitive Data များနှင့် String များကို Read / Write လုပ်နိုင်တဲ့အပြင် Object တွေကိုလဲ Object အတိုင်း Read / Write လုပ်နိုင်ပါတယ်။

Java ဘာသာရပ်မှာ JVM Memory အပေါ်မှာရှိတဲ့ Object တွေကို အခြား တစ်နေနေရာကို ပို့ပေးလိုက်ခြင်းကို Serialize လုပ်တယ်လို့ခေါ်ပါတယ်။ တဖန် တစ်ခြားတစ်နေနေရာကနေလာတဲ့ Serialized လုပ်ထားတဲ့ Data တွေကနေ JVM Memory အပေါ်ကို ပြန်ပြီး Object အဖြစ်ပြန်ပြောင်းတာကိုတော့ Deserialize လုပ်တယ်လို့ခေါ်ပါတယ်။ Deseiralize လုပ်တယ်ဆိုတာကလဲ Serialize လုပ်ထားတဲ့ Data များကိုသာ ပြုလုပ်နိုင်မှာ ဖြစ်ပါတယ်။

နမူနာအားဖြင့် Program ထဲမှာ သုံးနေတဲ့ Java Object တွေကို File တစ်ခုခုမှာ သွားသိမ်းတာတို့၊ Internet ကိုဖြတ်ပြီး တစ်ခြားတစ်နေနေရာကိုပို့ပေးတာတို့ဟာ Serialize လုပ်တာဖြစ်ကြပါတယ်။ Server အပေါ်မှာရှိတဲ့ Object တွေကို Session ပေါ်မှာ သုံးနေတယ်ဆိုတာကလဲ Serialize လုပ်နေတာပဲ ဖြစ်ပါတယ်။

ဒါဖြင့် ဘယ်လို Object တွေကို Serialize လုပ်လို့ရတာလဲ။ Primitive Data Type တွေ၊ Serializable Interface ကို Implement လုပ်ထားတဲ့ Object တွေနဲ့ Serializable Object တွေရဲ့ Collection တွေ ဆိုရင် Serialize လုပ်လို့ရမှာ ဖြစ်ပါတယ်။

Object တစ်ခုကို Serialize လုပ်တဲ့အခါမှာ Object ရဲ့ State တွေဖြစ်ကြတဲ့ Instance Variable တွေကိုသာ Serialize လုပ်သွားမှာ ဖြစ်ပါတယ်။ ဒါ့ကြောင့် Serialize လုပ်မည့် Object ရဲ့ Instance Variable တွေဟာလဲ Serializable ဖြစ်ဖို့လိုအပ်ပါတယ်။ တကယ်လို့ Serialize မလုပ်ချင်တဲ့ Instance Variable တွေဆိုရင် transient modifier ကို ရေးသားပြီး ဖေါ်ပြနိုင်ပါတယ်။ Instance Variable တွေရှေ့မှာ transient ကို ရေးသားထားရင် အဲ့ဒီ Field ကို Serialize လုပ်မှာ မဟုတ်တော့ပါဘူး။
package com.jdc.io.stream.ep5;

import java.io.Serializable;

public class Employee implements Serializable{

    private static final long serialVersionUID = 1L;

    private int id;
    private String name;
    private String phone;
  
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
}


Serial Version UID

Serializable Object တစ်ခုကို Serialize လုပ်ပြီး ပြန်ပြီး Deserialize လုပ်တဲ့အခါ Serial Version UID ကို အသုံးပြုပြီး Class ရဲ့ Version မှန်မမှန်ကို ပြန်ပြီး စစ်ဆေးလေ့ရှိပါတယ်။ Serial Version UID ကို ရေးသားရာမှာ static final long serialVersionUID ဆိုတဲ့ပုံစံနဲ့ ရေးသားပေးရပါတယ်။ Access Modifier ကိုတော့ နှစ်သက်ရာ ရေးသားအသုံးပြုနိုင်ပါတယ်။

Serialize လုပ်တဲ့အခါမှာ Serial Version UID ဟာ Static Variable ဖြစ်ပေမဲ့ ခြွင်းချက်အနေနဲ့ Serialize အလုပ်ခံရမှာ ဖြစ်ပါတယ်။ Deserialize လုပ်တဲ့အခါမှာ လက်ရှိ Class နဲ့ Deserialize လုပ်မည့် Object ရဲ့ Serial Version UID ကို တိုက်စစ်ပြီး မှန်ကန်မှသာ Serialize လုပ်ပေးမှာ ဖြစ်ပါတယ်။ တကယ်လို့ Version နှစ်ခုမတူညီခဲ့ပါက InvalidClassException ကို ဖြစ်ပေါ်စေမှာ ဖြစ်ပါတယ်။

တကယ်လို့ Serializable Class တစ်ခုမှာ Serial Version UID ကို မရေးထားဖူးဆိုရင် Serialize လုပ်တဲ့အခါမှာ JVM ကနေ နှစ်သက်ရာ ID တစ်ခုကို Generate လုပ်ပေးမှာ ဖြစ်ပါတယ်။

ဒါပေမဲ့ Serial Version UID Calculation ဟာ Compiler Implementation အပေါ်မူတည်ပြီး ပြောင်းလဲတတ်တဲ့အတွက် Serial Version UID ကို Class အတွင်းမှာ မဖြစ်မနေရေးသားသင့်ပါတယ်။


Writing Objects (Serialization)

Java Program ထဲကနေ Memory အပေါ်မှာရှိတဲ့ Serializable Object တွေနဲ့ Serializable Object ရဲ့ Collection တွေကို Serialize လုပ်လိုတဲ့အခါမှာ ObjectOutputStream ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ ObjectOutputStream ကို အသုံးပြုပြီး Primitive Data တွေနဲ့ Serializable Object Graphs တွေကို Serialize လုပ်ပေးနိုင်မှာ ဖြစ်ပါတယ်။

Object တွေကို Serialize လုပ်တဲ့နေရာမှာလဲ File တွေမှာလဲ Serialize လုပ်နိုင်သလို Network ကို အသုံးပြုတဲ့ Socket Stream တွေနဲ့လဲ တွဲဖက် အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ ObjectOutputStream ရဲ့ Constructor တွေကတော့ အောက်ပါအတိုင်း ဖြစ်ကြပါတယ်။

Constructor Description
ObjectOutputStream() ObjectOutputStream ရဲ့ Sub Class တွေအတွက် ပြင်ဆင်ထားပေးတဲ့ Constructor ဖြစ်ပါတယ်။
ObjectOutputStream(OutputStream out) OutputStream Object တစ်ခုကို အသုံးပြုပြီး ObjectOuputStream ကို တည်ဆောက်ရန် ပြင်ဆင်ထားတဲ့ Constructor ဖြစ်ပါတယ်။

package com.jdc.io.stream.ep5;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectWriteTest {

    public static void main(String[] args) {
        Employee e = new Employee();
        e.setId(1);
        e.setName("Aung Aung");
        e.setPhone("09788986677");
        
        try(ObjectOutputStream out = new ObjectOutputStream(
                new FileOutputStream("employee.obj"))) {
            out.writeObject(e);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}
အထက်ပါနမူနာအတိုင်း JVM Memory အပေါ်မှာရှိတဲ့ Object တွေကို Serialize လုပ်လိုပါက writeObject(Object obj) method ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။


Reading Objects (Deserialization)

ObjectOutputStream ကို အသုံးပြုပြီး Serialize လုပ်ထားတဲ့ Primitive Data တွေနဲ့ Object တွေကို Deserialize လုပ်လိုတဲ့အခါ ObjectInputStream ကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။

File ထဲမှာရှိတဲ့ Data တွေကို Deserialize လုပ်တဲ့အခါမျိုးမှာ ObjectInputStream ဟာ FileInputStream ကို အသုံးပြုပါတယ်။ ဒါကြောင့် File ထဲက Data တွေကို Read လုပ်လိုတဲ့အခါမျိုးမှာ InputStream Parameter နေရာမှာ FileInputStream Object ကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။

တဖန် Remote System တစ်ခုကနေ Data တွေကို ရယူတဲ့အခါမျိုးမှာတော့ Socket Streams ကို အသုံးပြုပြီး Data တွေကို Deserialize လုပ်နိုင်ပါတယ်။

Constructor Description
ObjectInputStream() ObjectInputStream ရဲ့ Sub Class တွေအတွက် ပြင်ဆင်ထားပေးတဲ့ Constructor ဖြစ်ပါတယ်။
ObjectInputStream(InputStream in) OutputStream Object တစ်ခုကို အသုံးပြုပြီး ObjectOuputStream ကို တည်ဆောက်ရန် ပြင်ဆင်ထားတဲ့ Constructor ဖြစ်ပါတယ်။

package com.jdc.io.stream.ep5;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ObjectReadTest {

    public static void main(String[] args) {
        
        try(ObjectInputStream in = new ObjectInputStream(
                new FileInputStream("employee.obj"))) {
            
            Employee e = (Employee) in.readObject();
            
            System.out.println(e.getName());
            
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

ယခင် နမူနာဖြင့် Serialize လုပ်ထားတဲ့ Employee Object ကို Deserialize လုပ်လိုတဲ့အခါ အထက်ပါအတိုင်း ObjectInputStream ကို အသုံးပြုပြီး ရေးသားနိုင်ပါတယ်။ အထက်ပါအတိုင်း in.readObject() method ရဲ့ Return Type ဟာ Object ဖြစ်နေတဲ့အတွက် Employee အဖြစ်ပြန်ပြီး Cast လုပ်ပေးဖို့လိုအပ်ပါတယ်။

ဆက်ပါဦးမယ်
မင်းလွင်

January 11, 2017

A Glance to Java 9

Java SE 9 အကြောင်း အတော်လေးပြောလာကြပြီ။ ဘာပဲပြောပြော ၂၀၁၇ နှစ်ထဲမှာပဲ Release လုပ်ဖြစ်မှာတော့ သေချာတယ်။ Java SE 9 ရဲ့ အဓိက Feature လို့ပြောရရင်တော့ Project Jigsaw လို့ပဲ ပြောရမှာ ဖြစ်ပေမဲ့ ပြောင်းလဲမှု့တွေကတော့ အတော်လေးကိုများပါတယ်။

စမ်းသပ်မယ်ဆိုရင်တော့ JDC 9 Early Release ကို Download လုပ်လို့ရနေပါပြီ။

JDK 9 Download
https://jdk9.java.net/download/

အဓိကအားဖြင့် Language, Tools နဲ့ Library Features တွေမှာ ပြောင်းလဲမှုတွေကို တွေ့ရမှာ ဖြစ်ပါတယ်။ JDK 9 ရဲ့ Early Release လဲ Download လုပ်လို့ရပြီဖြစ်တဲ့အတွက် ဒီတစ်ခေါက်တော့ Java SE 9 မှာ ဘာတွေပြောင်းသွားမလဲဆိုတာကို လေ့လာရင်းမိတ်ဆက်သွားပါမယ်။

JEP ဆိုတာက Java Enhancement Proposal ရဲ့ အတိုကောက် အခေါ်အဝါ်ဖြစ်ပါတယ်။ Java နဲ့ ပတ်သက်တဲ့ ပြုပြင်ပြောင်းလဲမှူ့ဆိုင်ရာ အကြံပြုလွှာတွေဖြစ်ပါတယ်။ Java SE 9 မှာ ပါဝင်တဲ့ JEP တွေကတော့ အားလုံးပေါင်း ၈၈ခုရှိပါတယ်။

102: Process API Updates
110: HTTP 2 Client
143: Improve Contended Locking
158: Unified JVM Logging
165: Compiler Control
193: Variable Handles
197: Segmented Code Cache
199: Smart Java Compilation, Phase Two
200: The Modular JDK
201: Modular Source Code
211: Elide Deprecation Warnings on Import Statements
212: Resolve Lint and Doclint Warnings
213: Milling Project Coin
214: Remove GC Combinations Deprecated in JDK 8
215: Tiered Attribution for javac
216: Process Import Statements Correctly
217: Annotations Pipeline 2.0
219: Datagram Transport Layer Security (DTLS)
220: Modular Run-Time Images
221: Simplified Doclet API
222: jshell: The Java Shell (Read-Eval-Print Loop)
223: New Version-String Scheme
224: HTML5 Javadoc
225: Javadoc Search
226: UTF-8 Property Files
227: Unicode 7.0
228: Add More Diagnostic Commands
229: Create PKCS12 Keystores by Default
231: Remove Launch-Time JRE Version Selection
232: Improve Secure Application Performance
233: Generate Run-Time Compiler Tests Automatically
235: Test Class-File Attributes Generated by javac
236: Parser API for Nashorn
237: Linux/AArch64 Port
238: Multi-Release JAR Files
240: Remove the JVM TI hprof Agent
241: Remove the jhat Tool
243: Java-Level JVM Compiler Interface
244: TLS Application-Layer Protocol Negotiation Extension
245: Validate JVM Command-Line Flag Arguments
246: Leverage CPU Instructions for GHASH and RSA
247: Compile for Older Platform Versions
248: Make G1 the Default Garbage Collector
249: OCSP Stapling for TLS
250: Store Interned Strings in CDS Archives
251: Multi-Resolution Images
252: Use CLDR Locale Data by Default
253: Prepare JavaFX UI Controls & CSS APIs for Modularization
254: Compact Strings
255: Merge Selected Xerces 2.11.0 Updates into JAXP
256: BeanInfo Annotations
257: Update JavaFX/Media to Newer Version of GStreamer
258: HarfBuzz Font-Layout Engine
259: Stack-Walking API
260: Encapsulate Most Internal APIs
261: Module System
262: TIFF Image I/O
263: HiDPI Graphics on Windows and Linux
264: Platform Logging API and Service
265: Marlin Graphics Renderer
266: More Concurrency Updates
267: Unicode 8.0
268: XML Catalogs
269: Convenience Factory Methods for Collections
270: Reserved Stack Areas for Critical Sections
271: Unified GC Logging
272: Platform-Specific Desktop Features
273: DRBG-Based SecureRandom Implementations
274: Enhanced Method Handles
275: Modular Java Application Packaging
276: Dynamic Linking of Language-Defined Object Models
277: Enhanced Deprecation
278: Additional Tests for Humongous Objects in G1
279: Improve Test-Failure Troubleshooting
280: Indify String Concatenation
281: HotSpot C++ Unit-Test Framework
282: jlink: The Java Linker
283: Enable GTK 3 on Linux
284: New HotSpot Build System
285: Spin-Wait Hints
287: SHA-3 Hash Algorithms
288: Disable SHA-1 Certificates
289: Deprecate the Applet API
290: Filter Incoming Serialization Data
292: Implement Selected ECMAScript 6 Features in Nashorn
294: Linux/s390x Port
295: Ahead-of-Time Compilation
297: Unified arm32/arm64 Port

ခေါင်းစဉ်တွေကြီး ဖတ်ကြည့်ရင်တောင် Language ပိုင်းဆိုင်ရာ ပြောင်းလဲမှူ့ထက် Platform ဘက်မှာ ပိုပြီး အားသာတာကို တွေ့ရပါမယ်။ Keywords ကတော့ Modularity ပါပဲ။ jshell ကတော့ Java ကို သင်ကြားရာမှာ Statement တွေကို အလွယ်တကူသင်ကြားနိုင်မှာ ဖြစ်ပါတယ်။

နောက်တစ်ခုစိတ်ဝင်စားမိတာက HTTP2 Client ဟာလဲ​စိတ်ဝင်စားစရာ ဖြစ်ပါတယ်။ Tools နဲ့ JVM အစရှိတဲ့ Platform ပိုင်းဆိုင်ရာ ပြောင်းလဲမှု့တွေကများတာကို တွေ့ရပါတယ်။

ဆက်ပြီးလေ့လာသွားပါဦးမယ်။
လေးစားစွာဖြင့်
မင်းလွင်

January 5, 2017

Static Vs Instance

Q - Static နဲ့ Instance ကို အလွယ် ဘယ်လိုခွဲမလဲ


A - Java ကို လေ့လာကာစလူတွေ အမြဲတမ်းလိုလို ကြုံတွေ့တတ်တဲ့ မေးခွန်းတစ်ခုဖြစ်ပါတယ်။ ဒီမေးခွန်းကို ခွဲစိတ်ကြည့်မယ်ဆိုရင် အောက်ပါ မေးခွန်းလေးတွေ ထပ်ပြီးထွက်လာနိုင်ပါတယ်။

  1. Static ဆိုတဲ အဓိပ္ပါယ်နဲ့ Instance ဆိုတဲ့အဓိပ္ပါယ်
  2. ဘယ်လိုနေရာတွေမှာ Static နဲ့ Instance တို့ကိုခွဲပြီးရေးနိုင်လဲ
  3. ဘယ်လိုရေးရင် Static ဖြစ်ပြီး ဘယ်လိုရေးရင် Instance ဖြစ်သွားမလဲ
  4. Static နဲ့ Instance တွေကို ဘယ်လို Access လုပ်ကြမလဲ
  5. Static နဲ Instance တွေရဲ့ ထူးခြားချက်တွေကဘာတွေလဲ
  6. ဘယ်လိုနေရာမျိုးတွေမှာ Static ကို သုံးပြီး ဘယ်လိုနေရာမျိုးတွေမှာ Instance တွေကို သုံးရမလဲ 

Static ဆိုတဲ့အဓိပ္ပါယ် နဲ့ Instance ဆိုတဲ့အဓိပ္ပါယ်

တိုက်ရိုက်ပြန်ရင်တော့ Static ကို Dynamic မဟုတ်တဲ့အတွက် ကိန်းသေတွေလို့ပြောနိုင်မယ်။ ဒါပေမဲ့ ဒီနေရာမှာ ကတော့ Class နဲ့ ပတ်သက်တဲ့အရာတွေလို့ဆိုလိုနိုင်ပါတယ်။

ဒါဆိုရင် Class ကို ဘာလို့ရေးရတာလဲ။
  1. Object ဆောက်ဖို့၊ Object ရဲ့ State နဲ့ Behavior ကို သတ်မှတ်ပေးဖို့
  2. Utility အနေနဲ့ Function တွေကို ရေးသား အသုံးဖို့
Static ဆိုတာက Object အတွက်မဟုတ်ပဲ ဒုတိယ ရည်ရွယ်ချက်တွေကို ရေးသားတဲ့အခါမှာ Class ထဲမှာ ထားပြီး သုံးနိုင်တဲ့ Member တွေကို ဖေါ်ပြတဲ့နေရာမှာ အသုံးပြုပါတယ်။

Object တွေကို Instance တွေလို့လဲခေါ်လေ့ရှိပါတယ်။ ဒါ့ကြောင့် Instance ဆိုတာက Object နဲ့ဆိုင်တဲ့အရာတွေကို ဖေါ်ပြတဲ့အခါတွေမှာ သုံးပါတယ်။

ဒါ့ကြောင့် Instance Variable ဆိုရင် Object တွေနဲ့ ဆိုင်တဲ့ Variable တွေ ဖြစ်ပြီး Instance Method ဆိုရင် Object တွေမှာ သုံးလို့ရတဲ့ Method တွေလို့ မှတ်နိုင်ပါတယ်။

တနည်း Static Variable ဆိုရင် Class နဲ့ ဆိုင်တဲ့ Variable ဖြစ်ပြီး Object ဆောက်တဲ့အခါမှာ အဲ့ဒီအချက်အလက်တွေကို Object တစ်ခု ရဲ့ State အနေနဲ့ အသုံးပြုမှာ မဟုတ်ပါဘူး။ ပြီးတော့ Static Method တွေကလဲ Class ရဲ့ Utility Method တွေဖြစ်ကြပါတယ်။ ဒါ့ကြောင့် Class ကနေ အသုံးပြုရမှာ ဖြစ်ပါတယ်။

ဒီလိုမှတ်ရင်လဲရနိုင်တယ်။ Instance Member တွေရဲ့ Owner ဟာ Object ဖြစ်ပြီး Static Member တွေရဲ့ Owner ဟာ Class ဖြစ်ပါမယ်။


ဘယ်လိုနေရာတွေမှာ Static နဲ့ Instance တို့ကိုခွဲပြီးရေးနိုင်လဲ

Class ရဲ့ Member တွေမှာ Static နဲ့ Instance တို့ကို ခွဲပြီးရေးနိုင်တယ်။

ဒါဆို Class ရဲ့ Member တွေက ဘာတွေလဲ ဆိုတဲ့ မေးခွန်းက ပေါ်လာပြန်မယ်။ Class Body ထဲမှာ ရေးလို့ရတဲ့ အရာတွေဟာ အဲ့ဒီ Class ရဲ့ Member တွေ ဖြစ်ကြတယ်။ အဲ့ဒီနေရာမှာ Class ထဲမှာ ဘာတွေရေးလို့ရလဲ ဆိုတာကို မသိရင် Class Member တွေ ဘာတွေရှိတယ်ဆိုတာကို သိမှာ မဟုတ်ပြန်ဘူး။

Class ထဲမှာ ရေးလို့ရတာကတော့ အောက်ပါ အရာတွေဖြစ်ပါတယ်။
Members Static Instance Description
Variable Yes Yes
Methods Yes Yes
Constructors No Yes Object ဆောက်တဲ့အခါမှာသာ သုံးတဲ့အတွက် Static Constructor ဆိုတာမရှိပါဘူး
Nested Class Yes Yes
Nested Interface Yes Yes
Nested Enum Yes No Enum တွေဟာ Default Static Entity တွေ ဖြစ်တဲ့အတွက် Instance Enum ဆိုတာ မရှိပါဘူး။ အဲ့ဒီအတွက် Static Keyword ကို မရေးလဲ Static တွေ သာဖြစ်ကြပါတယ်

Nested Class, Interface နဲ့ Enum တွေကိုတော့ နောက်အခန်းတွေကျမှ ဆက်ပြီး ဖေါ်ပြသွားပါမယ်။ အခုတော့ ဘာတွေလဲလို့ မမေးပါနဲ့ ဦး။


ဘယ်လိုရေးရင် Static ဖြစ်ပြီး ဘယ်လိုရေးရင် Instance ဖြစ်သွားမလဲ

အလွယ်ပြောရမယ်ဆိုရင် Static ကော Instance ကော သတ်မှတ်နိုင်တဲ့ Member တွေမှာ static လို့ရေးထားရင် Static Member တွေဖြစ်ပြီး ဘာမှ မရေးထားရင် Instance Member တွေ ဖြစ်ကြတယ်။

တကယ်တော့ Class ကို ရေးရတဲ့ အဓိက ရည်ရွယ်ချက်ဟာ Object မှာပါတဲ့ State နဲ့ Behavior ကို Define လုပ်ပေးဖို့ဖြစ်တယ်။ အဲ့ဒီအတွက် Default အတိုင်းဆိုလို့ကတော့ Object အတွက်ကြီးပဲ ဖြစ်တယ်။ Object ရဲ့ State တွေအတွက် Variable တွေနဲ့ သတ်မှတ်ပေးတယ်။ အဲ့ဒီတော့ Default အတိုင်း ဆိုလို့ကတော့ Variable တွေဟာ Object ရဲ့ State အတွက် ဖြစ်တဲ့အတွက် Instance Variable တွေဖြစ်မှာပဲ။

Method တွေကလဲ Object တွေရဲ့ Behavior ကို သတ်မှတ်ဖို့ရေးတယ်။ အဲ့ဒီအတွက် Default အတိုင်းဆိုလို့ကတော့ Instance Method တွေ ဖြစ်နေမှာပါပဲ။

အဲ့ဒီ Default တန်ဖိုးတွေကို ပြင်ချင်တော့မှ၊ ဆိုလိုတာက Variable တွေ Method တွေဟာ Object အတွက်မဟုတ်ဘူး၊ Class ထဲမှာပဲ သုံးမှာပါလို့ ဖေါ်ပြနိုင်အောင် Static Modifier ကို သုံးပြီး ရေးသားရမှာ ဖြစ်ပါတယ်။
public class Person {

    // static variable
    static int count;

    // instance variable
    String name;

    // instance method
    public void showName() {
        System.out.println(name);
    }

    // static method
    public static void showStudentCount() {
        System.out.println(count);
    }
}
ဒါ့ကြောင့် Variable တွေ Method တွေရှေ့မှာ ဘာမှမပါရင် Instance တွေ ဖြစ်ကြပြီး static ပါရင် Static တွေဖြစ်တယ်လို့ ခွဲပြီး မှတ်နိုင်မှာ ဖြစ်ပါတယ်။


Static နဲ့ Instance တွေကို ဘယ်လို Access လုပ်ကြမလဲ

ဒီနေရာမှာ အရေးကြီးတာက Owner ဟာ ဘယ်ဟာလဲဆိုတာကို သိဖို့လိုအပ်ပါတယ်။ Static Members တွေရဲ့ Owner ဟာ Class ဖြစ်ပြီး Instance Member တွေရဲ့ Owner ဟာ Object ဖြစ်ပါတယ်။ Members တွေကို Access လုပ်တဲ့ အခါမှာ Class တစ်ခုထဲကနေ Access လုပ်တာနဲ့ အဲ့ဒီ Class ရဲ့ အပြင်ကနေ Access လုပ်တာဆိုပြီး ၂ မျိုးရှိနိုင်ပါလိမ့်မယ်။

Class တစ်ခုထဲကနေ Access လုပ်မယ်ဆိုရင်တော့ Owner ကို မရေးပဲနေလို့ရပါတယ်။ ဒါ့ကြောင့် Variable ပဲ ဖြစ်ဖြစ် Method ပဲဖြစ်ဖြစ် အဲ့ဒီအတိုင်းကို Access လုပ်နိုင်လိမ့်မယ်။ (ဒီနေရာမှာ Variable Hiding တို့ Super Class ထဲက Member တွေကိုသုံးချင်ရင်ကောတို့၊ ခေါ်လို့ရတာမရတာတို့ ရှိပါသေးတယ်။ ဒါတွေကိုတော့ နောက်အခန်းတွေကြမှ ဆက်ပြောကြရအောင်။)

အဲ့ဒီ Class ရဲ့ အပြင်ကနေ Access လုပ်မယ်ဆိုရင်တော့ Owner ကနေ တဆင့် Access လုပ်ရမှာ ဖြစ်ပါတယ်။ [Owner].[Member] ဆိုပြီး Access လုပ်ရမှာ ဖြစ်တယ်။ Variable တွေဆိုရင်တော့ owner.variable ဆိုပြီး ရေးရပါမယ်။ Method တွေဆိုရင်တော့ owner.method() ဆိုပြီးရေးရမှာပါ။ Method တွေကို Access လုပ်တဲ့အခါမှာတော့ Method Signature အတိုင်း Parameter တွေကို ရေးသားပေးရမှာ ဖြစ်ပါတယ်။
public class PersonTest {

    public static void main(String [] args) {

        // static variable
        Person.count = 10;

        // static method
        Person.showStudentCount();
    }
}

Person Class ထဲမှာ ပါတဲ့ count ဟာ Static Variable ဖြစ်တဲ့အတွက် Owner ဟာ Class ဖြစ်တဲ့အတွက် Class ကနေတဆင့် Access လုပ်ရမှာပါ။ ဒါ့ကြောင့် Person.count ဆိုပြီး ရေးရမှာ ဖြစ်ပါတယ်။ တဖန် showStudentCount() ဆိုတဲ့ Method ဟာလဲ Static Method ဖြစ်တဲ့အတွက် Person.showStudentCount() ဆိုပြီး Person Class ကနေတဆင့် ရေးသားရမှာ ဖြစ်ပါတယ်။
public class PersonTest {

    public static void main(String [] args) {

     Person p = new Person();

        // static variable
        p.name = "Thidar";

        // static method
        p.showName();
    }
}

Instance Member တွေကို Access လုပ်ချင်ပြီ ဆိုရင်တော့ Owner ဟာ Object ဖြစ်တဲ့အတွက် Object တွေကနေမှ ဆက်သွယ်လို့ရမှာပါ။ ဒါ့ကြောင် Person အမျိုးအစား ဖြစ်တဲ့ p variable နေရာမှာ new Person() ဆိုပြီး Object ဆောက်ပြီး သူ့ကို Reference အနေနဲ့ ပေးနေပါတယ်။

ပြီးတော့မှ instance variable ဖြစ်တဲ့ name ကို p.name ဆိုပြီး Access လုပ်ရမှာ ဖြစ်ပါတယ်။ အလားတူပဲ instance method ဖြစ်တဲ့ showName ကို Access လုပ်တဲ့အခါမှာလဲ onwer object ဖြစ်တဲ့ p ကနေတဆင့် p.showName() ဆိုပြီး Access လုပ်နေတာဖြစ်ပါတယ်။


Static နဲ Instance တွေရဲ့ ထူးခြားချက်တွေကဘာတွေလဲ

Static နဲ့ Instance တို့ရဲ့ ထူးခြားချက်တွေလို့ပြောလာရင် Class နဲ့ Object တို့ရဲ့ ထူးခြားချက်တွေလို ပြောလာတာနဲ့ အတူတူဖြစ်ပါလိမ့်မယ်။

အရင်ဆုံး Class ရဲ့ ထူးခြားချက်ဆိုတာကို ကြည့်အောင်။ Class တွေဟာ JVM တစ်ခုလုံးမှာ တစ်ခုထဲသာရှိပါမယ်။ Runtime ကနေ အလုပ်လုပ်နေရင်းနဲ့ Class တစ်ခုကို Declare လုပ်နေတာကို တွေ့ရင် JVM ရဲ့ Memory ပေါ်မှာ ရှိလားဆိုတာကို ကြည့်မယ်။ မရှိဘူးဆိုရင် Class Path ထဲကနေ အဲ့ဒီ Class ကို Memory ပေါ်ကို Load လုပ်ပါမယ်။ တကယ်လို့ ရှိပြီးသားဆိုရင်တော့ အဲ့ဒီ Class ကိုပဲ အသုံးပြုပါလိမ့်မယ်။ ဒါ့ကြောင့် Class တွေဟာ JVM ရဲ့ Memory ပေါ်မှာ တစ်ခုထဲသာ ရှိနေမှာ ဖြစ်ပါတယ်။

Object တွေကကော။ သူတို့တွေကတော့ new keyword နဲ Constructor ကို ခေါ်လိုက်တိုင်း Object အသစ်တစ်ခုကို တည်ဆောက်ပါတယ်။ အဲ့ဒီ Object တွေက တစ်ခုနဲ့ တစ်ခု ပတ်သက်မှူ့မရှိပါဘူး။ ကျွန်တော်တို့ Class တစ်ခုကနေ Object objectA နဲ့ objectB ကို တည်ဆောက်ခဲ့တယ်ဆိုပါစို့။ objectA မှာပါတဲ့ State တွေဟာ objectA နဲ့သာ ဆိုင်ပြီး objectB နဲ့ ပတ်သက်မှာ မဟုတ်ပါဘူး။

ဆက်ပြီး Object ကို Instantiate လုပ်တယ်ဆိုတာ JVM ပေါ်မှာ လက်တွေ့ ဘယ်လို ဖြစ်သွားလဲ ဆိုတဲ့ ဘက်ကနေ ကြည့်ကြရအောင်။ new keyword ကို သုံးပြီး Object ဆောက်ရင် JVM ပေါ်မှာ Class ကနေ Object နဲ့ ဆိုင်တဲ့ Instance Variable တွေကို Copy ကူးသွားပြီး Heap Memory ပေါ်မှာ Object ကို သွားဆောက်ပါတယ်။ Copy ကူးသွားတဲ့နေရာမှာ Static Variable တွေမပါပါဘူး။ Class နဲ့သာ ပတ်သက်တဲ့အရာတွေ ဖြစ်တဲ့ အတွက် Class ထဲမှာပဲ ချန်ထားခဲ့ပါတယ်။


ထူးခြားချက် တွေကို Variable တွေ ဘက်ကကြည့်ကြရအောင်။

Static Variable တွေဟာ Class ထဲမှာပဲ ရှိနေမှာဖြစ်ပြီး၊ Class ဟာလဲ JVM တစ်ခုလုံးမှာ တစ်ခုထဲသာရှိနေမှာ ဖြစ်တဲ့အတွက် သူတို့တွေဟာလဲ JVM ထဲမှာ တစ်ခုထဲသာ ရှိနေမှာပဲဖြစ်တယ်။ ဘယ်နေရာကပဲ Static Variable ကို Access လုပ်လုပ် တစ်ခုထဲသော အဲ့ဒီ Variable ရဲ့ တန်ဖိုးကိုပဲ ရရှိမှာ ဖြစ်ပါတယ်။

Instance Variable တွေကတော့ Object ဆောက်လိုက်တိုင်း Class ကနေ Copy ကူးသွားတာဖြစ်တဲ့အတွက် အဲ့ဒီ Object တစ်ခုချင်းစီနဲ့သာ ပတ်သက်ပါတယ်။ ဒါ့ကြောင့် Object တစ်ခုရဲ့ Instance Variable ကို တန်ဖိုးပြောင်းရင် အဲ့ဒီ Object ကပိုင်တဲ့ Instance Variable ရဲ့တန်ဖိုးသာ ပြောင်းသွားမှာ ဖြစ်တယ်။ တစ်ခြား Object တွေရဲ့ တန်ဖိုးဟာ ပြောင်းသွားမှာ မဟုတ်ပါဘူး။


Method တွေရဲ့ ထူးခြားချက်တွေကကောဘယ်လိုလဲ။

Static Method တွေဟာ Class တွေနဲ့သာဆိုင်တယ်။ အဲ့ဒါကြောင့် Static Method တွေကို Class တွေကနေတဆင့် Invoke လုပ်ကြမှာ ဖြစ်တယ်။ ဒီလို Static Method တွေကို Invoke လုပ်တဲ့ အချိန်မှာ Object တွေကို မဆောက်ရသေးတာလဲ ဖြစ်နိုင်တယ်။ ဆောက်ပြီးပြန်ရင်လဲ new ခေါ်တိုင်း Object ဆိုတာ ဆောက်လို့ရနေတဲ့ အတွက် Static Method ထဲကနေ Instance Variable ကို Access လုပ်ပါ၊ ဒါမှမဟုတ် Instance Method ကို Invoke လုပ်ပါလို့ ခိုင်းလာရင် ဘယ် Object ရဲ့ variable ကို ဘယ် Object ရဲ့ Method ကို Access လုပ်ရမှန်း သိနိုင်မှာ မဟုတ်ဘူး။

ဒါ့ကြောင့် Static Method တွေဟာ Static Variable တွေကိုသာ Access လုပ်နိုင်ပြီး Static Method တွေ အချင်းချင်းသာ Invoke လုပ်နိုင်မှာ ဖြစ်ပါတယ်။  Static Method တစ်ခုကနေ တစ်ခြား Method တစ်ခုကို Invoke လုပ်တော့မယ်ဆိုရင် အဲ့ဒီ Method ဟာ Static Method ဖြစ်နေဖို့လိုအပ်ပါတယ်။ Static Method ကနေ Instance Method ကို Invoke လုပ်ချင်ရင်တော့ Object ဆောက်ပြီးမှသာ Invoke လုပ်နိုင်မှာ ဖြစ်ပါတယ်။

Instance Method တွေကတော့ Object တွေကပိုင်တဲ့အတွက် Owner ဖြစ်တဲ့ Object တစ်ခုချင်းစီနဲ့ ပဲဆိုင်ပါတယ်။ ပြီးတော့ Instance Method တွေကနေ Instance Variable တွေကိုလဲ Access လုပ်နိုင်သလို Instance Method တွေကိုလဲ Invoke လုပ်နိုင်ပါတယ်။ သတိထားဖို့လိုတာက Owner Object ကနေ Instance ကို Invoke လုပ်လိုက်ရင် အဲ့ဒီ method ထဲကနေ Access လုပ်နေတဲ့ Instance Variable တွေရှိရင်လဲ အဲ့ဒီ Object ရဲ့ Variable ကိုပဲ Access လုပ်မှာ ဖြစ်ပြီး၊ တစ်ခြား Instance Method တွေကို Invoke လုပ်နေရင်လဲ အဲ့ဒီ​ Object ရဲ့ method ကိုပဲ Invoke လုပ်နေတာပဲ ဖြစ်ပါတယ်။ တစ်ခြား Object တွေနဲ့ ပတ်သက်မှူ့လုံးဝမရှိပါ။

တဖန် Instance Method ကနေ Static Variable တွေကိုလဲ Access လုပ်နိုင်ပြီး Static Method တွေကိုလဲ Invoke လုပ်နိုင်ပါတယ်။ ဘာလို့လဲ ဆိုတော့ Static Member တွေက Object မဆောက်ခင်ကထဲက Memory ပေါ်မှာ ရှိပြီးသားဖြစ်နေပြီး တစ်ခုထဲသာ ရှိတာဖြစ်တဲ့အတွက် ဘယ် Member ကို Access လုပ်မယ်ဆိုတာကို သိနေနိုင်တဲ့အတွက်ဖြစ်ပါတယ်။


Static နဲ့ Instance ကိုဘယ်လိုခွဲ သုံးရမလဲ

Static Members တွေနဲ့ Instance Members တွေရဲ့ ထူးခြားချက်ကို ကြည့်ရင် သိနိုင်ပါတယ်။ Static တွေဟာ Instance တွေလို Instance တစ်ခုချင်းစီအတွက် State တွေကို ပိုင်လို့မရဘူး။ ပြီးတော့ သူတို့တွေဟာ JVM ပေါ်မှာ တစ်ခုထဲရှိတဲ့ အရာတွေ ဖြစ်ကြတယ်။

အဲ့ဒီတော့ Static Method တွေကို State ပိုင်စရာမလိုအပ်တဲ့ Utility Function တွေမှာ ရေးသား အသုံးပြုနိုင်ပါတယ်။ တဖန် Static Variable တွေကလဲ JVM တစ်ခုလုံးမှာ တစ်ခုထဲသာရှိတဲ့ Variable တွေ ဖြစ်လာမှာ ဖြစ်တဲ့အတွက် Application တစ်ခုလုံးမှာ ဘုံအနေနဲ့ အသုံးပြုလိုတဲ့ အချက်အလက်တွေ၊ Object တွေကို Static Variable တွေအနေနဲ့ အသုံးပြုနိုင်ပါတယ်။

Static Variable ရဲ့ ထူးခြားချက်ကို အသုံးပြုပြီး Singleton Patterns လိုမျိုးကိုလဲ ရေးသားနိုင်ပါတယ်။ Disktop Application မျိုးမှာ Session ကို အသုံးပြုလို့မရဘူး။ အဲ့ဒီအစား Static Variable တွေကို Chache အနေနဲ့ ထားပြီး Data တွေကို Share လုပ်ပြီး အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

ဒါဖြင့် Instance Member တွေကကော။ ဒါကလွယ်ပါတယ်ဗျာ။ Object တစ်ခုချင်းစီမှာ ပိုင်ဆိုင်စေလိုတဲ့ State တွေ Behavior တွေဆိုရင် Instance Member တွေ သုံးပြီး ရေးလိုက်ရုံပေါ့ဗျာ။

မေးကြပါဗျာ။ ကြိုးစားပြီးဖြေသွားပါမယ်။
လေးစားစွာဖြင့်
မင်းလွင်