+ - 0:00:00
Notes for current slide

Toggle speaker view by pressing P

Pressing C clones the slideshow view, which is the view to put on the projector if you're using speaker view.

Press ? to toggle keyboard commands help.

Notes for next slide

Functional Programming

Toggle speaker view by pressing P

Pressing C clones the slideshow view, which is the view to put on the projector if you're using speaker view.

Press ? to toggle keyboard commands help.

OO versus Functional

  • Object-oriented: group data with operations

OO versus Functional

  • Object-oriented: group data with operations
  • Functional: treat operations as data

OO

  • modular and encapsulated
  • Code reuse through inheritance and composition
  • Functionality and data tightly coupled

Functional

  • Can define functionality and pass it as a parameter
  • Well suited for concurrent and event driven

Java 8

Added many functional features

Functional Characteristics

  • Function call can be replace by the result

Functional Characteristics

  • Function call can be replace by the result
  • Functions are not allowed to have side effects

Functional Characteristics

  • Function call can be replace by the result
  • Functions are not allowed to have side effects
  • Compiler is allowed to rearrange function invocations

Functional Characteristics

  • Function call can be replace by the result
  • Functions are not allowed to have side effects
  • Compiler is allowed to rearrange function invocations... or run on different threads

Functional Characteristics

  • Function call can be replace by the result
  • Functions are not allowed to have side effects
  • Compiler is allowed to rearrange function invocations... or run on different threads
  • Program flow driven by data dependencies, not order of instructions
  • Data must be immutable
  • If changed, new copy is created

First-Class Functions

Functions can be

  • Assigned to variables

First-Class Functions

Functions can be

  • Assigned to variables
  • Passed as arguments to other functions

First-Class Functions

Functions can be

  • Assigned to variables
  • Passed as arguments to other functions
  • Returned by other functions

Lambda Functions

Button button = new Button("Run");
button.setOnAction(event -> run(event));

Lambda Functions

Button button = new Button("Run");
button.setOnAction(event -> run(event));
  • run(event) is a function that is passed to a method

Lambda Functions

Button button = new Button("Run");
button.setOnAction(event -> run(event));
  • run(event) is a function that is passed to a method
  • Under the hood it is really the implementation of an interface

Lambda Functions

Button button = new Button("Run");
button.setOnAction(event -> run(event));
  • run(event) is a function that is passed to a method
  • Under the hood it is really the implementation of an interface
Button button = new Button("Run");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
private void handle(ActionEvent event) {
run(event);
}});

Functional Interface

@FunctionalInterface
public interface EventHandler<T> {
void handle(T event);
}
  • An interface with only one method

Functional Interface

@FunctionalInterface
public interface EventHandler<T> {
void handle(T event);
}
  • An interface with only one method
  • Annotated as a @FunctionalInterface

Functional Interface

@FunctionalInterface
public interface EventHandler<T> {
void handle(T event);
}
  • An interface with only one method
  • Annotated as a @FunctionalInterface
  • Can use lambda expression

Functional Interface

@FunctionalInterface
public interface EventHandler<T> {
void handle(T event);
}
  • An interface with only one method
  • Annotated as a @FunctionalInterface
  • Can use lambda expression
    EventHandler<ActionEvent> handler = event -> run(event);

Collection and Stream Interfaces

  • Collection
    • Efficient management of and access to their elements

Collection and Stream Interfaces

  • Collection
    • Efficient management of and access to their elements
  • Stream
    • A sequence of elements supporting sequential and parallel aggregate operations

Collection and Stream Interfaces

  • Collection
    • Efficient management of and access to their elements
  • Stream
    • A sequence of elements supporting sequential and parallel aggregate operations
    • A declarative description of their source and computational operations which will be performed in aggregate on that source

Stream Methods

  • count() - returns the number of elements in the stream
  • distinct() - returns a stream with duplicates removed
  • limit(long maxSize) - returns a stream with no more than maxSize elements
  • skip(long count) - returns a stream without the first count elements
  • sorted() - returns a stream in sorted order

Example - count() and distinct()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
long count = words.stream()
.count();
long numberUnique = words.stream()
.distinct()
.count();
System.out.println("Count: " + count + " Unique: " + numberUnique);

Example - count() and distinct()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
long count = words.stream()
.count();
long numberUnique = words.stream()
.distinct()
.count();
System.out.println("Count: " + count + " Unique: " + numberUnique);

Output:

Count: 6 Unique: 4

Higher-Order Functions

  • Accept other functions as argument(s)
  • Return a function as a result

Higher-Order Functions

  • Accept other functions as argument(s)
  • Return a function as a result
  • E.g., setOnAction(EventHandler<ActionEvent> e)

Higher-Order Functions in Stream

  • allMatch(Predicate<? super T> predicate)
  • anyMatch(Predicate<? super T> predicate)
  • noneMatch(Predicate<? super T> predicate)
  • filter(Predicate<? super T> predicate)

Predicate Interface

@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}

^* Not showing default methods

Higher-Order Functions in Stream ... again

  • allMatch(Predicate<? super T> predicate)
  • anyMatch(Predicate<? super T> predicate)
  • noneMatch(Predicate<? super T> predicate)
  • filter(Predicate<? super T> predicate)

Example - filter()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
Predicate<String> isShort = (word -> word!=null && word.length()<5);
Object[] shortWords = words.stream()
.filter(isShort)
.toArray();
for(Object word : shortWords) {
System.out.print(word + " ");
}
System.out.println();

