Type inference and lambda expressions in Java

brief introduction

Java is a strongly typed programming language. Each variable used in Java needs to define its type, otherwise it will fail to compile. The advantage of strongly typed language is that it can find possible problems in the code during compilation, so as to reduce the possibility of problems at run time.

In contrast, the disadvantage of strongly typed languages is that they are not so flexible and redundant.

Before jdk8, Java did not support type inference. In jdk8, lambda expressions were introduced, which resulted in type inference.

This article will explain the best practice of type inference in lambda expressions and the matters needing attention in its use.

More highlights:

Display use of type

Suppose we define a custuser class with age and name attributes:

@Data
@AllArgsConstructor
public class CustUser {
    int age;
    String name;
}

Let's see how to display usage types in stream:

public static void testStream(){
        Stream.of(new CustUser(10,"alice"),new CustUser(20,"bluce"))
                .forEach( (CustUser custUser)-> System.out.println(custUser.name));
    }

In the above example, we build a stream of custuser type and process custuser in the foreach method.

Foreach receives a consumer object. The consumer needs to implement the void accept (T) method. Because of the consumer function interface, we can use lambda expressions instead.

Here, we show that a custuser type is passed in. Code compilation is no problem, but it seems a little complicated. Next, let's look at how to use type inference in stream.

Type inference in stream

The above example can be rewritten as follows:

public static void testInference(){
        Stream.of(new CustUser(10,"bluce"))
                .forEach(custUser-> System.out.println(custUser.name));
    }

Here we do not define the type of custuser, but Java can infer from the type in stream. So there is no problem writing this way. It can be compiled normally.

Importance of variable names in type inference

In the above example, we define the name of the variable as custuser. People who view the code can see at a glance that this parameter represents the custuser parameter of custuser type.

Meaningful names can greatly improve the readability and maintainability of the code. If you write this:

forEach(u-> System.out.println(u.name)

Although the code has become shorter, it has lost its readable meaning. At a glance, we don't know what your U represents, which affects the readability of the code.

Therefore, the definition of variable name must be meaningful.

Effect of type inference on Performance

Type inference is a good thing. Some students will ask, will type inference affect the performance of Java?

We can divide Java into two parts: compiling and running. Type inference is done during compilation. It may prolong the time of code compilation, but it has no impact on the efficiency of runtime.

Generally speaking, we focus on the performance of programs at run time rather than compile time, so type inference has no impact on performance.

Limitations of type inference

Although Java has type inference, this inference has certain limitations. It can't think like people, but it's smart enough. Here is an example:

public static Comparator<CustUser> createUser1(){
        return (CustUser user1,CustUser user2) -> user1.getAge() - user2.getAge();
    }

In the above example, we need to create a comparator. We can generate a comparator using lambda expression.

Comparator needs to implement the method int compare (t O1, t O2), pass in two parameters and return an int.

In the above example, we show that the type specifying the two parameters is custuser, and there is no problem with compilation.

Is it OK if the specified custuser type is not displayed?

public static Comparator<CustUser> createUser2(){
        return (user1,user2) -> user1.getAge() - user2.getAge();
    }

The answer is OK. In this example, we did not pass in user1 and user2. How did Java find the types of user1 and user2?

Note that in the above example, we defined that the return type is custuser, and Java infers that the actual type passed in is custuser through this return type. Isn't it smart.

If we split the above return statement into two, what will happen?

Comparator comparator=(user1,user2) -> user1.getAge() - user2.getAge();

At this time, the compiler will report an error, saying that the getage method cannot be found. This is because the comparator we returned does not specify the type, so it is the object type by default. Object type has no getage method, so an error is reported.

We can rewrite it this way:

Comparator<CustUser> comparator=(user1,user2) -> user1.getAge() - user2.getAge();

Compilation is complete with no errors.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>