Java 8 Lambdas: කෝඩ් ලස්සනට ලියමු SC Guide

Java 8 Lambdas: කෝඩ් ලස්සනට ලියමු SC Guide

කොහොමද යාලුවනේ! ❤️ අද අපි කතා කරන්නේ Java programming ලෝකයේ විප්ලවයක් වගේ ආපු, කෝඩ් ලියන විදිය සම්පූර්ණයෙන්ම වෙනස් කරපු, නියමම feature එකක් ගැන – ඒ තමයි Java 8 Lambda Expressions!

ඔයාලා Java 8 වලට කලින් programming කරලා තියෙනවා නම්, සමහර වෙලාවට anonymous inner classes පාවිච්චි කරලා ඇති, විශේෂයෙන්ම event handling, threads නැත්නම් collections එක්ක වැඩ කරනකොට. මතකද? ඒක කොච්චර කෝඩ් ලයින්ස් ප්‍රමාණයක් අරගෙනද කියලා? 😥 සමහර වෙලාවට පොඩි වැඩකටත් ලොකු කෝඩ් බ්ලොක් එකක් ලියන්න වෙනවා.

හැබැයි Java 8 එක්ක ආපු Lambda Expressions මේ ප්‍රශ්නයට නියම විසඳුමක් දුන්නා. මේවා අපේ කෝඩ් එක වඩාත් පැහැදිලි, කියවන්න ලේසි, සහ ප්‍රමාණයෙන් අඩු (concise) එකක් බවට පත් කරනවා. ඒ වගේම Functional Programming කියන සංකල්පය Java වලට ගෙන එන්නත් මේවා ලොකු පිටිවහලක් වුණා. අද අපි බලමු මේ Lambda Expressions කියන්නේ මොනවද, ඒවා කොහොමද පාවිච්චි කරන්නේ, සහ ඒකෙන් අපිට ලැබෙන වාසි මොනවද කියලා.

Lambda Expressions කියන්නේ මොනවද? 🤔

සරලවම කිව්වොත්, Lambda Expression කියන්නේ ඔබට functional interface එකක් implement කරන්න ඕන වුණාම, බොහොම ලේසියෙන්, ටිකක් කෝඩ් වලින් ඒක කරන්න පුළුවන් ක්‍රමයක්. ඒක ඇත්තටම ‘function’ එකක් variable එකකට වගේ assign කරනවා වගේ වැඩක්. කලින් anonymous inner class එකකින් කරපු දේ, දැන් මේ Lambda එකකින් ඉතාම කෙටියෙන් කරන්න පුළුවන්.

Lambda Expression එකකට සාමාන්‍යයෙන් ප්‍රධාන කොටස් තුනක් තියෙනවා:

  • Parameters: (පැරාමීටර්ස්) – මේක තමයි function එකට ලැබෙන input ටික. වරහන් ඇතුලේ තමයි මේවා ලියන්නේ.
  • Arrow Token: (ඇරෝ ටෝකන්) – මේක තමයි -> ලකුණ. මේකෙන් වෙන් කරලා පෙන්නනවා පැරාමීටර්ස් සහ කෝඩ් බ්ලොක් එක.
  • Body: (බොඩි) – මේක තමයි function එක ඇතුලේ සිද්ධ වෙන වැඩේ, එහෙමත් නැත්නම් කෝඩ් බ්ලොක් එක.

මේවා කලින් Java versions වල තිබුණේ නෑ. ඒ නිසා තමයි Java 8 කියන්නේ ගොඩක් වැදගත් update එකක් වුණේ.

Functional Interfaces කියන්නේ මොනවද? 🧩

Lambda Expressions වැඩ කරන්නේ functional interfaces එක්ක විතරයි. මේක ගොඩක් වැදගත් දෙයක්, හොඳට මතක තියාගන්න ඕනේ.

එතකොට functional interface එකක් කියන්නේ මොකක්ද? ඒක තමයි හරියටම abstract method එකක් විතරක් තියෙන interface එකක්. ඒක ඇතුලේ default methods, static methods, සහ Object class එකේ methods (e.g., equals, toString) තියෙන්න පුළුවන්. ඒත් abstract methods තියෙන්න පුළුවන් එකක් විතරයි.

