Java is a stubborn language, it has a good readability, the novice programmer is easy to get started, with long-term stability and support. But these design decisions also pay a price: lengthy code, type systems are less resilient than other languages.
However, the Java type System is already evolving, albeit relatively slowly in the history of the language. Let's take a look at some of its forms over the years.
Java the initial type system
Java has been the original type system for more than 15 years now. It is simple and clear, and the types include reference types and basic types. A class, interface, or array belongs to a reference type.
- Classes are the core of the Java platform, and classes are the basic unit of functionality that the Java platform will load, or link, and all the code to execute must reside in a class.
- Interfaces cannot be instantiated directly, but through a class that implements the interface API.
- Arrays can contain primitive types, instances of classes, or other arrays.
- The basic types are all defined by the platform, and programmers cannot define new basic types.
From the very beginning, the Java type System has always insisted on the important point that each type must have a name that can be referenced. This is known as the "marking type (nominative typing)", and Java is a strongly labeled type language.
Even if the so-called "anonymous inner classes" still have types, programmers must be able to reference them in order to implement those interface types:
Runnable r = new Runnable () {public void run () {System.out.println ("Hello world!");}};
In other words, each value in Java is either a base type or an instance of a class.
Other options for named type (Named type)
Other languages are not so obsessed with named types. For example, Java does not have such a Scala concept, a type that implements a specific method (a particular signature). In Scala, you can write this:
X: {def bar:string}
Remember, Scala signs the variable type (after the colon) on the right, so it reads like "X is a type, it has a method bar returns a string". We can use it to define a Scala method like this:
def showrefine (x: {def bar:string}) = {print (X.bar)}
Then, if we define a suitable Scala object:
Object Barbell {def bar = "Bell"}
And then call Showrefine (Barbell), that's what we're looking for:
Showrefine (Barbell) Bell
This is an example of a refined type (refinement typing). Programmers who turn from dynamic languages may be familiar with "duck type (Duck typing)". The structural refinement type (Structural refinement typing) is similar except for the duck type (which, if it walks like a duck, it can be used as a duck) is a run-time type, and these structural refinement types work at compile time.
In languages that fully support structured refinement types, these refinement types can be used anywhere a programmer might expect, such as the type of a method parameter. And Java, on the contrary, does not support such a type (except for a few slightly bizarre edge examples).
Java 5 type System
The release of Java 5 brings three major new features to the type system, enumerations, annotations, and generics.
- An enumeration type (enum) is similar in some ways to a class, but its properties can only be instances of a specified number, each of which differs and is specified in the class description. Used primarily for "type-safe constants" rather than small integer constants that were commonly used at the time, enumeration constructs also allow additional patterns, which are sometimes useful.
- Annotations (Annotation) are related to interfaces, and the keyword that declares annotations is @interface, which at @ begins to indicate that this is an annotation type. As the name suggests, they are used to annotate Java code elements, providing additional information, but without affecting their behavior. Previously, Java had used "tagged interfaces (Marker interface)" To provide a limited form of this metadata, but annotations were considered more flexible.
- Java generics provide a parameterized type, and the idea is that a type can act as a "container" for other types of objects without needing to care about the specifics of the included type. Types that are assembled into a container are often referred to as type parameters.
In the features introduced in Java 5, enumerations and annotations provide a new form of reference types that require special processing by the compiler and are effectively detached from existing type hierarchies.
Generics add significant additional complexity to the Java type System, not only because they are purely compile-time features, but also require Java developers to be aware that the type systems at compile-time and runtime are slightly different from each other.
Despite these changes, Java remains a marked type. The type name now includes List (read: "List-of-string") and Map, cachedobject> ("Map-of-class-of-unknown-type-to-cachedobject"), However, these are still named types, and the value of each non-primitive type is still an instance of a class.
Java 6 and 7 features introduced
Java 6 is basically a version of performance optimization and class library enhancements. The only change in the type system is to expand the annotation role and release the pluggable annotation processing functionality. This has no effect on most developers, nor does Java 6 really provide a pluggable type system.
There is no significant change to the Java 7 type system. There are only a few new features that look similar:
- Small improvements in type inference in the Javac compiler.
- Signature Polymorphism Dispatch (Signature polymorphic Dispatch), used for implementation details of method handle, which in turn is used in Java 8 to implement lambda expressions.
- Multi-Catch provides some small tracking information for "Algebraic data types," but these are purely javac internal and have no effect on end-user programmers.
Java 8 the type system
Throughout its history, Java has largely been defined by its type system. It is the core of the language and strictly follows the marking type. In reality, the Java type System has not changed much between Java 5 and 7.
At first glance, we might expect Java 8 to change this. After all, a simple lambda expression seems to allow us to remove the marked type:
(), {System.out.println ("Hello world!");}
This is a method that has no name, no arguments, and returns void. It is still completely static type, but is now anonymous.
Have we escaped the kingdom of nouns? Is this really a new type of Java form?
Perhaps unfortunately, the answer is no. Java and other languages running on the JVM are very tightly limited to the concept of classes. Class loading is central to the security and validation patterns of the Java platform. Simply put, it is very, very difficult to express a type without a class.
Instead of creating a new type, Java 8 automatically converts a lambda expression into an instance of a class through the compiler. This class is determined by type inference. For example:
Runnable r = () {System.out.println ("Hello world!");};
The lambda expression on the right is a valid Java 8 value, but its type is inferred from the left value, so it is actually a value of type runnable. It is important to note that if you do not use lambda expressions correctly, you may cause compiler errors. Even the introduction of Lambda,java has not changed this, and still follows the marking type.
Java 8 How about functional programming?
Finally, let's go back to the question raised at the beginning of this article, "What about functional programming for Java 8?" ”
Before Java 8, if a developer wanted to program in a functional style, he or she could only use nested types (usually anonymous inner classes) as a substitute for function code. The default Collection class library does not provide any convenience for the code, and the magic of the variability is always present.
The lambda expression of Java 8 does not magically turn into a functional language. Instead, it still creates a forced strong-named type language, but has better syntax to support lambda expression function text. At the same time, the collection class library has been enhanced to allow Java developers to begin simplifying cumbersome code with simple functional styles such as filter and map.
Java 8 needs to introduce some new types to represent the basic building blocks of a function pipeline, such as predicate, function, and consumer interfaces in Java.util.function. These new features enable Java 8 to "function slightly", but Java needs to represent them by type (and they are in the toolkit, not the language core), indicating that the type still binds the Java language, which is far from the purely Lisp dialect or other functional language.
In addition to these, this small set of functional language energies is likely to be the real need of the daily development of most developers. For advanced users, there are other languages (JVM or other platforms), and there is no doubt that it will continue to flourish.
< turn >java some history