Lambda Expressions

Ace your homework & exams now with Quizwiz!

We need to add { } even if we have only one line of the code because we will return a String value(a second argument in Function<firstArgument, secondArgument>).

Function<Employee, String> getFirstName = (Employee employee) -> { return employee.getName().substring(0, employee.getName().indexOf(" ")); };

We can chain functions together with "andThen and composite". The function which calls the andThen method will run first and only then a function which in the method. Compose is reverse from andThen.

Function<Employee, String> upperCase = employee -> employee.getName().toUpperCase(); Function<String, String> firstName = name -> name.substring(0, name.indexOf(" ")); Function chainedFunction = upperCase.andThen(firstName); System.out.println(chainedFunction.apply(employees.get(0)));

We will get the name of the class in which the lambda statement is placed when we try getClass.getSimpleName( ); That means it is treated as a nested block of code, also a new instance isn't created(like it is with anonymous class).

UpperConcat up = (s1, s2) -> { System.out.println("The Lambda's name is: " + getClass().getSimpleName()); String s = s1.toUpperCase() + s2.toUpperCase(); return s; };

We can use the flatMap method if we want to print a multidimensional array. Here we have multiple departments and each department has an array list of employees, so it's a multidimensional array.

departments.stream() .flatMap(department -> department.getEmployees().stream()) .forEach(System.out::println);

The lambda expression:

printByAge(employees, "Younger then 35", employee -> employee.getAge() < 35);

The anonymous class.

printByAge(employees, "Younger then 35", new Predicate<Employee>() { @Override public boolean test(Employee employee) { return employee.getAge() <= 35; } });

The items in the source enter the pipeline, and the chain result emerges at the other end of the pipeline.

toUpperString has changed the character of the array and this wasn't the case in the example without stream.So now "g64" is printer as "G64".

We can create an array like this: List<String> someBingoNumbers = Arrays.asList( "N40", "N36", "B12", "B6", "G53", "G49", "G60", "G50", "g64", "I26", "I17", "I29", "071" );

And print all elements which start with "G": someBingoNumbers.forEach(number -> { if (number.toUpperCase().startsWith("G")) { System.out.println(number); } });9

Lamda has 3 parts:

Argument List, an arrow token, the body

BiFunction<arg1, arg1, return type> accepts two arguments, so it must be chained as first. That is why we don't have the compose method for this function.

BiFunction<String, Employee, String> concatAge = (name, employee) -> { return name.concat(" " + employee.getAge()); };

Only the functional interface can use lambda expressions because it has only one method.

Check more about this on google.yt

"::" this notation is called a method reference

Class::method

Or we can use lambda instead of anonymous class:

Collections.sort(employees, (Employee o1,Employee o2) -> o1.getName().compareToIgnoreCase(o2.getName()) );

We don't need to specify a type if there is only type:

Collections.sort(employees, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()) );

We can sort like this:

Collections.sort(employees, new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { return o1.getName().compareToIgnoreCase(o2.getName()); } });

But we can't do it like this because needs to be final or effectively final.

Employee employee; for (int i = 0; i < employees.size(); i++) { employee = employees.get(i); System.out.println(employee.getName()); new Thread(() -> { System.out.println("Age: " + employee.getAge()); }).start(); }

When we want to use a stream that uses a collection as a source, the stream method will always be the first call we make.

Every stream operation has to fulfill two conditions: 1. They must be non-interfering which means that they don't change the stream source in any way. 2. They must be stateless, so the result of an operation can't depend on any state outside of the operation

When a chain is evaluated a stream pipeline is created. The stream pipeline consists of a source, zero or more intermediate operations, and one terminal operation.

In our example we used a collection as a source, but we could use an array or an I/O channe, and we can build streams from scratch.

So far we have been using general predicates and consumers, but we can try IntPredicate and IntConsumer, long, double... Besides and there is also negate and or, and they can be chained together.

IntPredicate lessThen100 = i -> i < 100; IntPredicate greaterThen50 = i -> i > 50; System.out.println(lessThen100.test(50)); System.out.println(lessThen100.and(greaterThen50).test(66));

The unaryOperator accepts returns the same type of a argument, such as int, long, double etc.

IntUnaryOperator incBy5 = i -> i + 5; System.out.println(incBy5.applyAsInt(10));

We can use gNumbers.add( ) inside the lambda because it doesn't change the reference to the Object.

List<String> gNumbers = new ArrayList<>(); someBingoNumbers.forEach(number -> { if (number.toUpperCase().startsWith("G")) { gNumbers.add(number); } }); gNumbers.sort((String s1, String s2) -> s1.compareTo(s2)); gNumbers.forEach((String s) -> System.out.println(s));

We can use the terminal method collect to create a new array which we can continue to use for our purposes.

List<String> sortedGNumbers = someBingoNumbers .stream() .map(String::toUpperCase) .filter(s -> s.startsWith("G")) .sorted() .collect(Collectors.toList());

Consumer can be chained, but there it's pointless because it can't return anything.

Nothing will be printed on the console log: Consumer<String> c1 = s -> s.toUpperCase(); Consumer<String> c2 = s -> System.out.println(s); c1.andThen(c2).accept("Hello");

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

Or with lambda UpperConcat up = (s1, s2) -> s1.toUpperCase() + s2.toUpperCase(); String sillyString = doStuff(up, employees.get(0).getName(), employees.get(1).getName());

We need to use { } if we have more than one line of statement.

Otherwise we will get a compiler error.

Supplier doesn't require an argument, but it return a value.

Random random = new Random(); Supplier<Integer> supplier = () -> random.nextInt(1000); for (int i = 0; i < 10; i++) { System.out.println(supplier.get()); }

