Functional Programming in Java

Java 8 

1.Lambda expression

 

2.Functional Interface

 

3.Stream Operation

 

 Hello, Lambda Expressions!
 

 Change the Way You Think
 

 Imperative style—that’s what Java has provided us since its inception. In this style, we tell Java every step of what we want it to do and then we watch it faithfully exercise those steps. That’s worked fine, but it’s a bit low level.

The code tends to get verbose, and we often wish the language were a tad more intelligent;

we could then tell it—declaratively—what we want rather than
delve into how to do it. 

 

The Habitual Way:

Imperative way
 

boolean found = false;

for(String city : cities) {
    if(city.equals("Chicago")) {
    found = true;
    break;
    }
}
System.out.println("Found chicago?:" + found);

A Better way:

System.out.println("Found chicago?:" + cities.contains("Chicago"));

 Tangible Improvements

  •  No messing around with mutable variables
  • Iteration steps wrapped under the hood
  • Less clutter
  • Better clarity; retains our focus
  • Less impedance; code closely trails the business intent
  • Less error prone
  • Easier to understand and maintain

  Beyond Simple Case

final List<BigDecimal> prices = Arrays.asList(
new BigDecimal("10"), new BigDecimal("30"), new BigDecimal("17"),
new BigDecimal("20"), new BigDecimal("15"), new BigDecimal("18"),
new BigDecimal("45"), new BigDecimal("12"));

BigDecimal totalOfDiscountedPrices = BigDecimal.ZERO;
for(BigDecimal price : prices) {
    if(price.compareTo(BigDecimal.valueOf(20)) > 0)
    totalOfDiscountedPrices =
    totalOfDiscountedPrices.add(price.multiply(BigDecimal.valueOf(0.9)));
}
System.out.println("Total of discounted prices: " + totalOfDiscountedPrices);

 Suppose we’re asked to total the prices greater than $20, discounted by 10%.
Let’s do that in the habitual Java way first.

 

   A Better Way, Again

final BigDecimal totalOfDiscountedPrices =
prices.stream()
.filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
.map(price -> price.multiply(BigDecimal.valueOf(0.9)))
.reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println("Total of discounted prices: " + totalOfDiscountedPrices);

 The looping is concealed much like it was under the contains() method. The
map() method (and the filter() method), however, is more sophisticated. For each
price in the prices list, it invokes the provided lambda expression and puts the
responses from these calls into a new collection. The reduce() method is invoked
on this collection to get the final result.

 

Why Code in the Functional Style?

  •  Enforcing Policies
     
Transaction transaction = getFromTransactionFactory();
//... operation to run within the transaction ...
checkProgressAndCommitOrRollbackTransaction();
UpdateAuditTrail();
runWithinTransaction((Transaction transaction) -> {
//... operation to run within the transaction ...
});
  •  Telling the Story

 if the code reads more like the way the business states the problem, it becomes easier to read, easier to discuss with the business folks, and easier to evolve to meet their changing demands.
 

tickers.map(StockUtil::getprice).filter(StockUtil::priceIsLessThan500).sum()

Recap

 It’s a whole new world in Java. We can now program in an elegant and fluent functional style, with higher-order functions. This can lead to concise code that has fewer errors and is easier to understand, maintain, and parallelize.
The Java compiler works its magic so we can send lambda expressions or method references where functional interfaces are expected.

 

 Using Collections
 

 Iterating through a List
 

final List<String> friends =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");

for(int i = 0; i < friends.size(); i++) {
    System.out.println(friends.get(i));
}

 The Iterable interface has been enhanced in Java Development Kit (JDK) 8 with a special method named forEach(), which accepts a parameter of type Consumer.
 

friends.forEach(new Consumer<String>() {
    public void accept(final String name) {
        System.out.println(name);
    }
});
friends.forEach((final String name) -> 
    System.out.println(name));
friends.forEach((name) -> 
    System.out.println(name));
friends.forEach(System.out::println);

 Transforming a List

