What is functional programming

I’m sure you’ve all used object-oriented programming languages. Object-oriented programming abstracts data, while functional programming abstracts behavior. Functional programming allows programmers to write code that is easier to read. So when is functional programming?

Functional programming is a programming methodology that involves writing behavior into functions.

What is a function?

The function processes the input value and returns another value.

Lambda expressions

Labmda expressions, introduced in Java 8, are an implementation of functional programming.

What is a Lambda expression? Let’s take an example

The following code would look like this if you were using Java 7:

  //sort using java 7
   private void sortUsingJava7(List<String> names){   
      Collections.sort(names, new Comparator<String>() {
         @Override
         public int compare(String s1, String s2) {
            returns1.compareTo(s2); }}); }Copy the code

Does the code need to implement an anonymous class seem complicated? Let’s rewrite this with a Java 8 lambda expression:

   //sort using java 8
   private void sortUsingJava8(List<String> names){ Collections.sort(names, (s1, s2) -> s1.compareTo(s2)); }}Copy the code

Where (s1, s2) -> s1.compareTo(s2) is the implementation of Comparator’s compare method.

Here we replace the anonymous Comparator class with a Lambda expression. Why can you do that? What anonymous classes can be replaced by Lambda expressions? Here we introduce a concept called functional interfaces.

A Lambda expression requires a functional interface as its corresponding type, and its method body is the implementation of the functional interface. Each Lambda expression of that interface type is matched to the abstract method of that interface.

@functionalinterface a FunctionalInterface

A function is an interface that includes the following characteristics:

  • Interfaces have one and only one abstract method
  • The interface allows you to define static methods
  • The interface allows you to define default methods
  • The interface allows public methods in java.lang.object

Let’s look at the implementation of the Comparator above:

@FunctionalInterface
public interface Comparator<T> {
 
    int compare(T o1, T o2);

    boolean equals(Object obj);

    default Comparator<T> reversed(a) {
        return Collections.reverseOrder(this);
    }

    default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return(res ! =0)? res : other.compare(c1, c2); }; }default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }

    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        return thenComparing(comparing(keyExtractor));
    }

    default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
        return thenComparing(comparingInt(keyExtractor));
    }

    default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
        return thenComparing(comparingLong(keyExtractor));
    }

    default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
        return thenComparing(comparingDouble(keyExtractor));
    }

   
    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder(a) {
        return Collections.reverseOrder();
    }

    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder(a) {
        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
    }

    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(true, comparator);
    }

   
    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {... }public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {... }public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {... }public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {... }public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {... }public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {... }}Copy the code

We can see that the Comparator interface has static methods, default methods, and Boolean equals(Object obj) from Object; There’s an abstract method that needs to be implemented int compare(T o1, T o2)

The default method is the latest keyword added to Java 8, indicating that the class implementing the interface should use the interface’s own method if it does not implement the method itself, which is mainly used for backward compatibility.

The JDK comes with some useful functional interfaces:

  • java.lang.Runnable,

  • java.awt.event.ActionListener,

  • java.util.Comparator,

  • java.util.concurrent.Callable

  • Interfaces under the java.util.function package, such as Consumer, Predicate, Supplier, etc

The format of a Lambda expression

In general, Lambda expressions look like this:

parameter -> expression body

Look at the following code:

    public static void main(String[] args) {
        Runnable noArguments = () -> System.out.println("Hello World");
        ActionListener oneArgument = event -> System.out.println("button clicked");
        Runnable multiStatement = () -> {
            System.out.print("Hello");
            System.out.println(" World");
        };
        BinaryOperator<Long> add = (x, y) -> x + y;
        BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;
    }
Copy the code

Here are some of the formats we often use in Lambda.

  • Format that contains no arguments

    Runnable noArguments = () -> System.out.println(“Hello World”);

  • Contains only one argument and can omit the parentheses

    ActionListener oneArgument = event -> System.out.println(“button clicked”);

  • The body of a Lambda is a block of code

    Runnable multiStatement = () -> { System.out.print(“Hello”); System.out.println(” World”); };

  • Multiple parameters

    BinaryOperator add = (x, y) -> x + y;

  • Explicitly specifies the type of the argument

    BinaryOperator addExplicit = (Long x, Long y) -> x + y;

All the argument types in Lambda expressions are inferred by the compiler. If the compiler cannot infer your parameter types, you need to specify them manually.

Method references

In the first example we looked at Lambda expressions like this:

Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
Copy the code

Where (s1, s2) -> s1.compareTo(s2) represents a comparison of two strings, calling the compareTo method of the String class. To express business logic more succinctly, you can replace Lambda expressions with method references.

Collections.sort(names, String::compareTo);
Copy the code

This is shorter and more concise than the original code.

There are three methods that can be cited:

  • A static method
  • Instance methods
  • Constructor methods that use new such as: (TreeSet::new)

See flydean’s blog for more tutorials