We can create a stream like this

Stream<String> ioNumberStream = Stream.of("I26", "I17", "I29", "O71"); Stream<String> inNumberStream = Stream.of("N40", "N36", "I26", "I17", "I29", "O71"); Stream<String> concatStream = Stream.concat(ioNumberStream, inNumberStream);

We will get nothing if we try to get a name of the anonymous class and that is reasonable.

System.out.println("The anonymous class's name is: " + getClass().getSimpleName());

And we can print stream like this, but also we can check with the peek method if everything is alright(for debugging).

System.out.println(concatStream .distinct() .peek(System.out::println) .count() );

A stream can be a sequence of computer chaining.

This stream has nothing to do with IO stream.

Stream defined by Oracle: A sequence of elements supporting sequential and parallel aggregate operations.

We can say that the stream is a set of object references. The stream method which has been added to the collections class in Java 8 creates a stream from a collections. Now each object reference in the stream corresponds to an object in the collection and the ordering of the object reference matches the ordering of the collection.

The point of the previous two examples is that the lambdas are viewed as nested blocks. Here i also has to be final or effectively final.

class AnotherClass { public String doSomething() { System.out.println("AnotherClass name is: " + getClass().getSimpleName()); int i = 33; i++; UpperConcat up = (s1, s2) -> { System.out.println("The Lambda's name is: " + getClass().getSimpleName()); System.out.println("The value of i: " + i); String s = s1.toUpperCase() + s2.toUpperCase(); return s; }; return Main.doStuff(up, "String1", "String2"); } }

Error:(98, 105) java: local variables referenced from an inner class must be final or effectively final(to not change them after we add them in the anonymous class).

class AnotherClass { public String doSomething() { int a = 22; { UpperConcat up = new UpperConcat() { @Override public String upperAndConcat(String s1, String s2) { System.out.println("The anonymous class's name is: " + getClass().getSimpleName() + a); String s = s1.toUpperCase() + s2.toUpperCase(); System.out.println(s); return s; } }; a++; System.out.println("AnotherClass name is: " + getClass().getSimpleName()); return Main.doStuff(up, "String1", "String2"); } } }

Here you can see a trick how to get a first name form Jon Johnson String.

employee.getName().substring(0, employee.getName().indexOf(" "));

A trick with subString. How to get a last name from String "John Johnson" ?

employees.forEach(employee -> { String lastName = employee.getName().substring(employee.getName().indexOf(" ") + 1); System.out.println("Last name: " + lastName); });

a is declared as final so we will not have the previous error anymore. We need to remove a ++ since it is final. The second way to correct the error is to remove a++ without declaring as a final variable.

final class AnotherClass { public String doSomething() { final int a = 22; { UpperConcat up = new UpperConcat() { @Override public String upperAndConcat(String s1, String s2) { System.out.println("The anonymous class's name is: " + getClass().getSimpleName() + a); String s = s1.toUpperCase() + s2.toUpperCase(); System.out.println(s); return s; } }; System.out.println("AnotherClass name is: " + getClass().getSimpleName()); return Main.doStuff(up, "String1", "String2");

We can solve the previous problem like this:

for (int i = 0; i < employees.size(); i++) { Employee employee = employees.get(i); System.out.println(employee.getName()); new Thread(() -> { System.out.println("Age: " + employee.getAge()); }).start(); }

Another example, here needs to be final or effectively final, but that is not possible since it is an iterator.

for (int i = 0; i < employees.size(); i++) { System.out.println(employees.get(i).getName()); new Thread(() -> { System.out.println("Age: " + employees.get(i).getAge()); }).start(); }

Picture to see:

https://drive.google.com/uc?export=download&id=1MF9fCP1oZ0MvYIRE3SF9Sd_hanaCsxbD

Create an interface:

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

JavaFX and Lambdas <Button fx:id="clickMeButton" text="Click me!" GridPane.columnIndex="0" GridPane.rowIndex="0"/>

public Button clickMeButton; public void initialize() { clickMeButton.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("Clicked!"); } }); }

Create a method:

public final static String doStuff(UpperConcat up, String s1, String s2) { return up.upperAndConcat(s1, s2); }

We need to use the test( ) method instead of the if block if we are using a predicate. We can pass a new Predicate as a lambda expression or as an anonymous class.

public static void printByAge(List<Employee> employees, String ageText, Predicate<Employee> ageCondition) { System.out.println(ageText); System.out.println("****************"); for (Employee employee : employees) { if (ageCondition.test(employee)) { System.out.println(employee.getName() + " : " + employee.getAge()); } } }

Another example, here b needs to be final or effectively final.

public void printValue() { int b = 22; Runnable r = () -> { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("The value of b is: " + b++); }; }

All methods presented here are the part of the collection class. forEach is called the terminal operation because it doesn't return anything(void) or a non-stream result and that creates the end of the stream pipe. Other methods here are called intermediate operation since they provide a return value to continue the stream pipe.

someBingoNumbers .stream() .map(String::toUpperCase) .filter(s -> s.startsWith("G")) .sorted() .forEach(System.out::println); }


Related study sets

Neurotransmitters and Drugs (Pt 2 of 2)

View Set

Nombre: Clases, género y número

View Set

Separation of Powers & Federalism

View Set

NUTR 132 Ch. 14 Nutrition During Pregnancy and Breastfeeding - Learn Smart

View Set

Quadrilateral Proofs 2.06 FLVS (100%)

View Set

Christ and His Everlasting Gospel Unit 3

View Set

FCS 202 Chapter 2 Quiz questions

View Set