මේ වගේ interface එකක් define කරනකොට, ඒක functional interface එකක් බව compiler එකට කියන්න @FunctionalInterface annotation එක පාවිච්චි කරනවා. මේක දාන්නම ඕනේ නෑ, හැබැහයි දාන එක හොඳ practice එකක්. මොකද එතකොට compiler එක check කරනවා ඒකේ එක abstract method එකක් විතරක් තියෙනවද කියලා. එහෙම නැත්නම් error එකක් දෙනවා.

උදාහරණයක් විදියට, අපිම හදාගත්ත functional interface එකක් බලමු:


@FunctionalInterface
interface MyCalculator {
    int operate(int a, int b); // Single abstract method
}

// Java built-in functional interfaces:
// Runnable (void run())
// Comparable (int compareTo(T o))
// Consumer (void accept(T t))
// Predicate (boolean test(T t))
// Function (R apply(T t))

දැන් ඔයාලට පැහැදිලියි නේද functional interface එකක් කියන්නේ මොකක්ද කියලා? මේවා තමයි Lambda Expressions වලට පදනම වෙන්නේ.

Lambda Expressions වල Syntax එක ✍️

Lambda Expressions වල syntax එක ගොඩක්ම සරලයි. අපි විවිධ අවස්ථා වලදී ඒවා පාවිච්චි කරන හැටි බලමු:

1. Parameters නැති Lambda Expression එකක්

මේක සාමාන්‍යයෙන් Runnable වගේ interface එකක් එක්ක පාවිච්චි කරන්න පුළුවන්. කෝඩ් එකේ කිසිම input එකක් නැත්නම්, වරහන් හිස්ව තියන්න පුළුවන්.


// Before Java 8 (Anonymous inner class)
Runnable oldWay = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from old way!");
    }
};
new Thread(oldWay).start();

// With Lambda Expression
Runnable newWay = () -> System.out.println("Hello from Lambda!");
new Thread(newWay).start();

දැක්කනේ කොච්චර සරලද කියලා? කෝඩ් ලයින්ස් ගානත් අඩුයි.

2. එක Parameters එකක් තියෙන Lambda Expression එකක්

එක parameter එකක් විතරක් තියෙනකොට, ඒ parameter එක වටේට වරහන් දාන්නේ නැතුව ලියන්න පුළුවන්. ඒ වගේම parameter එකේ Data Type එක සඳහන් කරන්නත් ඕනේ නෑ (Type Inference නිසා), හැබැයි දාන්නත් පුළුවන්.


// Example 1: Without parentheses and type
Consumer<String> greet = name -> System.out.println("Hello, " + name + "!");
greet.accept("Kasun");

// Example 2: With parentheses and type (still valid)
Consumer<String> anotherGreet = (String name) -> System.out.println("Hi there, " + name + "!");
anotherGreet.accept("Nimal");

3. Parameters කිහිපයක් තියෙන Lambda Expression එකක්

parameters කිහිපයක් තියෙනකොට, අනිවාර්යයෙන්ම ඒවා වරහන් ඇතුලේ දාන්න ඕනේ. Data Types සඳහන් කරන එක අනිවාර්ය නෑ, compiler එකට ඒවා automatically detect කරන්න පුළුවන්.


// Our custom MyCalculator functional interface
MyCalculator add = (num1, num2) -> num1 + num2;
System.out.println("Sum: " + add.operate(10, 5)); // Output: Sum: 15

// Another example with explicit types
MyCalculator multiply = (int num1, int num2) -> num1 * num2;
System.out.println("Product: " + multiply.operate(10, 5)); // Output: Product: 50

4. Body එකේ Statements කිහිපයක් තියෙන Lambda Expression එකක්

Lambda Body එක ඇතුලේ statements එකකට වඩා තියෙනවා නම්, ඒක Curly braces {} ඇතුලේ ලියන්න ඕනේ. ඒ වගේම return statement එකක් තියෙන්න ඕනේ, ඒක single expression එකක් නම් return keyword එක අනිවාර්ය නෑ. හැබැයි Curly braces එක්ක නම් return keyword එක අනිවාර්යයි.


