Lambda expression best practices

Introduction

The functional programming framework introduced by Lambda Expression java 8. In the previous article we also talked about the basic usage of Lambda expressions.

This article will explain the best practice experience of Lambda expression in practical application based on previous articles in more detail.

Prefer to use the standard Functional interface

As mentioned in the previous article, java defines many Function interfaces in the java.util.function package. Basically covers all types we can think of.

If we customize the following Functional interface:

@FunctionalInterface
public interface Usage {
    String method(String string);
}

Then we need to pass in the interface in a test method:

public String test(String string, Usage usage) {
    return usage.method(string);
}

The function interface we defined above needs to implement the method method, receiving a String and returning a String. So we can use Function instead:

public String test(String string, Function<String, String> fn) {
    return fn.apply(string);
}

The advantage of using a standard interface is that you don't reinvent the wheel.

Use @FunctionalInterface annotation

Although @FunctionalInterface is not necessary, a Functional Interface can be defined without @FunctionalInterface.

But using @FunctionalInterface can alarm when it violates the definition of Functional Interface.

If you are maintaining a large project, the @FunctionalInterface annotation can clearly let others understand the role of this class.

This makes the code more standardized and usable.

So we need to define it like this:

@FunctionalInterface
public interface Usage {
    String method(String string);
}

Instead of:

public interface Usage {
    String method(String string);
}

Do not abuse Default Methods in Functional Interfaces

Functional Interface refers to an interface that has only one unimplemented abstract method.

If there are multiple methods in the Interface, you can use the default keyword to provide a default implementation for it.

But we know that Interface can inherit more than one, a class can implement multiple Interface. If the same default method is defined in multiple Interfaces, an error will be reported.

Generally speaking, the default keyword is generally used in upgrade projects to avoid code errors.

Use Lambda expressions to instantiate the Functional Interface

Or the above example:

@FunctionalInterface
public interface Usage {
    String method(String string);
}

To instantiate Usage, we can use the new keyword:

Usage usage = new Usage() {
    @Override
    public String method(String string) {
        return string;
    }
};

But the best way is to use lambda expressions:

Usage usage = parameter -> parameter;

Do not rewrite the method of Functional Interface as a parameter

How to understand? We look at the following two methods:

public class ProcessorImpl implements Processor {
    @Override
    public String process(Callable<String> c) throws Exception {
        // implementation details
    }
 
    @Override
    public String process(Supplier<String> s) {
        // implementation details
    }
}

The method names of the two methods are the same, only the parameters passed in are different. But both parameters are Functional Interface, and can be expressed with the same lambda expression.

When calling:

String result = processor.process(() -> "test");

Because you can't tell which method is called, you will get an error.

The best way is to change the names of the two methods to different ones.

Lambda expressions and inner classes are different

Although we mentioned earlier that using lambda expressions can replace inner classes. But the scope of the two is different.

In the inner class, a new scope will be created. Within this scope, you can define a new variable, and you can refer to it with this.

However, in the Lambda expression, there is no new scope defined. If you use this in the Lambda expression, it refers to the external class.

Let's take an example:

private String value = "Outer scope value";

public String scopeExperiment() {
    Usage usage = new Usage() {
        String value = "Inner class value";
 
        @Override
        public String method(String string) {
            return this.value;
        }
    };
    String result = usage.method("");
 
    Usage usageLambda = parameter -> {
        String value = "Lambda value";
        return this.value;
    };
    String resultLambda = usageLambda.method("");
 
    return "Results: result = " + result + 
      ", resultLambda = " + resultLambda;
}

The above example will output "Results: result = Inner class value, resultLambda = Outer scope value"

Lambda Expression is as concise as possible

Generally speaking, one line of code is enough. If you have a lot of logic, you can encapsulate the logic into a method and call the method in the lambda expression.

Because lambda expressions are ultimately expressions, the shorter the expression, the better.

Java uses type inference to determine the type of the incoming parameter, so we try not to pass the parameter type in the parameters of the lambda expression, as follows:

(a, b) -> a.toLowerCase() + b.toLowerCase();

Instead of:

(String a, String b) -> a.toLowerCase() + b.toLowerCase();

If there is only one parameter, no parentheses are required:

a -> a.toLowerCase();

Instead of:

(a) -> a.toLowerCase();

The return value does not need to bring return:

a -> a.toLowerCase();

Instead of:

a -> {return a.toLowerCase()};

How to use

To make the lambda expression more concise, we can use method references when we can use method references:

a -> a.toLowerCase();

Can be replaced with:

String::toLowerCase;

Effectively Final Variable

If a non-final variable is referenced in a lambda expression, an error will be reported.

What does effectively final mean? This is an approximate final meaning. As long as a variable is only assigned once, the compiler will treat the variable as effectively final.

    String localVariable = "Local";
    Usage usage = parameter -> {
         localVariable = parameter;
        return localVariable;
    };

In the above example, localVariable is assigned twice, so it is not an Effectively Final variable, and it will compile and report an error.

Why should it be set this way? Because lambda expressions are usually used in parallel calculations, when multiple threads access variables at the same time, Effectively Final variables can prevent unexpected changes.

in conclusion

Lambda is a very useful function, I hope my friends can master it at work.

Welcome to pay attention to my public number: those things of the program, more exciting waiting for you!
For more information, please visit www.flydean.com

Published 168 original articles · praised 177 · 470,000 views

Guess you like

Origin blog.csdn.net/superfjj/article/details/105649643