Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

An example Analysis of Java10 Local variable types

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces "Java10 local variable type example analysis". In daily operation, I believe many people have doubts about Java10 local variable type example analysis. The editor consulted all kinds of data and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts of "Java10 local variable type example analysis". Next, please follow the editor to study!

Context: platitudes and code readability

Maybe day after day, you don't have to do something over and over again. For example, in the following code (using the collection factory of Java 9), the type on the left may feel redundant and insipid.

Import static java.util.Map.entry;List cities = List.of ("Brussels", "Cardiff", "Cambridge") Map citiesPopulation= Map.ofEntries (entry ("Brussels", 1x 139000), entry ("Cardiff", 341000))

This is a very simple example, but it also confirms the traditional Java philosophy: you need to define static types for all contained simple expressions. Let's take a look at some complex examples. For example, the following code creates a bar chart from string to word. It uses the groupingBy collector to aggregate streams into the Map. The groupingBy collector can also use a classification function to establish a mapped key for the first parameter and the (counting ()) key of the second collector to calculate the number of associations. Here is an example:

String sentence = "A simple Java example that explores what Java10 has to offer"; Collector byOccurrence= groupingBy (Function.identity (), counting ()); Map wordFrequency= Arrays.stream (sentence.split (")) .subscription (byOccurrence)

It makes sense to extract complex expressions to a variable or method to improve the readability and reusability of the code. In this example, the logic for creating a bar chart uses a collector. Unfortunately, the result type from groupingBy is almost unreadable! There's nothing you can do about this. All you can do is observe.

The most important point is that when new class libraries are added to Java, they develop more and more generics, which puts extra pressure on developers to introduce more formulaic code (boilerplate code). The above example does not show that writing types is not good. It is clear that forcing operations that define types for variable and method signatures to be performed as a protocol that needs to be respected will be beneficial to maintenance and understanding. However, declaring a type for an intermediate expression may seem useless and redundant.

History of type inference

We have seen language designers add "type inference" to help us write more concise code many times in Java history. Type inference is an idea: the compiler can help you derive static types, and you don't have to specify them yourself.

Generic methods have been introduced since Java 5, and the parameters of generic methods can be derived from context. such as

This code:

List cs = Collections.emptyList ()

Can be simplified to:

List cs = Collections.emptyList ()

Then, in Java 7, type parameters can be omitted from the expression, as long as they can be determined by context. For example:

Map myMap = new HashMap ()

You can use the angle bracket operator to simplify to:

Map userChannels = new HashMap ()

In general, the compiler can infer types based on the surrounding context. In this example, it can be inferred from the left that HashMap contains a list of strings.

Starting with Java 8, the Lambda expression looks like this

Predicate nameValidation = (String x)-> x.length () > 0

The type can be omitted and written as

Predicate nameValidation = x-> x.length () > 0

Local variable type inference

As there are more and more types, it is possible that the generic parameter is another generic, in which case type derivation can enhance readability. The Scala and C # languages allow the type of local variables to be declared as var, and the compiler fills the appropriate type based on initialization statements. For example, a statement facing userChannels can be written like this:

Var userChannels = new HashMap ()

It can also be inferred from the return value of the method (the list is returned here):

Var channels = lookupUserChannels ("Tom"); channels.forEach (System.out::println)

This idea, called local variable type inference, has been introduced in Java 10!

For example, the following code:

Path path = Paths.get ("src/web.log"); try (Stream lines = Files.lines (path)) {long warningCount= lines.filter (line-> line.contains ("WARNING")). Count (); System.out.println ("Found" + warningCount + "warnings in thelog file");} catch (IOException e) {e.printStackTrace ();}

In Java 10, you can restructure something like this:

Var path = Paths.get ("src/web.log"); try (var lines = Files.lines (path)) {var warningCount= lines.filter (line-> line.contains ("WARNING")). Count (); System.out.println ("Found" + warningCount + "warnings in thelog file");} catch (IOException e) {e.printStackTrace ();}

Each expression in the above code is still a static type (that is, the type of value):

The type of the local variable path is Path variable lines is Stream variable warningCount is long

That is, if you assign different values to these variables, you will fail. For example, secondary assignments like the following can cause compilation errors:

Var warningCount = 5 warningCount = "6"; | Error: | incompatible types: java.lang.String cannot be converted to int | warningCount = "6"

However, there are some minor problems with type inference; if the classes Car and Bike are both subclasses of Vehicle, then declare

Var v = new Car ()

Is the type of v declared here Car or Vehicle? This case is easy to explain because the type of initializer (in this case Car) is very clear. Without an initializer, you cannot use var. Assign values like this later

V = new Bike ()

It can go wrong. In other words, var does not apply perfectly to polymorphic code.

So where should local variable type inference be used?

Under what circumstances will local type inference fail? You cannot use it in field and method signatures. It can only be used for local variables, for example, the following code is incorrect:

Public long process (var list) {}

You cannot use var to declare local variables without explicitly initializing them. That is, you cannot use the var syntax to declare a variable that has no assignment. The following code

Var x

This results in a compilation error:

| | Error: | cannot infer type for local variable x | (cannot use 'var' on variable without initializer) | var x; | ^-^ |

Nor can you initialize a variable declared by var to null. In fact, it is not clear what type it is before post-initialization.

| | Error: | cannot infer type for local variable x | (variable initializer is' null') | var x = null; | ^-^ |

You cannot use var in Lambda expressions because it requires an explicit target type. The following assignment is wrong:

Var x = ()-> {} | Error: | cannot infer type for local variable x | (lambda expression needs an explicit target-type) | var x = ()-> {}; | ^-^

However, the following assignment is valid because there is an explicit initialization on the right side of the equation.

Var list = new ArrayList ()

What is the static type of this list? The type of the variable is deduced to ArrayList, which completely loses the meaning of generics, so you may want to avoid this situation.

Infer types that cannot be represented (Non-Denotable Types)

There are a large number of unrepresentable types in Java-- these types exist in the program, but cannot accurately write their names. For example, anonymous classes are typically unrepresentable types. You can add fields and methods to anonymous classes, but you can't write the name of anonymous classes in Java code. Angle brackets operators cannot be used for anonymous classes, while var is slightly less restricted and can support types that cannot be expressed, namely anonymous classes and cross types.

The var keyword also allows us to use anonymous classes more effectively, which can refer to types that cannot be described. Generally speaking, you can add fields to anonymous classes, but you can't reference them anywhere else, because it requires variables to specify the name of the type when assigning values. For example, the following code cannot be compiled because the type of productInfo is Object, and you cannot access the name and total fields through the Object type.

Object productInfo = new Object () {String name = "Apple"; int total = 30;}; System.out.println ("name =" + productInfo.name + ", total =" + productInfo.total)

This limitation can be broken by using var. When an anonymous class object is assigned to a local variable declared with var, it infers the type of the anonymous class instead of treating it as its parent class type. Therefore, fields declared on anonymous classes can be referenced to.

Var productInfo = new Object () {String name = "Apple"; int total = 30;}; System.out.println ("name =" + productInfo.name + ", total =" + productInfo.total)

At first glance, this is just an interesting thing in the language, and it won't be of much use. But it does work in some cases. For example, when you want to return some values as intermediate results. In general, you will create and maintain a new class for this, but use it in only one method. For this reason, a decimal array of type double is used in the implementation of Collectors.averagingDouble ().

With var, we have a better way to deal with it-using anonymous classes to hold intermediate values. Now consider an example of some products, each with a name, inventory, and monetary value or value. We need to calculate the total price (quantity * value) of each item. This is the information we need to map each Product to its total price, but to make the information more meaningful, we also need to add the name of the product. The following example describes how to use var to achieve this in Java 10:

Var products = List.of (new Product (10,3, "Apple"), new Product (5,2, "Banana"), new Product (17,5, "Pear"); var productInfos = products.stream (). Map (product-> new Object () {String name = product.getName (); int total = product.getStock () * product.getValue ();}). ProductInfos.forEach (prod-> System.out.println ("name =" + prod.name + ", total =" + prod.total)); This outputs:name = Apple, total = 30name = Banana, total = 10name = Pear, total = 85

Not all types that cannot be represented can use var-it only supports anonymous classes and crossover types. Types matched by wildcards cannot be inferred, which prevents wildcard-related errors from being reported to Java programmers. The purpose of supporting unrepresentable types is to retain as much information as possible in inferred types so that people can take advantage of local variables and better ReFactor the code. The original intention of this feature is not for people to write code as in the example above, but to use var to simplify dealing with problems related to types that cannot be represented. It is not known whether var will be used to deal with the details of types that cannot be expressed in the future.

Type inference recommendation

Type inference does help you write Java code quickly, but what about readability? Developers spend about 10 times as much time reading code as they do writing code, so they should make it easier to read rather than write. The degree of improvement brought about by var is always subjective, and inevitably some people will like it and others will hate it. What you should focus on is how to help team members read your code, so if they like to read code that uses var, use it, otherwise don't.

Sometimes, the display type also reduces readability. For example, when looping through Map's entryset, you need to find the type parameters of the Map.Entry object. Here is an example of traversing Map, which maps the country name to the list of city names in it.

Map countryToCity = new HashMap (); / /... for (Map.Entry citiesInCountry: countryToCity.entrySet ()) {List cities = citiesInCountry.getValue (); / /...}

Then rewrite this code with var to reduce repetition and hassle:

Var countryToCity = new HashMap (); / /... for (var citiesInCountry: countryToCity.entrySet ()) {var cities = citiesInCountry.getValue (); / /...}

This brings advantages not only in readability, but also in improving and maintaining code. If we change the name of the city from the name represented by String to the City class in explicitly typed code to retain more city information, we need to rewrite all code that depends on a particular type, such as:

Map countryToCity = new HashMap (); / /... for (Map.Entry citiesInCountry: countryToCity.entrySet ()) {List cities = citiesInCountry.getValue (); / /...}

But with the var keyword and type derivation, we only need to modify the first line of code:

Var countryToCity = new HashMap (); / /... for (var citiesInCountry: countryToCity.entrySet ()) {var cities = citiesInCountry.getValue (); / /...}

This illustrates an important principle for using var variables: don't optimize for ease of coding or readability, but optimize for ease of maintenance. At the same time, consider that some of the code may be modified in the future and compromise the readability of the code. Of course, it is slightly arbitrary to say that adding type inference is only good for code, and sometimes explicit types contribute to the readability of the code. Especially when some of the generated expression types are not very intuitive, I will choose explicit rather than implicit types. For example, I can't see what object the getCitiest () method will return from the following code:

Map countryToCity = getCities (); var countryToCity = getCities ()

Now that both readability and var are in mind, how to compromise becomes a new problem. One suggestion is: pay attention to variable names, which is important! Because var loses the readability of the code, you have no idea what the code's intention is when you see such code, which makes it more important to have a good variable name. In theory, this is one of the areas that JAVA programmers should strive for, but in fact, many of the readability problems of Java code do not lie in the features of the language at all, but in the improper naming of some variables.

Type inference in IDE

Many IDE have the ability to extract local variables, which can correctly infer the type of variable and write it for you. This feature is somewhat duplicated with the var of Java 10. This feature of IDE, like var, eliminates the need for explicit writing types, but they differ in other ways.

The local extraction feature generates complete, well-typed local variables in the code. Var, on the other hand, eliminates the need for explicit writing types in code. So although they play a similar role in simplifying writing code, the impact of var on code readability is not available for local extraction. As we mentioned earlier, it improves readability most of the time, but sometimes it may decrease readability.

Compared with other programming languages

Java is not the first language to implement variable type inference. Type inference has been widely used in other languages in recent decades. In fact, the type inference through var in Java 10 is very limited and relatively constrained in form. This is a simple implementation that limits compilation errors associated with var declarations to a single statement, because the var inference algorithm only needs to evaluate the type of expression assigned to the variable. In addition, the Hindley-Milner type inference algorithm used in most languages takes exponential time in the worst case, which slows down javac.

At this point, the study on "Java10 local variable type example analysis" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report