// Lambda with multiple statements in the body
MyCalculator complexOperation = (a, b) -> {
    int sum = a + b;
    int product = a * b;
    System.out.println("Intermediate sum: " + sum);
    System.out.println("Intermediate product: " + product);
    return sum + product; // Must return a value if the interface method returns one
};
System.out.println("Complex result: " + complexOperation.operate(2, 3));
// Output:
// Intermediate sum: 5
// Intermediate product: 6
// Complex result: 11

ප්‍රායෝගික උදාහරණ (Practical Examples) ✨

Lambda Expressions වල බලය ඇත්තටම පේන්නේ ඒවා ප්‍රායෝගිකව පාවිච්චි කරනකොට. අපි පොඩි උදාහරණ කිහිපයක් බලමු:

1. List එකක් Sort කිරීම

අපිට List එකක තියෙන Objects සාමාන්‍ය ක්‍රමයට වඩා වෙනස් විදියකට sort කරන්න ඕන වුණාම, කලින් Comparator interface එක implement කරපු anonymous inner class එකක් පාවිච්චි කළා. දැන් Lambda Expressions වලින් ඒක කොච්චර ලේසිද කියලා බලමු:


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class LambdaSortExample {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Chandana");
        names.add("Amal");
        names.add("Gayani");
        names.add("Bimal");

        System.out.println("Original List: " + names);

        // Before Java 8: Sorting with anonymous inner class
        // Collections.sort(names, new Comparator<String>() {
        //     @Override
        //     public int compare(String s1, String s2) {
        //         return s1.compareTo(s2);
        //     }
        // });

        // With Lambda Expression: Sorting in ascending order (natural order)
        Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
        System.out.println("Sorted Ascending: " + names);

        // With Lambda Expression: Sorting in descending order
        Collections.sort(names, (s1, s2) -> s2.compareTo(s1));
        System.out.println("Sorted Descending: " + names);
    }
}

කෝඩ් එක කොච්චර කෙටිද කියලා බලන්න! 🤯

2. Collection එකක Iteration (forEach)

Collections වල තියෙන elements වලට එකින් එක access වෙන්න (iterate වෙන්න) කලින් අපි for-each loop එකක් වගේ පාවිච්චි කළා. දැන් Java 8 වලට ආපු forEach method එකට Lambda Expression එකක් දෙන්න පුළුවන්. ඒ වගේම මෙතනදී Method References කියන තව නියම feature එකකුත් පාවිච්චි කරන්න පුළුවන්.


import java.util.Arrays;
import java.util.List;

public class LambdaForEachExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // Using Lambda Expression
        System.out.println("Printing with Lambda:");
        numbers.forEach(number -> System.out.println(number));

        // Using Method Reference (even more concise!)
        System.out.println("Printing with Method Reference:");
        numbers.forEach(System.out::println);
    }
}

Method Reference එක කියන්නේ Lambda එකක් තව ටිකක් කෙටි කරපු විදියක්. ඒ ගැන අපි පස්සේ වෙනම post එකකින් කතා කරමු.

3. Stream API එක්ක පාවිච්චි කිරීම

Java 8 එක්ක ආපු තවත් ලොකුම feature එකක් තමයි Stream API එක. මේක Collections වල Data process කරන්න නියම ක්‍රමයක්. Stream API එකත් එක්ක Lambda Expressions ගොඩක්ම පාවිච්චි වෙනවා. උදාහරණයක් විදියට List එකක තියෙන ඉරට්ටේ සංඛ්‍යා (even numbers) විතරක් filter කරලා print කරන හැටි බලමු:


import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class LambdaStreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Filter even numbers and print them
        System.out.println("Even numbers:");
        numbers.stream()
               .filter(n -> n % 2 == 0) // Lambda expression for filtering
               .forEach(System.out::println); // Method reference for printing

        // Map numbers to their squares and collect into a new list
        System.out.println("\nSquared numbers:");
        List<Integer> squaredNumbers = numbers.stream()
                                              .map(n -> n * n) // Lambda expression for mapping
                                              .collect(Collectors.toList());
        System.out.println(squaredNumbers); // Output: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    }
}

මේ වගේ Stream Operations එක්ක Lambda expressions එකතුවෙනකොට කෝඩ් එක ගොඩක්ම Powerful වෙනවා, ඒ වගේම කියවන්නත් හරිම ලේසියි.

Lambda Expressions වල වාසි මොනවද? ✅

දැන් ඔයාලට Lambda Expressions මොනවද කියලා සහ කොහොමද පාවිච්චි කරන්නේ කියලා හොඳ අවබෝධයක් ලැබෙන්න ඇති. මේවා පාවිච්චි කිරීමෙන් අපිට ලැබෙන ප්‍රධාන වාසි කිහිපයක් තියෙනවා:

  1. කෝඩ් එකේ දිග අඩු කරනවා (Conciseness): මේක තමයි ලොකුම වාසිය. කලින් anonymous inner classes වලින් කරපු වැඩේට වඩා කෝඩ් ලයින්ස් ගොඩක් අඩු වෙනවා.
  2. කියවන්න ලේසියි (Readability): කෝඩ් එකේ අනවශ්‍ය boilerplate code අඩු වෙන නිසා, අපිට වැඩේ කෙලින්ම මොකක්ද කියලා තේරුම් ගන්න පුළුවන්.
  3. Functional Programming වලට දොර ඇරෙනවා (Enabling Functional Programming): Lambda Expressions නිසා Java වලට map, filter, reduce වගේ functional programming concepts ගෙන එන්න පුළුවන් වුණා. Stream API එකත් මේ නිසා තමයි මෙච්චර දියුණු වුණේ.
  4. Parallel Processing වලට පහසුව (Easier Parallel Processing): Stream API එකත් එක්ක Lambda Expressions පාවිච්චි කරලා collections වල operations ඉතාම ලේසියෙන් parallelize කරන්න පුළුවන්. ඒකෙන් performance එක වැඩි කරගන්න පුළුවන්.

කවදද Lambda Expressions පාවිච්චි කරන්න ඕනේ? 💡

Lambda Expressions කියන්නේ හැම තැනටම දාන්න ඕනේ දෙයක් නෙමෙයි. මේවා පාවිච්චි කරන්න ඕනේ, ඒකෙන් කෝඩ් එකේ පැහැදිලිකම වැඩි වෙනවා නම් සහ සරලව functional interface එකක් implement කරන්න පුළුවන් නම් විතරයි.

  • ඔබට functional interface එකක් implement කරන්න ඕනේ නම්, සහ ඒ implement කරන logic එක බොහොම කෙටි නම් (single line or a few lines), Lambda එකක් පාවිච්චි කරන්න.
  • Complex logic එකක් තියෙනවා නම්, නැත්නම් වෙනම instance variables තියාගන්න ඕනේ නම්, එතකොට anonymous inner class එකක් නැත්නම් වෙනම class එකක් හදන එක වඩා හොඳයි. හැම වෙලාවෙම Lambda expressions පාවිච්චි කරන්න ගියාම කෝඩ් එක කියවන්න අමාරු වෙන්න පුළුවන්.

අවසාන වශයෙන්… 🔚

ඉතින් යාලුවනේ, Java 8 එක්ක ආපු Lambda Expressions කියන්නේ ඔයාලගේ කෝඩ් ලියන විදියට නියම පහසුවක් ගෙන දෙන නියම feature එකක්. මේකෙන් අපිට කෝඩ් එක වඩාත් පැහැදිලි, කෙටි සහ කාර්යක්ෂම එකක් බවට පත් කරගන්න පුළුවන්. විශේෂයෙන්ම Stream API එකත් එක්ක එකතු වුණාම මේවාගේ බලය තවත් වැඩි වෙනවා.

ඕගොල්ලොත් අනිවාර්යයෙන්ම මේවා පාවිච්චි කරලා බලන්න. මුලින් ටිකක් අමුතු වගේ දැනුනත්, දවස් දෙක තුනක් යනකොට පුරුදු වෙයි. මොනාහරි ප්‍රශ්න තියෙනවා නම්, මේ ගැන තවත් දැනගන්න ඕනේ නම්, නැත්නම් ඔයාලගේ අත්දැකීම් බෙදාගන්න ඕනේ නම්, පහලින් comment කරන්න අමතක කරන්න එපා. අපි එකට මේ ගැන කතා කරමු! ජය වේවා! 🚀