final List<String> uppercaseNames = new ArrayList<String>();
for(String name : friends) {
    uppercaseNames.add(name.toUpperCase());
}

 In this imperative style, we created an empty list then populated it with alluppercase names, one element at a time
 

 We used the internal iterator, but that still required the empty list and the effort to add elements to it. We can do a lot better.
 

final List<String> uppercaseNames = new ArrayList<String>();
friends.forEach(name -> uppercaseNames.add(name.toUpperCase()));
System.out.println(uppercaseNames);
friends.stream()
.map(name -> name.toUpperCase())
.forEach(name -> System.out.print(name + " "));

 The Stream’s map() method can map or transform a sequence of input to a sequence of output—that fits quite well for the task at hand.

  Using Method Reference

 We can nudge the code to be just a bit more concise by using a feature called
method reference. The Java compiler will take either a lambda expression or
a reference to a method where an implementation of a functional interface is
expected. With this feature, a short String::toUpperCase can replace name ->
name.toUpperCase()

friends.stream()
    .map(String::toUpperCase)
    .forEach(name -> System.out.println(name));

 Finding Element

 From a list of names, let’s pick the ones that start with the letter N. Since
there may be zero matching names in the list, the result may be an empty
list. Let’s first code it using the old approach.

final List<String> startsWithN = new ArrayList<String>();
for(String name : friends) {
    if(name.startsWith("N")) {
        startsWithN.add(name);
    }
}

 Let’s refactor this code to use the filter() method, and see how it changes things
 

final List<String> startsWithN =
    friends.stream()
        .filter(name -> name.startsWith("N"))
        .collect(Collectors.toList());

 Reusing Lambda Expression

final List<String> friends =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
final List<String> comrades =
Arrays.asList("Kate", "Ken", "Nick", "Paula", "Zach");
final List<String> editors =
Arrays.asList("Brian", "Jackie", "John", "Mike");
final long countFriendsStartN =
friends.stream().filter(name -> name.startsWith("N")).count();
final long countComradesStartN =
comrades.stream().filter(name -> name.startsWith("N")).count();
final long countEditorsStartN =
editors.stream().filter(name -> name.startsWith("N")).count();

 We want to filter out names that start with a certain letter. Let’s first take a naive approach to this using the filter() method.
 

 Let’s refactor the previous code to make it DRY.1 (See the Don’t Repeat Yourself—DRY—principle)
 

final Predicate<String> startsWithN = name -> name.startsWith("N");
final long countFriendsStartN =
friends.stream().filter(startsWithN).count();

  Duplication in Lambda Expressions

final Predicate<String> startsWithN = name -> name.startsWith("N");
final Predicate<String> startsWithB = name -> name.startsWith("B");
final long countFriendsStartN =
friends.stream().filter(startsWithN).count();
final long countFriendsStartB =
friends.stream().filter(startsWithB).count();

 Let’s pick the names that start with N or B from the friends collection of names.Continuing with the previous example, we may be tempted to write something
like the following:

 

 Removing Duplication with Lexical coping
 

public static Predicate<String> checkIfStartsWith(final String letter) {
    return name -> name.startsWith(letter);
}
final long countFriendsStartN =
friends.stream().filter(checkIfStartsWith("N")).count();
final long countFriendsStartB =
friends.stream().filter(checkIfStartsWith("B")).count();
 Java reaches over to the scope of the definition of this lambda expression and finds the variable letter in that scope. This is called lexical
scoping.  it’s also referred to as a closure

 Refactoring to Narrow the Scop

final Function<String, Predicate<String>> startsWithLetter =
(String letter) -> {
    Predicate<String> checkStartsWith =
        (String name) -> name.startsWith(letter);
    return checkStartsWith;
};

 In the preceding (smelly) example we used a static method, but we don’t want to pollute the class with static methods to cache each variable in the future.
It would be nice to narrow the function’s scope to where it’s needed. We can
do that using a Function class.

  Our examples illustrate how to pass functions to functions, create functions within functions,and return functions from within functions. 
 

