functional programming 1
TRANSCRIPT
Functional Programming
Lambda expressions in Java 8
Functional Programming
• What is Functional Programming and Predicate (example from predicates logics of the first order).
• It’s properties and peculiarities (no states and passing the control, one big function, no cycles)
Functional Programming - Definition
• Функційне програмування є способом створення програм, в яких єдиною дією є виклик функції, єдиним способом розбиття програми є створення нового імені функції та задання для цього імені виразу, що обчислює значення функції, а єдиним правилом композиції є оператор суперпозиції функцій. Жодних комірок пам'яті, операторів присвоєння, циклів, ні, тим більше, блок-схем чи передачі управління.
Determine if number is prime (простое)
1. Write in good old Java
2. Write in Lambdas
IsPrime (imperative)/* * Imperative - how we do it * is mutable */private static boolean isPrimeImperative(final int number) { for (int i = 2; i < number; i++) { if (number % i == 0) return false; } return true;}
IsPrime (declarative)/* * Declarative - what we do * is immutable */private static boolean isPrimeDeclarative(final int number) { return IntStream.range(2, number).noneMatch(i -> number % i == 0);}
Get first doubled number greater than 3
1. Imperative style
2. Declarative style using list Arrays.asList(1, 2, 5, 4, 6, 5, 4, 3, 8)
3. Make inner methods
4. Add sout to methods to see amount of steps
5. Make method excluding findFirst().get() and explain lazy initialisation.
6. Show other ways to address to methods inside of others (through lightbulb)
7. Students try on their own do similar with IntStream
Get first doubled number greater than 3
Declarativeprivate static int getEvenDoubledGreaterThanList(List<Integer> values, final int number) { return values.stream() .filter(i -> i > number) .filter(i -> i % 2 == 0) .map(i -> 2 * i) .findFirst().get();
Get first doubled number greater than 3 Declarative
with functionsprivate static int getEvenDoubledGreaterThanListSample(List<Integer> values, final int number) { return getEvenDoubleGreaterThan3Stream(values) .findFirst().get();}
private static Stream<Integer> getEvenDoubleGreaterThan3Stream(List<Integer> values) { return values.stream() .filter(FunctionalProgramming::isGreaterThan3 ) .filter(FunctionalProgramming::isEven) .map(FunctionalProgramming::doubleNumber);}
private static Function<Integer, Integer> multiplyBy2() { return i -> 2 * i;}
private static int doubleNumber(int number){ System.out.printf("\nLet's double -> " + number); return number * 2;}
private static Predicate<Integer> isEven() { return i -> i % 2 == 0;}
private static boolean isEven(Integer number) { System.out.printf("\nIs even -> " + number); return number % 2 == 0;}
private static boolean isGreaterThan3(Integer number) { System.out.printf("\nIs greater than 3 -> " + number); return number > 3;}
Get first doubled number greater than 3 with
IntStreamprivate static int getEvenDoubledGreaterThan(final int number) { return IntStream.range(number + 1, 100) .filter(i -> i % 2 == 0) .map(i -> 2 * i) .findFirst() .getAsInt();}
Interface with one method
1. Create an interface with one boolean method.
2. Write realisation of the method: static OneMethodInterface cond1 = e -> e > 2;
3. Use it in filter
4. Students create similar stuff but with integer method: public int condition1 (int element);
Interface with one method Implementation
public class Interfaces {// static OneMethodInterface cond1 = e -> e > 2; static OneMethodInterface cond2 = e -> e % 2; public static void main(String[] args) { call(cond2); }
private static void call(OneMethodInterface interf) { // Stream.of(1, 3,2, 6,3,8).filter(i -> interf.condition(i)).forEach(i -> System.out.println(i)); // Stream.of(1, 3,2, 6,3,8).filter(interf::condition).forEach(i -> System.out.println(i)); Stream.of(1, 3,2, 6,3,8).map(interf::condition1).forEach(System.out::println);
} public interface OneMethodInterface { // public boolean condition (int element); public int condition1 (int element); }}
Dependency Injection Using Strategy Pattern
Strategy Pattern in Old Java
1. Task: count total of List of integers
2. Add if statement to pick which values to sum using interface.
3. Create a Selector interface with one boolean method pick(int) and add it to total parameters.
4. Write realisation for the interface.
Strategy Pattern in Old Java Implementation
public class InterfacesDI1 {
public static void main(String[] args) { System.out.println(totalValues(Arrays.asList(1, 5, 3, 2, 8), new EvenSelector())); }
public static int totalValues(List<Integer> values, Selector selector){ int sum = 0; for (Integer value : values) { if(selector.pick(value)) sum +=value; }return sum; } interface Selector{ public boolean pick(int element);
} static class EvenSelector implements Selector{
@Override public boolean pick(int element) { return element % 2 == 0; } }}
Strategy Pattern in lambdas
1. Task: count total of List of integers
2. Change interface for Predicate
3. Write realisation of it’s test method instead of pick and use it
4. Rewrite total method into lambdas
5. Delete redundant
Strategy Pattern in lambdas Implementationpublic class InterfacesDI2 {
public static void main(String[] args) { System.out.println(totalValues(Arrays.asList(1, 5, 3, 2, 8), e -> true)); System.out.println(totalValues(Arrays.asList(1, 5, 3, 2, 8), e -> e % 2 == 0));
}
public static int totalValues(List<Integer> values, Predicate<Integer> selector) { return values.stream().filter(selector).reduce(0, Math::addExact); }}
TDD + flatMap
1. Task: using TDD write Developer object with name and list of languages.
2. Create several developer objects3. Make a team4. Collect all the languages they know
TDD + flatMap Implementation
public class FlatMapTest { public static void main(String[] args) { FlatMapTest flatMapTest = new FlatMapTest(); flatMapTest.flatMap(); } @Test public void flatMap() { List<Developer> team = new ArrayList<>(); Developer polyglot = new Developer("esoteric"); polyglot.add("clojure"); polyglot.add("scala"); polyglot.add("groovy"); polyglot.add("go");
Developer busy = new Developer("pragmatic"); busy.add("java"); busy.add("javascript");
team.add(polyglot); team.add(busy);
List<String> teamLanguages = team.stream(). map(d -> d.getLanguages()). flatMap(l -> l.stream()). collect(Collectors.toList()); System.out.println(teamLanguages); }
private class Developer { String name; List<String> langs = new LinkedList<>();
public Developer(String name) { this.name = name; }
private void add(String lang) { langs.add(lang); }
private List<String> getLanguages() { return this.langs; } }}
Instance of public static void tryInstanceOf() { List<String> strings = Stream.of(1, 2.03, "Petit France", 3).filter(String.class::isInstance).map(String.class::cast).collect(Collectors.toList()); System.out.println("This is list " + strings); String string = Stream.of(1, 2.03, "Petit France", 3).filter(String.class::isInstance).map(String.class::cast).collect(Collectors.joining(",")); System.out.println("This is string " + string); Stream.of(1, 2.03, "Petit France", 3).filter(String.class::isInstance).map(String.class::cast).forEach(e -> System.out.println("This is string in lambdas for each " + e)); Stream.of(1, 2.03, "Petit France", 3).filter(Integer.class::isInstance).map(Integer.class::cast).forEach(System.out::println); Stream.of(1, 2.03, "Petit France", 3).filter(e -> e instanceof Double).map(e -> (Double) e).forEach(System.out::println);}
Home work• Copy-paste method in the task on this link in
your code http://stackoverflow.com/questions/25439277/lambdas-multiple-foreach-with-casting
• Implement it using TDD
• Rewrite it into lambdas
• Check yourself
Maps + Sort1. Create a map and feel it with values
2. Try to sort it by values
3. Add writing to LinkedHashMap
collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1, LinkedHashMap::new)));
4. Look https://docs.oracle.com/javase/tutorial/collections/interfaces/map.html
Maps + Sort Example public static void main(String[] args) { Map<Integer, String> map = new LinkedHashMap<>(); map.put(2, "2"); map.put(3, "3"); map.put(1, "1");
map.entrySet().stream().forEach(System.out::println);// map.entrySet().stream().forEach(e -> System.out.println(e));
System.out.println(map); System.out.println((Object) map.entrySet().stream().sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())). collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2, LinkedHashMap::new))); }
Homework for sorting
• Sort the cities and apartments in them in order of having the nearest free apartment starting form the given date.
Supplier or Lazy initialisation + empty
parameter1. Write method <R> R use(Supplier<R> mapper)
2. Use mapper.get in it
3. Write methods that use the method in the way use(() -> {…return …});
4. Try return nothing
5. Return different parameters in «use» method and in the method that uses «use».
Consumer and other types of functions.
• Takes an argument and returns nothingTypes of functions in Java 8
Immutable and Mutable1. Don't provide "setter" methods — methods that modify fields or objects
referred to by fields.
2. Make all fields final and private.
3. Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final. A more sophisticated approach is to make the constructor private and construct instances in factory methods.
4. If the instance fields include references to mutable objects, don't allow those objects to be changed:- Don’t provide methods that modify the mutable objects.
-Don’t share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.