Java 8 Optional: NullPointerException වලට බයි බයි! Safe Code ලියන්න - SC Guide

ආයුබෝවන්! කොහොමද ඉතින් අපේ කට්ටියට? අද අපි කතා කරන්න යන්නේ Java development වලදී ඕනම කෙනෙක්ට නිතරම වගේ මුහුණ දෙන්න වෙන, හරිම හිසරදයක් වගේ වැඩක් ගැන. ඒ තමයි NullPointerException (NPE)! මම දන්නවා, මේක ඇහෙනකොටත් සමහරුන්ට සීතල වතුර ටිකක් ඔලුවට වක්කරගත්තා වගේ වෙයි. මොකද මේක කොච්චර පොඩි වෙලාවකට ආවත්, අපේ Application එකේ වැඩේ අවුල් කරන හැටි හොඳටම දන්නවනේ.
හිතන්නකෝ, අපේ කෝච්චිය නියම වෙලාවට එනවා කියලා ටිකට් අරන් ගියාම, පොඩි වැස්සකටත් පරක්කු වෙනකොට එන කේන්තිය වගේ දෙයක් තමයි මේ NullPointerException කියන්නෙත්. එක පාරටම Application එක බිඳ දාලා දානවා. ඒත් බය වෙන්න එපා! Java 8 එක්ක ආපු හරිම සුපිරි feature එකක් තියෙනවා මේ වගේ හිසරද වලින් මිදෙන්න. ඒ තමයි Optional
කියන Class එක.
අද අපි මේ Guide එකෙන් බලාපොරොත්තු වෙන්නේ, Optional
කියන්නේ මොකක්ද? ඒක කොහොමද අපිට මේ NullPointerException වලින් බේරෙන්න උදව් කරන්නේ කියන එක පැහැදිලිව කියලා දෙන්න. කම්මැලි කතා පැත්තකට දාලා, අපි යමු බලන්න මේ Optional
magic එක කොහොමද වැඩ කරන්නේ කියලා!
NullPointerException (NPE) කියන්නේ මොකක්ද? ☠️
මුලින්ම බලමු මේ NPE කියන්නේ මොකක්ද කියලා. සරලව කිව්වොත්, අපි යම්කිසි object එකක method එකක් call කරන්න හරි, ඒකේ field එකකට access කරන්න හරි හදනකොට, ඒ object එක null
නම්, ඒ කියන්නේ ඒක කිසිම value එකක් reference කරන්නේ නැත්නම්, Java Virtual Machine (JVM) එක මේ NullPointerException
එක විසි කරනවා (throws an exception). මේක Java development වලදී නිතරම වගේ එන runtime error එකක්. ගොඩක් වෙලාවට මේක සිදුවෙන්නේ අපිට නොදැනීමයි, ඒ නිසා debug කරන්නත් අමාරුයි.
උදාහරණයක් විදිහට බලන්නකෝ මේ simple code snippet එක.
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
User user = null; // මෙතනදී අපි user object එක null විදිහට assign කරනවා
String userName = user.getName(); // මෙතනදී NullPointerException එකක් එනවා
System.out.println("User Name: " + userName);
}
}
උඩ තියෙන code එක run කරොත්, user.getName()
කියන line එකේදී අනිවාර්යයෙන්ම NPE එකක් එනවා. මොකද user
කියන object එක null
නිසා. මේ වගේ දේවල් නිසා තමයි අපේ Application එක crash වෙන්නේ.
Optional කියන්නේ මොකක්ද? 📦
Java 8 එක්ක හඳුන්වා දුන්න java.util.Optional
කියන්නේ null
values හැසිරවීමට තියෙන සුපිරිම විසඳුමක්. සරලව කිව්වොත්, Optional
කියන්නේ container object එකක්. මේ container එක ඇතුලේ non-null value එකක් තියෙන්නත් පුළුවන්, එහෙම නැත්නම් කිසිම value එකක් නැතුව empty වෙන්නත් පුළුවන්.
මේකෙන් වෙන්නේ, අපි null
check කරන්න අමතක වුණාම එන NPE එක වෙනුවට, Optional
එකේ value එකක් තියෙනවද නැද්ද කියලා explicitly කියන්න අපිට බල කරන එක. මේක හරියට, අපි කඩේට ගිහින් බඩු ගන්නකොට, බඩු නැත්නම් 'බඩු නෑ' කියලා කියනවා වෙනුවට, 'මේ බෑග් එක හිස්' කියලා බෑග් එක පෙන්නනවා වගේ දෙයක්. ඒක අපිට තේරෙනවා බෑග් එක හිස් කියලා, එතකොට අපිට ඊළඟට මොකද කරන්නේ කියලා තීරණය කරන්න පුළුවන්.
Optional භාවිතා කරන්නේ කොහොමද? 🤔
හරි, දැන් අපි බලමු මේ Optional
එක practical විදිහට කොහොමද අපේ code එකට ගේන්නේ කියලා.
1. Optional Instances හදාගන්න විදිහ (Creating Optional Instances)
Optional.empty()
: හිස්Optional
object එකක් හදන්න මේක පාවිච්චි කරනවා.Optional.of(value)
: non-null value එකකින්Optional
එකක් හදන්න මේක පාවිච්චි කරනවා. හැබැයි මතක තියාගන්න, value එකnull
වුණොත් මේක NPE එකක් throw කරනවා!Optional.ofNullable(value)
: මේක තමයි ගොඩක් වෙලාවට පාවිච්චි වෙන්නේ. value එකnull
ද නැද්ද කියලා නොදන්නකොට මේක පාවිච්චි කරන්න පුළුවන්. Value එකnull
නම්,Optional.empty()
එකක් return කරනවා.null
නැත්නම්,Optional.of(value)
වගේම වැඩ කරනවා.
String maybeName = "Sunil";
Optional<String> optionalMaybeName = Optional.ofNullable(maybeName);
String anotherMaybeName = null;
Optional<String> optionalAnotherMaybeName = Optional.ofNullable(anotherMaybeName); // Returns Optional.empty()
String name = "Kamal";
Optional<String> optionalName = Optional.of(name);
// String nullName = null;
// Optional<String> optionalNullName = Optional.of(nullName); // NullPointerException here!
Optional<String> emptyOptional = Optional.empty();
2. Value එකක් තියෙනවද කියලා බලන විදිහ (Checking for Presence)
isPresent()
:Optional
එක ඇතුලේ value එකක් තියෙනවද කියලාboolean
එකකින් කියනවා.isEmpty()
(Java 11+):Optional
එක හිස්ද කියලාboolean
එකකින් කියනවා.isPresent()
එකේ ප්රතිලෝමය වගේ.
if (optionalAnotherMaybeName.isEmpty()) {
System.out.println("Another name is empty (Java 11+).");
}
if (optionalName.isPresent()) {
System.out.println("Name is present: " + optionalName.get());
} else {
System.out.println("Name is not present.");
}
3. Value එක ගන්න විදිහ (Getting the Value)
get()
:Optional
එක ඇතුලේ තියෙන actual value එක return කරනවා. හැබැයි!Optional
එක හිස් නම් මේකNoSuchElementException
එකක් throw කරනවා. ඒ නිසා මේකisPresent()
එක්ක විතරක් පාවිච්චි කරන්න!
Optional<String> name = Optional.of("Chamara");
String value = name.get(); // "Chamara"
// Optional<String> emptyName = Optional.empty();
// String emptyValue = emptyName.get(); // NoSuchElementException!
4. Value එකක් තියෙනවා නම් මොකක් හරි කරන්න (Conditional Actions)
ifPresent(Consumer action)
:Optional
එක ඇතුලේ value එකක් තියෙනවා නම්, දීපුConsumer
එක run කරනවා.ifPresentOrElse(Consumer action, Runnable emptyAction)
(Java 9+): value එකක් තියෙනවා නම්action
එක run කරනවා, නැත්නම්emptyAction
එක run කරනවා.
Optional<String> phone = Optional.ofNullable("0771234567");
phone.ifPresentOrElse(
p -> System.out.println("Phone: " + p),
() -> System.out.println("No phone number provided.")
);
Optional<String> optionalEmail = Optional.ofNullable("[email protected]");
optionalEmail.ifPresent(email -> System.out.println("Email found: " + email));
Optional<String> noEmail = Optional.empty();
noEmail.ifPresent(email -> System.out.println("This won't print."));
5. Default Values දෙන්න (Providing Default Values)
මේවා තමයි ගොඩක්ම ප්රයෝජනවත් methods. Value එකක් නැත්නම් default value එකක් දෙන්න මේවා පාවිච්චි කරන්න පුළුවන්.
orElse(T other)
:Optional
එකේ value එකක් තියෙනවා නම් ඒක return කරනවා. නැත්නම් දීපුother
default value එක return කරනවා. සටහන:other
value එකOptional
එක empty වුණත් නැතත් හැමවෙලේම evaluate වෙනවා.orElseGet(Supplier<? extends T> supplier)
:Optional
එකේ value එකක් තියෙනවා නම් ඒක return කරනවා. නැත්නම් දීපුSupplier
එක call කරලා ඒකෙන් එන value එක return කරනවා. වැදගත්:Supplier
එක call වෙන්නේOptional
එක empty නම් විතරයි. ඒ කියන්නේ lazy evaluation.orElseThrow(Supplier<? extends X> exceptionSupplier)
:Optional
එක හිස් නම් දීපුSupplier
එකෙන් එන exception එක throw කරනවා. Value එකක් තියෙනවා නම් ඒක return කරනවා.
try {
String importantValue = Optional.ofNullable(null)
.orElseThrow(() -> new IllegalArgumentException("Value must be present!"));
} catch (IllegalArgumentException e) {
System.out.println("Caught exception: " + e.getMessage());
}
String validValue = Optional.of("Valid Data")
.orElseThrow(() -> new IllegalArgumentException("Should not happen"));
System.out.println("Valid Data: " + validValue);
// Imagine a heavy operation to get default value
String expensiveDefault = Optional.ofNullable(null)
.orElseGet(() -> {
System.out.println("Getting expensive default...");
return "Default User";
});
System.out.println("Expensive Default User: " + expensiveDefault);
// This will NOT print "Getting expensive default..." because value is present
String anotherUser = Optional.of("Normal User")
.orElseGet(() -> {
System.out.println("Getting expensive default...");
return "Default User";
});
System.out.println("Another User: " + anotherUser);
String username = Optional.ofNullable(null).orElse("Guest");
System.out.println("Username: " + username); // Output: Guest
String activeUsername = Optional.of("Admin").orElse("Guest");
System.out.println("Active Username: " + activeUsername); // Output: Admin
6. Values Transform කරන්න (Transforming Values)
map(Function<? super T, ? extends U> mapper)
:Optional
එක ඇතුලේ value එකක් තියෙනවා නම්, ඒක දීපුFunction
එකට pass කරලා, ඒකෙන් එන result එක අලුත්Optional
එකක් විදිහට return කරනවා.flatMap(Function<? super T, ? extends Optional<U>> mapper)
:map
වගේමයි. හැබැයි,mapper
function එක return කරන්නේOptional
එකක් නම්, මේක nestedOptional
එකක් හැදෙන්නේ නැතුව, straight upOptional
එකක් return කරනවා. (එකම මට්ටමේ තියාගන්න).
// Imagine a method that returns Optional<Integer>
public static Optional<Integer> parseNumber(String s) {
try {
return Optional.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
Optional<String> ageString = Optional.of("30");
Optional<Integer> age = ageString.flatMap(Main::parseNumber);
System.out.println("Parsed Age: " + age.orElse(0)); // 30
Optional<String> invalidAgeString = Optional.of("abc");
Optional<Integer> invalidAge = invalidAgeString.flatMap(Main::parseNumber);
System.out.println("Invalid Age: " + invalidAge.orElse(0)); // 0
Optional<String> companyName = Optional.of("softlogic");
Optional<String> upperCaseName = companyName.map(String::toUpperCase);
System.out.println("Upper Case Name: " + upperCaseName.orElse("N/A")); // SOFTLOGIC
Optional<String> emptyCompany = Optional.empty();
Optional<String> upperCaseEmpty = emptyCompany.map(String::toUpperCase);
System.out.println("Upper Case Empty: " + upperCaseEmpty.orElse("N/A")); // N/A
7. Values Filter කරන්න (Filtering Values)
filter(Predicate<? super T> predicate)
:Optional
එක ඇතුලේ value එකක් තියෙනවා නම්, දීපුPredicate
එකෙන් ඒක check කරනවා.true
නම්Optional
එකේ value එක ඒ විදිහටම return කරනවා.false
නම්Optional.empty()
එකක් return කරනවා.
Optional<Integer> age = Optional.of(25);
Optional<Integer> adultAge = age.filter(a -> a >= 18);
System.out.println("Adult Age: " + adultAge.orElse(0)); // 25
Optional<Integer> childAge = Optional.of(15);
Optional<Integer> filteredChildAge = childAge.filter(a -> a >= 18);
System.out.println("Filtered Child Age: " + filteredChildAge.orElse(0)); // 0 (empty optional)
Optional වල වාසි මොනවද? 👍
දැන් ඔයාලට තේරෙනවා ඇති Optional
එක කොච්චර වටිනවද කියලා. මෙන්න ඒකෙන් අපිට ලැබෙන ප්රධාන වාසි ටිකක්:
- NullPointerException වලින් මිදීම: මේක තමයි ප්රධානම වාසිය.
Optional
භාවිතා කිරීමෙන්,null
විය හැකි තැන් explicit විදිහට handle කරන්න අපිට බල කරනවා. ඒ නිසා runtime එකේදී එන NPE අවදානම අඩු වෙනවා. - Code එකේ Readability එක වැඩිවීම:
if (value != null)
කියලා හැම තැනම check කරනවා වෙනුවට,Optional
methods (ifPresent
,orElse
,map
වගේ) පාවිච්චි කරන එකෙන් code එක වඩාත් පැහැදිලි, කියවන්න පහසු, functional style එකකට ලියන්න පුළුවන්. - API Design එක දියුණු වීම: method එකක්
Optional
එකක් return කරනවා නම්, ඒ method එකෙන් value එකක් නැති වෙන්න පුළුවන් කියලා caller ට පැහැදිලිවම කියනවා. ඒ නිසා caller ට ඒක handle කරන්න පුළුවන්. - Functional Programming වලට උදව් වීම: Java 8 Stream API එකත් එක්ක වගේම,
Optional
එකත් functional programming style එකට හොඳට ගැලපෙනවා.
Optional භාවිතා නොකළ යුතු තැන් ⚠️
ඕනම දෙයක් වගේ, Optional
වලටත් ඒක පාවිච්චි කරන්න හොඳ නැති තැන් තියෙනවා. හැම තැනම Optional
දාන එක හොඳ පුරුද්දක් නෙවෙයි. මතක තියාගන්න, Optional
එක designed කරලා තියෙන්නේ method return types සඳහා මිසක්, field වලට හෝ parameters වලට නෙවෙයි.
- Class Field එකක් විදිහට:
Optional
එක class එකක field එකක් විදිහට පාවිච්චි කරන එක එච්චර හොඳ පුරුද්දක් නෙවෙයි. ඒක serialization, persistence වගේ දේවල් වලට ගැටලු ඇති කරන්න පුළුවන්. ඒ වගේ තැන් වලටnull
value එකක් පාවිච්චි කරන එක වඩාත් සුදුසුයි. - Method Parameter එකක් විදිහට: method එකක parameter එකක් විදිහට
Optional
එකක් පාවිච්චි කරනවා නම්, ඒක code එකේ clarity එක අඩු කරන්න පුළුවන්. Parameter එකක්null
වෙන්න පුළුවන් නම්,null
එක pass කරලා, method එක ඇතුලේ check කරන එක සාමාන්යයෙන් වඩා හොඳයි, නැත්නම් method overloading කරන්න පුළුවන්. - Collections ඇතුලේ:
List<Optional<String>>
වගේ collections ඇතුලේOptional
objects දාන එක එච්චර සුදුසු නෑ. ඒ වෙනුවට,null
values remove කරලා clean collection එකක් පාවිච්චි කරන්න පුළුවන්. - Exceptions වෙනුවට: යම්කිසි value එකක් නැතිවීම exceptional case එකක් නම් (එනම්, ඒක සාමාන්ය තත්ත්වයක් නෙවෙයි නම්),
Optional.empty()
එකක් return කරනවා වෙනුවට, අදාලException
එක throw කරන එක වඩාත් සුදුසුයි.
අවසාන වශයෙන් 🚀
ඉතින්, අද අපි Java 8 වල Optional
කියන Class එක ගැන විස්තරාත්මකව කතා කළා. NullPointerException
කියන හිසරදයෙන් මිදිලා, වඩාත් safe සහ කියවන්න පහසු Java applications develop කරන්න Optional
කොච්චර උදව් වෙනවද කියලා ඔයාලට දැන් පැහැදිලි ඇති.
මතක තියාගන්න, Optional
කියන්නේ මැජික් විසඳුමක් නෙවෙයි, හැබැයි හරි විදිහට පාවිච්චි කරොත්, ඒක ඔයාලගේ code base එක ගොඩක් දියුණු කරන්න පුළුවන්. අද ඉඳන්ම ඔයාලගේ project වල Optional
භාවිතා කරලා බලන්න. ඒක ඔයාලගේ developer ජීවිතේට ලොකු සහනයක් වෙයි!
මේ ගැන ඔයාලගේ අදහස්, ප්රශ්න, හෝ ඔයාලගේ අත්දැකීම් පහළින් comment කරන්න. අපි ඊළඟ ලිපියෙන් හම්බවෙමු! තව සුපිරිම Java concept එකක් අරගෙන එන්නම්.
ජය වේවා!