Lambdas

Lambdas in Java.

// Easier way to work with interfaces that have just one method that has to be implemented (functional interfaces). Also true if more than one method but other(s) have default implementation
// Often used in place of anonymous classes
public class Lambdas {

    public static void main(String[] args) {
        new Thread(new CodeToRun()).start(); // One method

        new Thread(new Runnable() { // Another method - anonymous class. Still a lot of code to run one line of output
            @Override
            public void run() {
                System.out.println("Also printing from the Runnable");
            }
        }).start();

        // Can be replaced with a lambda
        new Thread(() -> System.out.println("Still printing from the Runnable")).start(); // Passes the println() directly to the Thread constructor
        // 3 parts to a lambda - 1. argument list (empty in this case) 2. arrow token 3. body (put code to be executed here) - use {} for multiple lines (remember ; when multiple lines):

        new Thread(() -> {
            System.out.println("Line one");
            System.out.println("Line two");
        }).start();

        Employee john = new Employee("John Doe", 30);
        Employee tim = new Employee("Tim Buchalka", 21);
        Employee jack = new Employee("Jack Hill", 40);
        Employee snow = new Employee("Snow White", 22);

        List<Employee> employees = new ArrayList<>();
        employees.add(john);
        employees.add(tim);
        employees.add(jack);
        employees.add(snow);

//        Collections.sort(employees, new Comparator<Employee>() {
//            @Override
//            public int compare(Employee employee1, Employee employee2) {
//                return employee1.getName().compareTo(employee2.getName());
//            }
//        });

        Collections.sort(employees, (employee1, employee2) -> employee1.getName().compareTo(employee2.getName()));

        for (Employee employee : employees) {
            System.out.println(employee.getName());
        }

//        String sillyString = doStringStuff(new UpperConcat() {
//            @Override
//            public String upperAndConcat(String s1, String s2) {
//                return s1.toUpperCase() + s2.toUpperCase();
//            }
//        }, employees.get(0).getName(), employees.get(1).getName());
//        System.out.println(sillyString);

        String sillyString = doStringStuff((s1, s2) -> s1.toUpperCase() + s2.toUpperCase(), employees.get(0).getName(), employees.get(1).getName()); // No return keyword required
        System.out.println(sillyString);

    }
    //What if the interface returns a value?
    public final static String doStringStuff(UpperConcat uc, String s1, String s2) {
        return uc.upperAndConcat(s1, s2);
    }
}

class CodeToRun implements Runnable {
    @Override
    public void run() {
        System.out.println("Printing from the Runnable");
    }
}

class Employee {
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

interface UpperConcat {
    public String upperAndConcat(String s1, String s2);
}