final Function<String, Predicate<String>> startsWithLetter =
letter -> name -> name.startsWith(letter);

final long countFriendsStartN =
friends.stream().filter(startsWithLetter.apply("N")).count();

final long countFriendsStartB =
friends.stream().filter(startsWithLetter.apply("B")).count();

 Picking an Element
 

public static void pickName(
    final List<String> names, 
        final String startingLetter) {

        String foundName = null;
        for(String name : names) {
            if(name.startsWith(startingLetter)) {
                foundName = name;
                break;
            }
        }

    System.out.print(
        String.format("A name starting with %s: ", 
            startingLetter));

    if(foundName != null) {
        System.out.println(foundName);
    } else {
        System.out.println("No name found");
    }

}
public static void pickName(
final List<String> names, final String startingLetter) {

    final Optional<String> foundName =
    names.stream()
    .filter(name ->name.startsWith(startingLetter))
    .findFirst();

    System.out.println(
        String.format("A name starting with %s: %s",
        startingLetter, foundName.orElse("No name found")
        )
    );
}

FP List

public static final class NonEmptyList<T> implements List<T> {
  public T head() { return _head; }
  public List<T> tail()  { return _tail; } 
  public boolean isEmpty() { return false; }
  protected NonEmptyList(T head, List<T> tail) {
    this._head = head; 
    this._tail = tail;
  }
  private final T _head; 
  private final List<T> _tail;
  @Override
  public boolean equals(Object other) {
    if (other == null || getClass() != other.getClass()) return false;
    List<?> that = (List<?>) other;
    return head().equals(that.head()) && tail().equals(that.tail()); 
  }
  @Override
  public int hashCode() { 
    return 37*(head().hashCode()+tail().hashCode()); 
  }
  
  @Override
  public String toString() { 
    return "(" + head() + ", " + tail() + ")"; 
    }
}

FP List(filter,map,fold)

public static final class NonEmptyList<T> implements List<T> {
  public List<T> filter (Function1<T,Boolean> f) { 
    if (f.apply(head())) {
      return list(head(), tail().filter(f)); 
    } else {
      return tail().filter(f); 
    }
  }
  
  public <T2> List<T2> map (Function1<T,T2> f) {
    return list(f.apply(head()), tail().map(f));
  }
  
  public <T2> T2 foldLeft (T2 seed, Function2<T2,T,T2> f) { 
    return tail().foldLeft(f.apply(seed, head()), f);
  }
  
  public <T2> T2 foldRight (T2 seed, Function2<T,T2,T2> f) { 
    return f.apply(head(), tail().foldRight(seed, f));
  }
  
  public void foreach (Function1Void<T> f) { 
    f.apply(head());
    tail().foreach(f);
  } 
  
}

 Starter Set of Functional Interfaces
 

 Description Represents an operation that will accept an input
and returns nothing.
 Abstract method  accept()
 Default method(s)  andThen()
 Popular usage As a parameter to the forEach() method
 Primitive specializations  IntConsumer, LongConsumer, DoubleConsumer, …

 Consumer<T>
 

 Description  A factory that’s expected to return either a new
instance or a precreated instance
 Abstract method   get()
 Default method(s) --
 Popular usage  To create lazy infinite Streams 
 Primitive specializations  IntSupplier, LongSupplier, DoubleSupplier, …

  Supplier<T>

 Description  Useful for checking if an input argument satisfies
some condition
 Abstract method  test()
 Default method(s)  and(), negate(), and or()
 Popular usage   As a parameter to Stream’s methods, like filter() and anyMatch()
 Primitive specializations  IntPredicate, LongPredicate, DoublePredicate, …

 Predicate<T>

 Description  A transformational interface that represents an operation intended to take in an argument and
return an appropriate result
 Abstract method  apply()
 Default method(s)   andThen(), compose()
 Popular usage  As a parameter to Stream’s map() method
 Primitive specializations  IntFunction, LongFunction, DoubleFunction, IntToDoubleFunction,
DoubleToIntFunction,

 Function<T, R>

Q&A