Example - filter()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
Predicate<String> isShort = (word -> word!=null && word.length()<5);
Object[] shortWords = words.stream()
.filter(isShort)
.toArray();
for(Object word : shortWords) {
System.out.print(word + " ");
}
System.out.println();

Output:

a that a

More Higher-Order Functions in Stream

  • map(Function<? super T, ? extends R> mapper)
  • mapToDouble(Function<? super T> mapper)
  • mapToInt(Function<? super T> mapper)

Function Interface

@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}

^* Not showing default methods

Example - map()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
List<String> lengths = words.stream()
.map(word -> word + ": " + word.length())
.collect(Collectors.toList());
System.out.println(lengths);

Example - map()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
List<String> lengths = words.stream()
.map(word -> word + ": " + word.length())
.collect(Collectors.toList());
System.out.println(lengths);

Alternative:

Function<String, String> toLength = (word -> word + ": " + word.length());
words.stream().map(toLength);

Example - map()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
List<String> lengths = words.stream()
.map(word -> word + ": " + word.length())
.collect(Collectors.toList());
System.out.println(lengths);

Alternative:

Function<String, String> toLength = (word -> word + ": " + word.length());
words.stream().map(toLength);

Output:

[a: 1, function: 8, that: 4, returns: 7, a: 1, function: 8]

Numeric Streams

IntStream, DoubleStream, and LongStream

  • sum()
  • max()
  • min()
  • average()
  • summaryStatistics()
  • reduce()

Example - mapToInt()

int sum = words.stream()
.mapToInt(w -> w.length());
.sum();

Example - mapToInt()

int sum = words.stream()
.mapToInt(w -> w.length());
.sum();

Output:

Sum of lengths of all strings: 29

Consumer Interface

@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}

^* Not showing default methods

Example - forEach()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
words.stream()
.forEach(w -> System.out.println(w + ": " + w.length()));

Example - forEach()

List<String> words = Arrays.asList("a", "function", "that", "returns", "a", "function");
words.stream()
.forEach(w -> System.out.println(w + ": " + w.length()));

Output:

a: 1
function: 8
that: 4
returns: 7
a: 1
function: 8

Note: we can do forEach() directly on a List:

words.forEach(w -> System.out.println(w + ": " + w.length()));

Extract Even Numbers

Stream<Integer> numbers = Stream.of(3, 8, 7, 2, 1, 9, 8);
List<Integer> evens = numbers.filter(i -> i%2==0)
.collect(Collectors.toList());
System.out.println(evens);

Extract Even Numbers

Stream<Integer> numbers = Stream.of(3, 8, 7, 2, 1, 9, 8);
List<Integer> evens = numbers.filter(i -> i%2==0)
.collect(Collectors.toList());
System.out.println(evens);

Output:

[8, 2, 8]

Extract Based on Suffix

System.out.println(Stream.of("happy", "discussion" /* ... */, "locomotion")
.filter(word -> word.endsWith("tion"))
.count());

Extract Based on Suffix

System.out.println(Stream.of("happy", "discussion" /* ... */, "locomotion")
.filter(word -> word.endsWith("tion"))
.count());

Output:

1

Extract Circles

Stream<Shape> shapes = Stream.of(new Circle(0, 0), new Square(0, 0, 4), new Circle(0, 0),
new Triangle(0, 0, 1, 5));
List<Circle> circles = shapes.filter(shape -> shape instanceof Circle)
.map(shape -> (Circle)shape)
.collect(Collectors.toList());

Sum

double totalArea = shapes.mapToDouble(shape -> shape.getArea())
.sum();
System.out.println("Total area: " + totalArea);

Sum

double totalArea = shapes.mapToDouble(shape -> shape.getArea())
.sum();
System.out.println("Total area: " + totalArea);

Output:

Total area: 38.239208802178716

Average

OptionalDouble averageArea = shapes.mapToDouble(Shape::getArea)
.average();
if(averageArea.isPresent()) {
System.out.println("Average area: " + averageArea.getAsDouble());
}

Average

OptionalDouble averageArea = shapes.mapToDouble(Shape::getArea)
.average();
if(averageArea.isPresent()) {
System.out.println("Average area: " + averageArea.getAsDouble());
}

Output:

Average area: 9.559802200544679

Summary Statistics

DoubleSummaryStatistics areaStats = shapes.mapToDouble(Shape::getArea)
.summaryStatistics();
System.out.println("Number of shapes: " + areaStats.getCount());
System.out.println("Total area: " + areaStats.getSum());
System.out.println("Average area: " + areaStats.getAverage());
System.out.println("Maximum area: " + areaStats.getMax());
System.out.println("Minimum area: " + areaStats.getMin());

Summary Statistics

DoubleSummaryStatistics areaStats = shapes.mapToDouble(Shape::getArea)
.summaryStatistics();
System.out.println("Number of shapes: " + areaStats.getCount());
System.out.println("Total area: " + areaStats.getSum());
System.out.println("Average area: " + areaStats.getAverage());
System.out.println("Maximum area: " + areaStats.getMax());
System.out.println("Minimum area: " + areaStats.getMin());

Output:

Number of shapes: 4
Total area: 38.239208802178716
Average area: 9.559802200544679
Maximum area: 16.0
Minimum area: 2.5

Average with reduce()

double area = shapes.map(Shape::getArea)
.reduce(0.0, (a, b) -> a+b);
System.out.println("Total area: " + area);

Average with reduce()

double area = shapes.map(Shape::getArea)
.reduce(0.0, (a, b) -> a+b);
System.out.println("Total area: " + area);

Output:

Total area: 38.239208802178716

OO versus Functional

  • Object-oriented: group data with operations
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow