Java SE > Java SE Specifications > Java Language Specification

Chapter 5. Conversions and Contexts

Table of Contents

Every expression written in the Java programming language either produces no result ( §15.1 ) or has a type that can be deduced at compile time ( §15.3 ). When an expression appears in most contexts, it must be compatible with a type expected in that context; this type is called the target type . For convenience, compatibility of an expression with its surrounding context is facilitated in two ways:

First, for some expressions, termed poly expressions ( §15.2 ), the deduced type can be influenced by the target type. The same expression can have different types in different contexts.

Second, after the type of the expression has been deduced, an implicit conversion from the type of the expression to the target type can sometimes be performed.

If neither strategy is able to produce the appropriate type, a compile-time error occurs.

The rules determining whether an expression is a poly expression, and if so, its type and compatibility in a particular context, vary depending on the kind of context and the form of the expression. In addition to influencing the type of the expression, the target type may in some cases influence the run time behavior of the expression in order to produce a value of the appropriate type.

Similarly, the rules determining whether a target type allows an implicit conversion vary depending on the kind of context, the type of the expression, and, in one special case, the value of a constant expression ( §15.28 ). A conversion from type S to type T allows an expression of type S to be treated at compile time as if it had type T instead. In some cases this will require a corresponding action at run time to check the validity of the conversion or to translate the run-time value of the expression into a form appropriate for the new type T .

Example 5.0-1. Conversions at Compile Time and Run Time

A conversion from type Object to type Thread requires a run-time check to make sure that the run-time value is actually an instance of class Thread or one of its subclasses; if it is not, an exception is thrown.

A conversion from type Thread to type Object requires no run-time action; Thread is a subclass of Object , so any reference produced by an expression of type Thread is a valid reference value of type Object .

A conversion from type int to type long requires run-time sign-extension of a 32-bit integer value to the 64-bit long representation. No information is lost.

A conversion from type double to type long requires a non-trivial translation from a 64-bit floating-point value to the 64-bit integer representation. Depending on the actual run-time value, information may be lost.

The conversions possible in the Java programming language are grouped into several broad categories:

Identity conversions

Widening primitive conversions

Narrowing primitive conversions

Widening reference conversions

Narrowing reference conversions

Boxing conversions

Unboxing conversions

Unchecked conversions

Capture conversions

String conversions

Value set conversions

There are six kinds of conversion contexts in which poly expressions may be influenced by context or implicit conversions may occur. Each kind of context has different rules for poly expression typing and allows conversions in some of the categories above but not others. The contexts are:

Assignment contexts ( §5.2 , §15.26 ), in which an expression's value is bound to a named variable. Primitive and reference types are subject to widening, values may be boxed or unboxed, and some primitive constant expressions may be subject to narrowing. An unchecked conversion may also occur.

Strict invocation contexts ( §5.3 , §15.9 , §15.12 ), in which an argument is bound to a formal parameter of a constructor or method. Widening primitive, widening reference, and unchecked conversions may occur.

Loose invocation contexts ( §5.3 , §15.9 , §15.12 ), in which, like strict invocation contexts, an argument is bound to a formal parameter. Method or constructor invocations may provide this context if no applicable declaration can be found using only strict invocation contexts. In addition to widening and unchecked conversions, this context allows boxing and unboxing conversions to occur.

String contexts ( §5.4 , §15.18.1 ), in which a value of any type is converted to an object of type String .

Casting contexts ( §5.5 ), in which an expression's value is converted to a type explicitly specified by a cast operator ( §15.16 ). Casting contexts are more inclusive than assignment or loose invocation contexts, allowing any specific conversion other than a string conversion, but certain casts to a reference type are checked for correctness at run time.

Numeric contexts ( §5.6 ), in which the operands of a numeric operator may be widened to a common type so that an operation can be performed.

The term "conversion" is also used to describe, without being specific, any conversions allowed in a particular context. For example, we say that an expression that is the initializer of a local variable is subject to "assignment conversion", meaning that a specific conversion will be implicitly chosen for that expression according to the rules for the assignment context.

Example 5.0-2. Conversions In Various Contexts

This program produces the output:

5.1. Kinds of Conversion

Specific type conversions in the Java programming language are divided into 13 categories.

5.1.1. Identity Conversion

A conversion from a type to that same type is permitted for any type.

This may seem trivial, but it has two practical consequences. First, it is always permitted for an expression to have the desired type to begin with, thus allowing the simply stated rule that every expression is subject to conversion, if only a trivial identity conversion. Second, it implies that it is permitted for a program to include redundant cast operators for the sake of clarity.

5.1.2. Widening Primitive Conversion

19 specific conversions on primitive types are called the widening primitive conversions :

byte to short , int , long , float , or double

short to int , long , float , or double

char to int , long , float , or double

int to long , float , or double

long to float or double

float to double

A widening primitive conversion does not lose information about the overall magnitude of a numeric value in the following cases, where the numeric value is preserved exactly:

from an integral type to another integral type

from byte , short , or char to a floating point type

from int to double

from float to double in a strictfp expression ( §15.4 )

A widening primitive conversion from float to double that is not strictfp may lose information about the overall magnitude of the converted value.

A widening primitive conversion from int to float , or from long to float , or from long to double , may result in loss of precision - that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode ( §4.2.4 ).

A widening conversion of a signed integer value to an integral type T simply sign-extends the two's-complement representation of the integer value to fill the wider format.

A widening conversion of a char to an integral type T zero-extends the representation of the char value to fill the wider format.

Despite the fact that loss of precision may occur, a widening primitive conversion never results in a run-time exception ( §11.1.1 ).

Example 5.1.2-1. Widening Primitive Conversion

This program prints:

thus indicating that information was lost during the conversion from type int to type float because values of type float are not precise to nine significant digits.

5.1.3. Narrowing Primitive Conversion

22 specific conversions on primitive types are called the narrowing primitive conversions :

short to byte or char

char to byte or short

int to byte , short , or char

long to byte , short , char , or int

float to byte , short , char , int , or long

double to byte , short , char , int , long , or float

A narrowing primitive conversion may lose information about the overall magnitude of a numeric value and may also lose precision and range.

A narrowing primitive conversion from double to float is governed by the IEEE 754 rounding rules ( §4.2.4 ). This conversion can lose precision, but also lose range, resulting in a float zero from a nonzero double and a float infinity from a finite double . A double NaN is converted to a float NaN and a double infinity is converted to the same-signed float infinity.

A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T . In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.

A narrowing conversion of a char to an integral type T likewise simply discards all but the n lowest order bits, where n is the number of bits used to represent type T . In addition to a possible loss of information about the magnitude of the numeric value, this may cause the resulting value to be a negative number, even though chars represent 16-bit unsigned integer values.

A narrowing conversion of a floating-point number to an integral type T takes two steps:

In the first step, the floating-point number is converted either to a long , if T is long , or to an int , if T is byte , short , char , or int , as follows:

If the floating-point number is NaN ( §4.2.3 ), the result of the first step of the conversion is an int or long 0 .

Otherwise, if the floating-point number is not an infinity, the floating-point value is rounded to an integer value V , rounding toward zero using IEEE 754 round-toward-zero mode ( §4.2.3 ). Then there are two cases:

If T is long , and this integer value can be represented as a long , then the result of the first step is the long value V .

Otherwise, if this integer value can be represented as an int , then the result of the first step is the int value V .

Otherwise, one of the following two cases must be true:

The value must be too small (a negative value of large magnitude or negative infinity), and the result of the first step is the smallest representable value of type int or long .

The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of type int or long .

In the second step:

If T is int or long , the result of the conversion is the result of the first step.

If T is byte , char , or short , the result of the conversion is the result of a narrowing conversion to type T ( §5.1.3 ) of the result of the first step.

Despite the fact that overflow, underflow, or other loss of information may occur, a narrowing primitive conversion never results in a run-time exception ( §11.1.1 ).

Example 5.1.3-1. Narrowing Primitive Conversion

The results for char , int , and long are unsurprising, producing the minimum and maximum representable values of the type.

The results for byte and short lose information about the sign and magnitude of the numeric values and also lose precision. The results can be understood by examining the low order bits of the minimum and maximum int . The minimum int is, in hexadecimal, 0x80000000 , and the maximum int is 0x7fffffff . This explains the short results, which are the low 16 bits of these values, namely, 0x0000 and 0xffff ; it explains the char results, which also are the low 16 bits of these values, namely, '\u0000' and '\uffff' ; and it explains the byte results, which are the low 8 bits of these values, namely, 0x00 and 0xff .

Example 5.1.3-2. Narrowing Primitive Conversions that lose information

5.1.4. Widening and Narrowing Primitive Conversion

The following conversion combines both widening and narrowing primitive conversions:

byte to char

First, the byte is converted to an int via widening primitive conversion ( §5.1.2 ), and then the resulting int is converted to a char by narrowing primitive conversion ( §5.1.3 ).

5.1.5. Widening Reference Conversion

A widening reference conversion exists from any reference type S to any reference type T , provided S is a subtype ( §4.10 ) of T .

Widening reference conversions never require a special action at run time and therefore never throw an exception at run time. They consist simply in regarding a reference as having some other type in a manner that can be proved correct at compile time.

5.1.6. Narrowing Reference Conversion

Six kinds of conversions are called the narrowing reference conversions :

From any reference type S to any reference type T , provided that S is a proper supertype of T ( §4.10 ).

An important special case is that there is a narrowing reference conversion from the class type Object to any other reference type ( §4.12.4 ).

From any class type C to any non-parameterized interface type K , provided that C is not final and does not implement K .

From any interface type J to any non-parameterized class type C that is not final .

From any interface type J to any non-parameterized interface type K , provided that J is not a subinterface of K .

From the interface types Cloneable and java.io.Serializable to any array type T [] .

From any array type SC [] to any array type TC [] , provided that SC and TC are reference types and there is a narrowing reference conversion from SC to TC .

Such conversions require a test at run time to find out whether the actual reference value is a legitimate value of the new type. If not, then a ClassCastException is thrown.

5.1.7. Boxing Conversion

Boxing conversion converts expressions of primitive type to corresponding expressions of reference type. Specifically, the following nine conversions are called the boxing conversions :

From type boolean to type Boolean

From type byte to type Byte

From type short to type Short

From type char to type Character

From type int to type Integer

From type long to type Long

From type float to type Float

From type double to type Double

From the null type to the null type

This rule is necessary because the conditional operator ( §15.25 ) applies boxing conversion to the types of its operands, and uses the result in further calculations.

At run time, boxing conversion proceeds as follows:

If p is a value of type boolean , then boxing conversion converts p into a reference r of class and type Boolean , such that r .booleanValue() == p

If p is a value of type byte , then boxing conversion converts p into a reference r of class and type Byte , such that r .byteValue() == p

If p is a value of type char , then boxing conversion converts p into a reference r of class and type Character , such that r .charValue() == p

If p is a value of type short , then boxing conversion converts p into a reference r of class and type Short , such that r .shortValue() == p

If p is a value of type int , then boxing conversion converts p into a reference r of class and type Integer , such that r .intValue() == p

If p is a value of type long , then boxing conversion converts p into a reference r of class and type Long , such that r .longValue() == p

If p is a value of type float then:

If p is not NaN, then boxing conversion converts p into a reference r of class and type Float , such that r .floatValue() evaluates to p

Otherwise, boxing conversion converts p into a reference r of class and type Float such that r .isNaN() evaluates to true

If p is a value of type double , then:

If p is not NaN, boxing conversion converts p into a reference r of class and type Double , such that r .doubleValue() evaluates to p

Otherwise, boxing conversion converts p into a reference r of class and type Double such that r .isNaN() evaluates to true

If p is a value of any other type, boxing conversion is equivalent to an identity conversion ( §5.1.1 ).

If the value p being boxed is an integer literal of type int between -128 and 127 inclusive ( §3.10.1 ), or the boolean literal true or false ( §3.10.3 ), or a character literal between '\u0000' and '\u007f' inclusive ( §3.10.4 ), then let a and b be the results of any two boxing conversions of p . It is always the case that a == b .

Ideally, boxing a primitive value would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rule above is a pragmatic compromise, requiring that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, the rule disallows any assumptions about the identity of the boxed values on the programmer's part. This allows (but does not require) sharing of some or all of these references. Notice that integer literals of type long are allowed, but not required, to be shared.

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.

A boxing conversion may result in an OutOfMemoryError if a new instance of one of the wrapper classes ( Boolean , Byte , Character , Short , Integer , Long , Float , or Double ) needs to be allocated and insufficient storage is available.

5.1.8. Unboxing Conversion

Unboxing conversion converts expressions of reference type to corresponding expressions of primitive type. Specifically, the following eight conversions are called the unboxing conversions :

From type Boolean to type boolean

From type Byte to type byte

From type Short to type short

From type Character to type char

From type Integer to type int

From type Long to type long

From type Float to type float

From type Double to type double

At run time, unboxing conversion proceeds as follows:

If r is a reference of type Boolean , then unboxing conversion converts r into r .booleanValue()

If r is a reference of type Byte , then unboxing conversion converts r into r .byteValue()

If r is a reference of type Character , then unboxing conversion converts r into r .charValue()

If r is a reference of type Short , then unboxing conversion converts r into r .shortValue()

If r is a reference of type Integer , then unboxing conversion converts r into r .intValue()

If r is a reference of type Long , then unboxing conversion converts r into r .longValue()

If r is a reference of type Float , unboxing conversion converts r into r .floatValue()

If r is a reference of type Double , then unboxing conversion converts r into r .doubleValue()

If r is null , unboxing conversion throws a NullPointerException

A type is said to be convertible to a numeric type if it is a numeric type ( §4.2 ), or it is a reference type that may be converted to a numeric type by unboxing conversion.

A type is said to be convertible to an integral type if it is an integral type, or it is a reference type that may be converted to an integral type by unboxing conversion.

5.1.9. Unchecked Conversion

Let G name a generic type declaration with n type parameters.

There is an unchecked conversion from the raw class or interface type ( §4.8 ) G to any parameterized type of the form G < T 1 ,..., T n > .

There is an unchecked conversion from the raw array type G [] k to any array type of the form G < T 1 ,..., T n > [] k . (The notation [] k indicates an array type of k dimensions.)

Use of an unchecked conversion causes a compile-time unchecked warning unless all type arguments T i (1 ≤ i ≤ n ) are unbounded wildcards ( §4.5.1 ), or the unchecked warning is suppressed by the SuppressWarnings annotation ( §9.6.4.5 ).

Unchecked conversion is used to enable a smooth interoperation of legacy code, written before the introduction of generic types, with libraries that have undergone a conversion to use genericity (a process we call generification). In such circumstances (most notably, clients of the Collections Framework in java.util ), legacy code uses raw types (e.g. Collection instead of Collection<String> ). Expressions of raw types are passed as arguments to library methods that use parameterized versions of those same types as the types of their corresponding formal parameters.

Such calls cannot be shown to be statically safe under the type system using generics. Rejecting such calls would invalidate large bodies of existing code, and prevent them from using newer versions of the libraries. This in turn, would discourage library vendors from taking advantage of genericity. To prevent such an unwelcome turn of events, a raw type may be converted to an arbitrary invocation of the generic type declaration to which the raw type refers. While the conversion is unsound, it is tolerated as a concession to practicality. An unchecked warning is issued in such cases.

5.1.10. Capture Conversion

Let G name a generic type declaration ( §8.1.2 , §9.1.2 ) with n type parameters A 1 ,..., A n with corresponding bounds U 1 ,..., U n .

There exists a capture conversion from a parameterized type G < T 1 ,..., T n > ( §4.5 ) to a parameterized type G < S 1 ,..., S n > , where, for 1 ≤ i ≤ n :

If T i is a wildcard type argument ( §4.5.1 ) of the form ? , then S i is a fresh type variable whose upper bound is U i [ A 1 := S 1 ,..., A n := S n ] and whose lower bound is the null type ( §4.1 ).

If T i is a wildcard type argument of the form ? extends B i , then S i is a fresh type variable whose upper bound is glb( B i , U i [ A 1 := S 1 ,..., A n := S n ] ) and whose lower bound is the null type.

glb( V 1 ,..., V m ) is defined as V 1 & ... & V m .

It is a compile-time error if, for any two classes (not interfaces) V i and V j , V i is not a subclass of V j or vice versa.

If T i is a wildcard type argument of the form ? super B i , then S i is a fresh type variable whose upper bound is U i [ A 1 := S 1 ,..., A n := S n ] and whose lower bound is B i .

Otherwise, S i = T i .

Capture conversion on any type other than a parameterized type ( §4.5 ) acts as an identity conversion ( §5.1.1 ).

Capture conversion is not applied recursively.

Capture conversion never requires a special action at run time and therefore never throws an exception at run time.

Capture conversion is designed to make wildcards more useful. To understand the motivation, let's begin by looking at the method java.util.Collections.reverse() :

The method reverses the list provided as a parameter. It works for any type of list, and so the use of the wildcard type List<?> as the type of the formal parameter is entirely appropriate.

Now consider how one would implement reverse() :

The implementation needs to copy the list, extract elements from the copy, and insert them into the original. To do this in a type-safe manner, we need to give a name, T , to the element type of the incoming list. We do this in the private service method rev() . This requires us to pass the incoming argument list, of type List<?> , as an argument to rev() . In general, List<?> is a list of unknown type. It is not a subtype of List<T> , for any type T . Allowing such a subtype relation would be unsound. Given the method:

the following code would undermine the type system:

So, without some special dispensation, we can see that the call from reverse() to rev() would be disallowed. If this were the case, the author of reverse() would be forced to write its signature as:

This is undesirable, as it exposes implementation information to the caller. Worse, the designer of an API might reason that the signature using a wildcard is what the callers of the API require, and only later realize that a type safe implementation was precluded.

The call from reverse() to rev() is in fact harmless, but it cannot be justified on the basis of a general subtyping relation between List<?> and List<T> . The call is harmless, because the incoming argument is doubtless a list of some type (albeit an unknown one). If we can capture this unknown type in a type variable X , we can infer T to be X . That is the essence of capture conversion. The specification of course must cope with complications, like non-trivial (and possibly recursively defined) upper or lower bounds, the presence of multiple arguments etc.

Mathematically sophisticated readers will want to relate capture conversion to established type theory. Readers unfamiliar with type theory can skip this discussion - or else study a suitable text, such as Types and Programming Languages by Benjamin Pierce, and then revisit this section.

Here then is a brief summary of the relationship of capture conversion to established type theoretical notions. Wildcard types are a restricted form of existential types. Capture conversion corresponds loosely to an opening of a value of existential type. A capture conversion of an expression e can be thought of as an open of e in a scope that comprises the top level expression that encloses e .

The classical open operation on existentials requires that the captured type variable must not escape the opened expression. The open that corresponds to capture conversion is always on a scope sufficiently large that the captured type variable can never be visible outside that scope. The advantage of this scheme is that there is no need for a close operation, as defined in the paper On Variance-Based Subtyping for Parametric Types by Atsushi Igarashi and Mirko Viroli, in the proceedings of the 16th European Conference on Object Oriented Programming (ECOOP 2002). For a formal account of wildcards, see Wild FJ by Mads Torgersen, Erik Ernst and Christian Plesner Hansen, in the 12th workshop on Foundations of Object Oriented Programming (FOOL 2005).

5.1.11. String Conversion

Any type may be converted to type String by string conversion .

A value x of primitive type T is first converted to a reference value as if by giving it as an argument to an appropriate class instance creation expression ( §15.9 ):

If T is boolean , then use new Boolean( x ) .

If T is char , then use new Character( x ) .

If T is byte , short , or int , then use new Integer( x ) .

If T is long , then use new Long( x ) .

If T is float , then use new Float( x ) .

If T is double , then use new Double( x ) .

This reference value is then converted to type String by string conversion.

Now only reference values need to be considered:

If the reference is null , it is converted to the string " null " (four ASCII characters n , u , l , l ).

Otherwise, the conversion is performed as if by an invocation of the toString method of the referenced object with no arguments; but if the result of invoking the toString method is null , then the string " null " is used instead.

The toString method is defined by the primordial class Object ( §4.3.2 ). Many classes override it, notably Boolean , Character , Integer , Long , Float , Double , and String .

See §5.4 for details of the string context.

5.1.12. Forbidden Conversions

Any conversion that is not explicitly allowed is forbidden.

5.1.13. Value Set Conversion

Value set conversion is the process of mapping a floating-point value from one value set to another without changing its type.

Within an expression that is not FP-strict ( §15.4 ), value set conversion provides choices to an implementation of the Java programming language:

If the value is an element of the float-extended-exponent value set, then the implementation may, at its option, map the value to the nearest element of the float value set. This conversion may result in overflow (in which case the value is replaced by an infinity of the same sign) or underflow (in which case the value may lose precision because it is replaced by a denormalized number or zero of the same sign).

If the value is an element of the double-extended-exponent value set, then the implementation may, at its option, map the value to the nearest element of the double value set. This conversion may result in overflow (in which case the value is replaced by an infinity of the same sign) or underflow (in which case the value may lose precision because it is replaced by a denormalized number or zero of the same sign).

Within an FP-strict expression ( §15.4 ), value set conversion does not provide any choices; every implementation must behave in the same way:

If the value is of type float and is not an element of the float value set, then the implementation must map the value to the nearest element of the float value set. This conversion may result in overflow or underflow.

If the value is of type double and is not an element of the double value set, then the implementation must map the value to the nearest element of the double value set. This conversion may result in overflow or underflow.

Within an FP-strict expression, mapping values from the float-extended-exponent value set or double-extended-exponent value set is necessary only when a method is invoked whose declaration is not FP-strict and the implementation has chosen to represent the result of the method invocation as an element of an extended-exponent value set.

Whether in FP-strict code or code that is not FP-strict, value set conversion always leaves unchanged any value whose type is neither float nor double .

5.2. Assignment Contexts

Assignment contexts allow the value of an expression to be assigned ( §15.26 ) to a variable; the type of the expression must be converted to the type of the variable.

Assignment contexts allow the use of one of the following:

an identity conversion ( §5.1.1 )

a widening primitive conversion ( §5.1.2 )

a widening reference conversion ( §5.1.5 )

a boxing conversion ( §5.1.7 ) optionally followed by a widening reference conversion

an unboxing conversion ( §5.1.8 ) optionally followed by a widening primitive conversion.

If, after the conversions listed above have been applied, the resulting type is a raw type ( §4.8 ), an unchecked conversion ( §5.1.9 ) may then be applied.

In addition, if the expression is a constant expression ( §15.28 ) of type byte , short , char , or int :

A narrowing primitive conversion may be used if the type of the variable is byte , short , or char , and the value of the constant expression is representable in the type of the variable.

A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:

Byte and the value of the constant expression is representable in the type byte .

Short and the value of the constant expression is representable in the type short .

Character and the value of the constant expression is representable in the type char .

The compile-time narrowing of constant expressions means that code such as:

is allowed. Without the narrowing, the fact that the integer literal 42 has type int would mean that a cast to byte would be required:

Finally, a value of the null type (the null reference is the only such value) may be assigned to any reference type, resulting in a null reference of that type.

It is a compile-time error if the chain of conversions contains two parameterized types that are not in the subtype relation ( §4.10 ).

An example of such an illegal chain would be:

The first three elements of the chain are related by widening reference conversion, while the last entry is derived from its predecessor by unchecked conversion. However, this is not a valid assignment conversion, because the chain contains two parameterized types, Comparable<Integer> and Comparable<String> , that are not subtypes.

If the type of the expression cannot be converted to the type of the variable by a conversion permitted in an assignment context, then a compile-time error occurs.

If the type of an expression can be converted to the type of a variable by assignment conversion, we say the expression (or its value) is assignable to the variable or, equivalently, that the type of the expression is assignment compatible with the type of the variable.

If the type of the variable is float or double , then value set conversion ( §5.1.13 ) is applied to the value v that is the result of the conversion(s):

If v is of type float and is an element of the float-extended-exponent value set, then the implementation must map v to the nearest element of the float value set. This conversion may result in overflow or underflow.

If v is of type double and is an element of the double-extended-exponent value set, then the implementation must map v to the nearest element of the double value set. This conversion may result in overflow or underflow.

The only exceptions that may arise from conversions in an assignment context are:

A ClassCastException if, after the conversions above have been applied, the resulting value is an object which is not an instance of a subclass or subinterface of the erasure ( §4.6 ) of the type of the variable.

This circumstance can only arise as a result of heap pollution ( §4.12.2 ). In practice, implementations need only perform casts when accessing a field or method of an object of parameterized type when the erased type of the field, or the erased return type of the method, differ from its unerased type.

An OutOfMemoryError as a result of a boxing conversion.

A NullPointerException as a result of an unboxing conversion on a null reference.

An ArrayStoreException in special cases involving array elements or field access ( §10.5 , §15.26.1 ).

Example 5.2-1. Assignment Conversion for Primitive Types

The following program, however, produces compile-time errors:

because not all short values are char values, and neither are all char values short values.

Example 5.2-2. Assignment Conversion for Reference Types

The following test program illustrates assignment conversions on reference values, but fails to compile, as described in its comments. This example should be compared to the preceding one.

Example 5.2-3. Assignment Conversion for Array Types

In this example:

The value of veclong cannot be assigned to a Long variable, because Long is a class type other than Object . An array can be assigned only to a variable of a compatible array type, or to a variable of type Object , Cloneable or java.io.Serializable .

The value of veclong cannot be assigned to vecshort , because they are arrays of primitive type, and short and long are not the same primitive type.

The value of cpvec can be assigned to pvec , because any reference that could be the value of an expression of type ColoredPoint can be the value of a variable of type Point . The subsequent assignment of the new Point to a component of pvec then would throw an ArrayStoreException (if the program were otherwise corrected so that it could be compiled), because a ColoredPoint array cannot have an instance of Point as the value of a component.

The value of pvec cannot be assigned to cpvec , because not every reference that could be the value of an expression of type ColoredPoint can correctly be the value of a variable of type Point . If the value of pvec at run time were a reference to an instance of Point[] , and the assignment to cpvec were allowed, a simple reference to a component of cpvec , say, cpvec[0] , could return a Point , and a Point is not a ColoredPoint . Thus to allow such an assignment would allow a violation of the type system. A cast may be used ( §5.5 , §15.16 ) to ensure that pvec references a ColoredPoint[] :

5.3. Invocation Contexts

Invocation contexts allow an argument value in a method or constructor invocation ( §8.8.7.1 , §15.9 , §15.12 ) to be assigned to a corresponding formal parameter.

Strict invocation contexts allow the use of one of the following:

Loose invocation contexts allow a more permissive set of conversions, because they are only used for a particular invocation if no applicable declaration can be found using strict invocation contexts. Loose invocation contexts allow the use of one of the following:

a boxing conversion ( §5.1.7 ) optionally followed by widening reference conversion

an unboxing conversion ( §5.1.8 ) optionally followed by a widening primitive conversion

If, after the conversions listed for an invocation context have been applied, the resulting type is a raw type ( §4.8 ), an unchecked conversion ( §5.1.9 ) may then be applied.

A value of the null type (the null reference is the only such value) may be assigned to any reference type.

If the type of the expression cannot be converted to the type of the parameter by a conversion permitted in a loose invocation context, then a compile-time error occurs.

If the type of an argument expression is either float or double , then value set conversion ( §5.1.13 ) is applied after the conversion(s):

If an argument value of type float is an element of the float-extended-exponent value set, then the implementation must map the value to the nearest element of the float value set. This conversion may result in overflow or underflow.

If an argument value of type double is an element of the double-extended-exponent value set, then the implementation must map the value to the nearest element of the double value set. This conversion may result in overflow or underflow.

The only exceptions that may arise in an invocation context are:

A ClassCastException if, after the type conversions above have been applied, the resulting value is an object which is not an instance of a subclass or subinterface of the erasure ( §4.6 ) of the corresponding formal parameter type.

Neither strict nor loose invocation contexts include the implicit narrowing of integer constant expressions which is allowed in assignment contexts. The designers of the Java programming language felt that including these implicit narrowing conversions would add additional complexity to the rules of overload resolution ( §15.12.2 ).

Thus, the program:

causes a compile-time error because the integer literals 12 and 2 have type int , so neither method m matches under the rules of overload resolution. A language that included implicit narrowing of integer constant expressions would need additional rules to resolve cases like this example.

5.4. String Contexts

String contexts apply only to an operand of the binary + operator which is not a String when the other operand is a String .

The target type in these contexts is always String , and a string conversion ( §5.1.11 ) of the non- String operand always occurs. Evaluation of the + operator then proceeds as specified in §15.18.1 .

5.5. Casting Contexts

Casting contexts allow the operand of a cast operator ( §15.16 ) to be converted to the type explicitly named by the cast operator.

Casting contexts allow the use of one of:

a narrowing primitive conversion ( §5.1.3 )

a widening and narrowing primitive conversion ( §5.1.4 )

a widening reference conversion ( §5.1.5 ) optionally followed by either an unboxing conversion ( §5.1.8 ) or an unchecked conversion ( §5.1.9 )

a narrowing reference conversion ( §5.1.6 ) optionally followed by either an unboxing conversion ( §5.1.8 ) or an unchecked conversion ( §5.1.9 )

a boxing conversion ( §5.1.7 ) optionally followed by a widening reference conversion ( §5.1.5 )

an unboxing conversion ( §5.1.8 ) optionally followed by a widening primitive conversion ( §5.1.2 ).

Value set conversion ( §5.1.13 ) is applied after the type conversion.

The compile-time legality of a casting conversion is as follows:

An expression of a primitive type may undergo casting conversion to another primitive type, by an identity conversion (if the types are the same), or by a widening primitive conversion, or by a narrowing primitive conversion, or by a widening and narrowing primitive conversion.

An expression of a primitive type may undergo casting conversion to a reference type without error, by boxing conversion.

An expression of a reference type may undergo casting conversion to a primitive type without error, by unboxing conversion.

An expression of a reference type may undergo casting conversion to another reference type if no compile-time error occurs given the rules in §5.5.1 .

The following tables enumerate which conversions are used in certain casting conversions. Each conversion is signified by a symbol:

- signifies no casting conversion allowed

≈ signifies identity conversion ( §5.1.1 )

ω signifies widening primitive conversion ( §5.1.2 )

η signifies narrowing primitive conversion ( §5.1.3 )

ω η signifies widening and narrowing primitive conversion ( §5.1.4 )

⇑ signifies widening reference conversion ( §5.1.5 )

⇓ signifies narrowing reference conversion ( §5.1.6 )

⊕ signifies boxing conversion ( §5.1.7 )

⊗ signifies unboxing conversion ( §5.1.8 )

In the tables, a comma between symbols indicates that a casting conversion uses one conversion followed by another. The type Object means any reference type other than the eight wrapper classes Boolean , Byte , Short , Character , Integer , Long , Float , Double .

Table 5.5-A. Casting conversions to primitive types

Table 5.5-B. Casting conversions to reference types

5.5.1. Reference Type Casting

Given a compile-time reference type S (source) and a compile-time reference type T (target), a casting conversion exists from S to T if no compile-time errors occur due to the following rules.

If S is a class type:

If T is a class type, then either | S | <: | T |, or | T | <: | S |. Otherwise, a compile-time error occurs.

Furthermore, if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types ( §4.5 ), and that the erasures of X and Y are the same, a compile-time error occurs.

If T is an interface type:

If S is not a final class ( §8.1.1 ), then, if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

Otherwise, the cast is always legal at compile time (because even if S does not implement T , a subclass of S might).

If S is a final class ( §8.1.1 ), then S must implement T , or a compile-time error occurs.

If T is a type variable, then this algorithm is applied recursively, using the upper bound of T in place of T .

If T is an array type, then S must be the class Object , or a compile-time error occurs.

If T is an intersection type, T 1 & ... & T n , then it is a compile-time error if there exists a T i (1 ≤ i ≤ n ) such that S cannot be cast to T i by this algorithm. That is, the success of the cast is determined by the most restrictive component of the intersection type.

If S is an interface type:

If T is an array type, then S must be the type java.io.Serializable or Cloneable (the only interfaces implemented by arrays), or a compile-time error occurs.

If T is a class or interface type that is not final ( §8.1.1 ), then if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

Otherwise, the cast is always legal at compile time (because even if T does not implement S , a subclass of T might).

If T is a class type that is final , then:

If S is not a parameterized type or a raw type, then T must implement S , or a compile-time error occurs.

Otherwise, S is either a parameterized type that is an invocation of some generic type declaration G , or a raw type corresponding to a generic type declaration G . Then there must exist a supertype X of T , such that X is an invocation of G , or a compile-time error occurs.

Furthermore, if S and X are provably distinct parameterized types then a compile-time error occurs.

If T is an intersection type, T 1 & ... & T n , then it is a compile-time error if there exists a T i (1 ≤ i ≤ n ) such that S cannot be cast to T i by this algorithm.

If S is a type variable, then this algorithm is applied recursively, using the upper bound of S in place of S .

If S is an intersection type A 1 & ... & A n , then it is a compile-time error if there exists an A i (1 ≤ i ≤ n ) such that A i cannot be cast to T by this algorithm. That is, the success of the cast is determined by the most restrictive component of the intersection type.

If S is an array type SC [] , that is, an array of components of type SC :

If T is a class type, then if T is not Object , then a compile-time error occurs (because Object is the only class type to which arrays can be assigned).

If T is an interface type, then a compile-time error occurs unless T is the type java.io.Serializable or the type Cloneable (the only interfaces implemented by arrays).

If T is an array type TC [] , that is, an array of components of type TC , then a compile-time error occurs unless one of the following is true:

TC and SC are the same primitive type.

TC and SC are reference types and type SC can undergo casting conversion to TC .

Example 5.5.1-1. Casting Conversion for Reference Types

Here, the first compile-time error occurs because the class types Long and Point are unrelated (that is, they are not the same, and neither is a subclass of the other), so a cast between them will always fail.

The second compile-time error occurs because a variable of type EndPoint can never reference a value that implements the interface Colorable . This is because EndPoint is a final type, and a variable of a final type always holds a value of the same run-time type as its compile-time type. Therefore, the run-time type of variable e must be exactly the type EndPoint , and type EndPoint does not implement Colorable .

Example 5.5.1-2. Casting Conversion for Array Types

This program compiles without errors and produces the output:

5.5.2. Checked Casts and Unchecked Casts

A cast from a type S to a type T is statically known to be correct if and only if S <: T ( §4.10 ).

A cast from a type S to a parameterized type ( §4.5 ) T is unchecked unless at least one of the following is true:

All of the type arguments ( §4.5.1 ) of T are unbounded wildcards

T <: S and S has no subtype X other than T where the type arguments of X are not contained in the type arguments of T .

A cast from a type S to a type variable T is unchecked unless S <: T .

A cast from a type S to an intersection type T 1 & ... & T n is unchecked if there exists a T i (1 ≤ i ≤ n ) such that a cast from S to T i is unchecked.

An unchecked cast from S to a non-intersection type T is completely unchecked if the cast from | S | to | T | is statically known to be correct. Otherwise, it is partially unchecked .

An unchecked cast from S to an intersection type T 1 & ... & T n is completely unchecked if, for all i (1 ≤ i ≤ n ), a cast from S to T i is either statically known to be correct or completely unchecked. Otherwise, it is partially unchecked .

An unchecked cast causes a compile-time unchecked warning, unless suppressed by the SuppressWarnings annotation ( §9.6.4.5 ).

A cast is checked if it is not statically known to be correct and it is not unchecked.

If a cast to a reference type is not a compile-time error, there are several cases:

The cast is statically known to be correct.

No run-time action is performed for such a cast.

The cast is a completely unchecked cast.

The cast is a partially unchecked or checked cast to an intersection type.

Where the intersection type is T 1 & ... & T n , then for all i (1 ≤ i ≤ n ), any run-time check required for a cast from S to T i is also required for the cast to the intersection type.

The cast is a partially unchecked cast to a non-intersection type.

Such a cast requires a run-time validity check. The check is performed as if the cast had been a checked cast between | S | and | T |, as described below.

The cast is a checked cast to a non-intersection type.

Such a cast requires a run-time validity check. If the value at run time is null , then the cast is allowed. Otherwise, let R be the class of the object referred to by the run-time reference value, and let T be the erasure ( §4.6 ) of the type named in the cast operator. A cast conversion must check, at run time, that the class R is assignment compatible with the type T , via the algorithm in §5.5.3 .

Note that R cannot be an interface when these rules are first applied for any given cast, but R may be an interface if the rules are applied recursively because the run-time reference value may refer to an array whose element type is an interface type.

5.5.3. Checked Casts at Run Time

Here is the algorithm to check whether the run-time type R of an object is assignment compatible with the type T which is the erasure ( §4.6 ) of the type named in the cast operator. If a run-time exception is thrown, it is a ClassCastException .

If R is an ordinary class (not an array class):

If T is a class type, then R must be either the same class ( §4.3.4 ) as T or a subclass of T , or a run-time exception is thrown.

If T is an interface type, then R must implement ( §8.1.5 ) interface T , or a run-time exception is thrown.

If T is an array type, then a run-time exception is thrown.

If R is an interface:

If T is a class type, then T must be Object ( §4.3.2 ), or a run-time exception is thrown.

If T is an interface type, then R must be either the same interface as T or a subinterface of T , or a run-time exception is thrown.

If R is a class representing an array type RC [] , that is, an array of components of type RC :

If T is an interface type, then a run-time exception is thrown unless T is the type java.io.Serializable or the type Cloneable (the only interfaces implemented by arrays).

This case could slip past the compile-time checking if, for example, a reference to an array were stored in a variable of type Object .

If T is an array type TC [] , that is, an array of components of type TC , then a run-time exception is thrown unless one of the following is true:

TC and RC are the same primitive type.

TC and RC are reference types and type RC can be cast to TC by a recursive application of these run-time rules for casting.

Example 5.5.3-1. Incompatible Types at Run Time

This program uses casts to compile, but it throws exceptions at run time, because the types are incompatible.

5.6. Numeric Contexts

Numeric contexts apply to the operands of an arithmetic operator.

Numeric contexts allow the use of:

A numeric promotion is a process by which, given an arithmetic operator and its argument expressions, the arguments are converted to an inferred target type T . T is chosen during promotion such that each argument expression can be converted to T and the arithmetic operation is defined for values of type T .

The two kinds of numeric promotion are unary numeric promotion ( §5.6.1 ) and binary numeric promotion ( §5.6.2 ).

5.6.1. Unary Numeric Promotion

Some operators apply unary numeric promotion to a single operand, which must produce a value of a numeric type:

If the operand is of compile-time type Byte , Short , Character , or Integer , it is subjected to unboxing conversion ( §5.1.8 ). The result is then promoted to a value of type int by a widening primitive conversion ( §5.1.2 ) or an identity conversion ( §5.1.1 ).

Otherwise, if the operand is of compile-time type Long , Float , or Double , it is subjected to unboxing conversion ( §5.1.8 ).

Otherwise, if the operand is of compile-time type byte , short , or char , it is promoted to a value of type int by a widening primitive conversion ( §5.1.2 ).

Otherwise, a unary numeric operand remains as is and is not converted.

After the conversion(s), if any, value set conversion ( §5.1.13 ) is then applied.

Unary numeric promotion is performed on expressions in the following situations:

Each dimension expression in an array creation expression ( §15.10.1 )

The index expression in an array access expression ( §15.10.3 )

The operand of a unary plus operator + ( §15.15.3 )

The operand of a unary minus operator - ( §15.15.4 )

The operand of a bitwise complement operator ~ ( §15.15.5 )

Each operand, separately, of a shift operator << , >> , or >>> ( §15.19 ).

A long shift distance (right operand) does not promote the value being shifted (left operand) to long .

Example 5.6.1-1. Unary Numeric Promotion

5.6.2. Binary Numeric Promotion

When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:

If any operand is of a reference type, it is subjected to unboxing conversion ( §5.1.8 ).

Widening primitive conversion ( §5.1.2 ) is applied to convert either or both operands as specified by the following rules:

If either operand is of type double , the other is converted to double .

Otherwise, if either operand is of type float , the other is converted to float .

Otherwise, if either operand is of type long , the other is converted to long .

Otherwise, both operands are converted to type int .

After the conversion(s), if any, value set conversion ( §5.1.13 ) is then applied to each operand.

Binary numeric promotion is performed on the operands of certain operators:

The multiplicative operators * , / , and % ( §15.17 )

The addition and subtraction operators for numeric types + and - ( §15.18.2 )

The numerical comparison operators < , <= , > , and >= ( §15.20.1 )

The numerical equality operators == and != ( §15.21.1 )

The integer bitwise operators & , ^ , and | ( §15.22.1 )

In certain cases, the conditional operator ? : ( §15.25 )

Example 5.6.2-1. Binary Numeric Promotion

The example converts the ASCII character G to the ASCII control-G (BEL), by masking off all but the low 5 bits of the character. The 7 is the numeric value of this control character.

  • Skip to main content
  • Skip to search
  • Skip to select language
  • Sign up for free

Nullish coalescing assignment (??=)

The nullish coalescing assignment ( ??= ) operator, also known as the logical nullish assignment operator, only evaluates the right operand and assigns to the left if the left operand is nullish ( null or undefined ).

Description

Nullish coalescing assignment short-circuits , meaning that x ??= y is equivalent to x ?? (x = y) , except that the expression x is only evaluated once.

No assignment is performed if the left-hand side is not nullish, due to short-circuiting of the nullish coalescing operator. For example, the following does not throw an error, despite x being const :

Neither would the following trigger the setter:

In fact, if x is not nullish, y is not evaluated at all.

Using nullish coalescing assignment

You can use the nullish coalescing assignment operator to apply default values to object properties. Compared to using destructuring and default values , ??= also applies the default value if the property has value null .

Specifications

Browser compatibility.

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

  • Nullish coalescing operator ( ?? )
  • Java Arrays
  • Java Strings
  • Java Collection
  • Java 8 Tutorial
  • Java Multithreading
  • Java Exception Handling
  • Java Programs
  • Java Project
  • Java Collections Interview
  • Java Interview Questions
  • Spring Boot
  • Java Tutorial

Overview of Java

  • Introduction to Java
  • The Complete History of Java Programming Language
  • C++ vs Java vs Python
  • How to Download and Install Java for 64 bit machine?
  • Setting up the environment in Java
  • How to Download and Install Eclipse on Windows?
  • JDK in Java
  • How JVM Works - JVM Architecture?
  • Differences between JDK, JRE and JVM
  • Just In Time Compiler
  • Difference between JIT and JVM in Java
  • Difference between Byte Code and Machine Code
  • How is Java platform independent?

Basics of Java

  • Java Basic Syntax
  • Java Hello World Program
  • Java Data Types
  • Primitive data type vs. Object data type in Java with Examples
  • Java Identifiers

Operators in Java

  • Java Variables
  • Scope of Variables In Java

Wrapper Classes in Java

Input/output in java.

  • How to Take Input From User in Java?
  • Scanner Class in Java
  • Java.io.BufferedReader Class in Java
  • Difference Between Scanner and BufferedReader Class in Java
  • Ways to read input from console in Java
  • System.out.println in Java
  • Difference between print() and println() in Java
  • Formatted Output in Java using printf()
  • Fast I/O in Java in Competitive Programming

Flow Control in Java

  • Decision Making in Java (if, if-else, switch, break, continue, jump)
  • Java if statement with Examples
  • Java if-else
  • Java if-else-if ladder with Examples
  • Loops in Java
  • For Loop in Java
  • Java while loop with Examples
  • Java do-while loop with Examples
  • For-each loop in Java
  • Continue Statement in Java
  • Break statement in Java
  • Usage of Break keyword in Java
  • return keyword in Java
  • Java Arithmetic Operators with Examples
  • Java Unary Operator with Examples
  • Java Assignment Operators with Examples
  • Java Relational Operators with Examples
  • Java Logical Operators with Examples
  • Java Ternary Operator with Examples
  • Bitwise Operators in Java
  • Strings in Java
  • String class in Java
  • Java.lang.String class in Java | Set 2
  • Why Java Strings are Immutable?
  • StringBuffer class in Java
  • StringBuilder Class in Java with Examples
  • String vs StringBuilder vs StringBuffer in Java
  • StringTokenizer Class in Java
  • StringTokenizer Methods in Java with Examples | Set 2
  • StringJoiner Class in Java
  • Arrays in Java
  • Arrays class in Java
  • Multidimensional Arrays in Java
  • Different Ways To Declare And Initialize 2-D Array in Java
  • Jagged Array in Java
  • Final Arrays in Java
  • Reflection Array Class in Java
  • util.Arrays vs reflect.Array in Java with Examples

OOPS in Java

  • Object Oriented Programming (OOPs) Concept in Java
  • Why Java is not a purely Object-Oriented Language?
  • Classes and Objects in Java
  • Naming Conventions in Java
  • Java Methods

Access Modifiers in Java

  • Java Constructors
  • Four Main Object Oriented Programming Concepts of Java

Inheritance in Java

Abstraction in java, encapsulation in java, polymorphism in java, interfaces in java.

  • 'this' reference in Java
  • Inheritance and Constructors in Java
  • Java and Multiple Inheritance
  • Interfaces and Inheritance in Java
  • Association, Composition and Aggregation in Java
  • Comparison of Inheritance in C++ and Java
  • abstract keyword in java
  • Abstract Class in Java
  • Difference between Abstract Class and Interface in Java
  • Control Abstraction in Java with Examples
  • Difference Between Data Hiding and Abstraction in Java
  • Difference between Abstraction and Encapsulation in Java with Examples
  • Difference between Inheritance and Polymorphism
  • Dynamic Method Dispatch or Runtime Polymorphism in Java
  • Difference between Compile-time and Run-time Polymorphism in Java

Constructors in Java

  • Copy Constructor in Java
  • Constructor Overloading in Java
  • Constructor Chaining In Java with Examples
  • Private Constructors and Singleton Classes in Java

Methods in Java

  • Static methods vs Instance methods in Java
  • Abstract Method in Java with Examples
  • Overriding in Java
  • Method Overloading in Java
  • Difference Between Method Overloading and Method Overriding in Java
  • Differences between Interface and Class in Java
  • Functional Interfaces in Java
  • Nested Interface in Java
  • Marker interface in Java
  • Comparator Interface in Java with Examples
  • Need of Wrapper Classes in Java
  • Different Ways to Create the Instances of Wrapper Classes in Java
  • Character Class in Java
  • Java.Lang.Byte class in Java
  • Java.Lang.Short class in Java
  • Java.lang.Integer class in Java
  • Java.Lang.Long class in Java
  • Java.Lang.Float class in Java
  • Java.Lang.Double Class in Java
  • Java.lang.Boolean Class in Java
  • Autoboxing and Unboxing in Java
  • Type conversion in Java with Examples

Keywords in Java

  • Java Keywords
  • Important Keywords in Java
  • Super Keyword in Java
  • final Keyword in Java
  • static Keyword in Java
  • enum in Java
  • transient keyword in Java
  • volatile Keyword in Java
  • final, finally and finalize in Java
  • Public vs Protected vs Package vs Private Access Modifier in Java
  • Access and Non Access Modifiers in Java

Memory Allocation in Java

  • Java Memory Management
  • How are Java objects stored in memory?
  • Stack vs Heap Memory Allocation
  • How many types of memory areas are allocated by JVM?
  • Garbage Collection in Java
  • Types of JVM Garbage Collectors in Java with implementation details
  • Memory leaks in Java
  • Java Virtual Machine (JVM) Stack Area

Classes of Java

  • Understanding Classes and Objects in Java
  • Singleton Method Design Pattern in Java
  • Object Class in Java
  • Inner Class in Java
  • Throwable Class in Java with Examples

Packages in Java

  • Packages In Java
  • How to Create a Package in Java?
  • Java.util Package in Java
  • Java.lang package in Java
  • Java.io Package in Java
  • Java Collection Tutorial

Exception Handling in Java

  • Exceptions in Java
  • Types of Exception in Java with Examples
  • Checked vs Unchecked Exceptions in Java
  • Java Try Catch Block
  • Flow control in try catch finally in Java
  • throw and throws in Java
  • User-defined Custom Exception in Java
  • Chained Exceptions in Java

Null Pointer Exception In Java

  • Exception Handling with Method Overriding in Java
  • Multithreading in Java
  • Lifecycle and States of a Thread in Java
  • Java Thread Priority in Multithreading
  • Main thread in Java
  • Java.lang.Thread Class in Java
  • Runnable interface in Java
  • Naming a thread and fetching name of current thread in Java
  • What does start() function do in multithreading in Java?
  • Difference between Thread.start() and Thread.run() in Java
  • Thread.sleep() Method in Java With Examples
  • Synchronization in Java
  • Importance of Thread Synchronization in Java
  • Method and Block Synchronization in Java
  • Lock framework vs Thread synchronization in Java
  • Difference Between Atomic, Volatile and Synchronized in Java
  • Deadlock in Java Multithreading
  • Deadlock Prevention And Avoidance
  • Difference Between Lock and Monitor in Java Concurrency
  • Reentrant Lock in Java

File Handling in Java

  • Java.io.File Class in Java
  • Java Program to Create a New File
  • Different ways of Reading a text file in Java
  • Java Program to Write into a File
  • Delete a File Using Java
  • File Permissions in Java
  • FileWriter Class in Java
  • Java.io.FileDescriptor in Java
  • Java.io.RandomAccessFile Class Method | Set 1
  • Regular Expressions in Java
  • Regex Tutorial - How to write Regular Expressions?
  • Matcher pattern() method in Java with Examples
  • Pattern pattern() method in Java with Examples
  • Quantifiers in Java
  • java.lang.Character class methods | Set 1
  • Java IO : Input-output in Java with Examples
  • Java.io.Reader class in Java
  • Java.io.Writer Class in Java
  • Java.io.FileInputStream Class in Java
  • FileOutputStream in Java
  • Java.io.BufferedOutputStream class in Java
  • Java Networking
  • TCP/IP Model
  • User Datagram Protocol (UDP)
  • Differences between IPv4 and IPv6
  • Difference between Connection-oriented and Connection-less Services
  • Socket Programming in Java
  • java.net.ServerSocket Class in Java
  • URL Class in Java with Examples

JDBC - Java Database Connectivity

  • Introduction to JDBC (Java Database Connectivity)
  • JDBC Drivers
  • Establishing JDBC Connection in Java
  • Types of Statements in JDBC
  • JDBC Tutorial
  • Java 8 Features - Complete Tutorial

NullPointerException is a RuntimeException. In Java , a special null value can be assigned to an object reference. NullPointerException is thrown when a program attempts to use an object reference that has the null value.

Reason for Null Pointer Exception

These are certain reasons for Null Pointer Exception as mentioned below: 

  • Invoking a method from a null object.
  • Accessing or modifying a null object’s field.
  • Taking the length of null, as if it were an array.
  • Accessing or modifying the slots of null objects, as if it were an array.
  • Throwing null, as if it were a Throwable value.
  • When you try to synchronize over a null object.

Why do we need the Null Value?  

Null is a special value used in Java. It is mainly used to indicate that no value is assigned to a reference variable. One application of null is in implementing data structures like linked lists and trees. Other applications include the Null Object pattern (See this for details) and the Singleton pattern . The Singleton pattern ensures that only one instance of a class is created and also, aims for providing a global point of access to the object.

A simple way to create at most one instance of a class is to declare all its constructors as private and then, create a public method that returns the unique instance of the class:

Output: 

In above example, a static instance of the singleton class. That instance is initialized at most once inside the Singleton getInstance method.

How to Avoid the NullPointerException?  

To avoid the NullPointerException, we must ensure that all the objects are initialized properly, before you use them. When we declare a reference variable, we must verify that object is not null, before we request a method or a field from the objects. Following are the common problems with the solution to overcome that problem.

Case 1 : String comparison with literals

A very common case problem involves the comparison between a String variable and a literal. The literal may be a String or an element of an Enum. Instead of invoking the method from the null object, consider invoking it from the literal. 

Below is the Example of the Case 1:

We can avoid NullPointerException by calling equals on literal rather than object.

Case 2 : Keeping a Check on the arguments of a method

Before executing the body of your new method, we should first check its arguments for null values and continue with execution of the method, only when the arguments are properly checked. Otherwise, it will throw an IllegalArgumentException and notify the calling method that something is wrong with the passed arguments. 

Below is the Example of the Case 2:

Case 3 : Use of Ternary Operator

The ternary operator can be used to avoid NullPointerException. First, the Boolean expression is evaluated. If the expression is true then, the value1 is returned, otherwise, the value2 is returned. We can use the ternary operator for handling null pointers:

The message variable will be empty if str’s reference is null as in case

  • Otherwise, if str point to actual data , the message will retrieve the first 6 characters of it as in case
  • Related Article – Interesting facts about Null in Java  

Frequently Asked Questions

1. what is nullpointerexception in java.

NullPointerException in Java is a type RuntimeException.

2. Why Null Pointer Exception Occurs?

NullPointerException occurs when one tries to access or manipulate object reference that has a Null value stored in it.

3. How to handle a Null Pointer Exception in Java?

There are certain methods to handle Null Pointer Exception in Java are mentioned below: String comparison with literals Keeping a Check on the arguments of a method Use of Ternary Operator

4. Reason for Null Pointer Exception.

NullPointerException is thrown when a program attempts to use an object reference that has the null value.

Please Login to comment...

Similar reads.

  • Exception Handling
  • Java-Exceptions
  • Technical Scripter

advertisewithusBannerImg

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

Advisory boards aren’t only for executives. Join the LogRocket Content Advisory Board today →

LogRocket blog logo

  • Product Management
  • Solve User-Reported Issues
  • Find Issues Faster
  • Optimize Conversion and Adoption
  • Start Monitoring for Free

A complete guide to null safety in Kotlin

java null assignment

One of the most common problems coming with programming languages is that accessing a variable with a null value causes a null reference exception at runtime. This leads to several issues that may be difficult to address while programming.

Complete Guide to Null Safety In Kotlin

This is why a few programming languages introduced the possibility to indicate that a variable is nullable, or in other words, that it can accept the null value. Consequently, any variable cannot contain the null value unless you explicitly say it can. This way, you can avoid the danger of null references, and you do not have to wait for exceptions or errors to be thrown at runtime.

Kotlin supports this possibility since its first release, and it is called null safety. This characteristic undoubtedly represents one of the coolest, most beautiful, and innovative features coming with the Kotlin programming language. This is why it is so important to know how to properly use it.

So, let’s dive into null safety in Kotlin and learn everything you should know.

Non-nullable types vs. nullable types

As opposed to what happens in Java, Kotlin distinguishes between references that cannot hold null and those that can. The first ones are called non-nullable references, and their type must be of a non-nullable type. On the other hand, the second ones are called nullable references and must be of a nullable type.

While initializing a variable in Kotlin as you would in Java, you are using non-nullable types. This is because Kotlin imposes strict null-safety by default. Let’s see what this means:

The real difference between Java and Kotlin when dealing with null values becomes clear when trying to give fooString a null value, as follows:

In Kotlin, this leads to a compilation error because the fooString variable was declared with a non-nullable type. In Java, this would not lead to any error, except for a NullPointerException at runtime when trying to call a method or accessing a field on fooString .

The reason is that Java does not support null safety, and non-nullable types do not exist. In other terms, any variable is always a nullable reference and there is no way to avoid null values except with custom logic. Thus, any reference in Java may be null by default.

Even in Kotlin, variables can accept null values, but you have to declare it explicitly. In the example above, you can achieve it by changing the type of fooString variable and replacing it with the corresponding nullable type:

As you can see, by adding the ? character to the end of the type name, you are making the variable a nullable reference. This is how nullable types are used in Kotlin.

Now the following line of code would not lead to any compile-time errors, just like it would in Java:

Nullable types can be also used as generics , but again you must explicitly declare them as nullable:

Nullable types are also useful when dealing with casts. This is because the operation would result in a ClassCastException if the object did not match the target type. But Kotlin introduced the safe cast operator as? , which returns null when the cast operation fails:

Basic null safety

Learning how to properly handle null safety in Kotlin takes time. Luckily, Kotlin is a versatile programming language, and it supports two approaches to make dealing with null safety easier, especially for beginners. Let’s see them in action.

Explicitly checking for null

If you want to avoid using advanced techniques to tackle null safety in Kotlin, all you have to do is use the same approach you would use in Java to avoid NullPointerException . Basically, before accessing a nullable variable field by calling one of its methods, you always have to explicitly check whether the variable is not null, and handle the two possible cases separately.

This can be easily achieved with an if-else expression:

The Kotlin compiler is smart enough to track the code logic and understand that there is a fallback logic when fooString is null. So, no errors at compile time will be thrown because the strict Kotlin null safety is enforced as expected. In fact, the fooString variable will be accessed only when it has a proper value.

java null assignment

Over 200k developers use LogRocket to create better digital experiences

java null assignment

The main problem with this approach is that it only works when the variable to check is immutable. Specifically, it works only with local variables that are not modified between the check and their usage, or val class members that have a backing non-overridable field value. This is because the compiler could not otherwise be sure that the nullable variable was not changed to null after the check.

Filtering null values

When dealing with a collection of a nullable type, you can simply remove them from the equation by filtering them all. This is easily achievable by employing the filterNotNull()  method coming with any Kotlin collection , as follows:

As you can see, the filterNonNull() method returns a list of the corresponding non-nullable type, making the null safety handling issue implicitly solved.

Advanced null safety using Kotlin operators

Kotlin comes with a few custom operators that represent the recommended and advanced way to properly address null safety. Let’s learn how to use them all.

Safe calls operator ?.

The Kotlin safe call operator ?.  allows you to access a field or call a method on a nullable variable. In particular, this operator executes the action on the variable only when its reference is not null. Otherwise, it returns null . Let’s see it in action through an example:

Plus, this operator is particularly useful when performing multiple chain calls. In this case, the chain calls return null if any of the properties are null :

In other words, if any variable in the chain calls is not null , the name in uppercase of the mayor of the fooCity is returned. Otherwise, null is returned.

Keep in mind that the safe call operator can also be used on the left side of an assignment. What happens is that if one of the properties in the safe calls chain is null , then the expression on the right is not evaluated, and the assignment is skipped as a result:

In this case, the assignment is performed only when fooCity and its mayor property are not null .

Also, this operator can be used together with the let() scope function to perform a particular operation only for non-null values:

Learn more about Kotlin’s scope functions here .

Elvis operator ?:

The Kotlin implementation of the Elvis operator ? : allows you to return a default value when the original nullable variable is null . In other words, if the expression before the ?: operator is not null , the Elvis operator returns it.

Otherwise, it returns the expression to the right of the ?: operator. This means that the expression on the right-hand side is evaluated only if the left-hand side is null . Otherwise, it is completely skipped. Let’s see in action below:

This expression reads just like an entire if-else expression, as follows:

Notice that throw and return are regular Kotlin expressions. This means that they can be used on the right-hand side of the ?: operator:

Not-null assertion operator !!

The Kotlin not-null assertion operator !! throws a Kotlin NullPointerException if the variable to which it is applied is null . What this operator does is convert any value to a non-null type and ensure that it is not null by throwing an exception otherwise:

This operator should be used carefully. Specifically, when you have more information than the compiler can have, and you are sure that a nullable variable cannot be null when you are using it.

Null safety Kotlin operators in action

You have seen both basic and advanced ways to deal with null safety in Kotlin. So, you are ready to see the Kotlin operators in action through three real-world examples.

More great articles from LogRocket:

  • Don't miss a moment with The Replay , a curated newsletter from LogRocket
  • Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
  • Use React's useEffect to optimize your application's performance
  • Switch between multiple versions of Node
  • Discover how to use the React children prop with TypeScript
  • Explore creating a custom mouse cursor with CSS
  • Advisory boards aren’t just for executives. Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

?. operator

Let’s see the ?. operator in action through an example:

If executed, this snippet would return:

As you can see, in the first case all names are printed, while in the second case only the non-null names are taken into consideration.

?: operator

Let’s see the ? : operator in action through an example:

When run, this snippet returns:

As you can see, the null value in the name list is replaced by the default <Missing name> string in the printAllOrMissing function thanks to the Elvis operator.

!! operator

Let’s see the !! operator in action through an example:

If run, the following result is printed:

In this case, you can be sure that the name and surname fields will not be null when accessed. On the other hand, the compiler cannot infer this because they do not meet the immutability requirement defined previously.

So, if the !! operator was omitted, the following two errors at compile time would be thrown:

In this article, we looked at what Kotlin null safety represents, how to properly address it, and through which techniques and approaches. As shown, Kotlin comes with many operators and inbuilt functions to deal with null safety and offers you much freedom of action. Plus, Kotlin has been supporting these operators since day one, making null safety one of the most important features coming with the language.

Since Kotlin variables are non-nullable by default, you may encounter a few problems if you are used to programming with Java. This is why we learned the main difference between Java’s and Kotlin’s default behaviors . Also, we delved into the Kotlin null safety operator, understanding how they work, when to use them, why, and how.

Thanks for reading! I hope that you found this article helpful. Feel free to reach out to me with any questions, comments, or suggestions.

LogRocket : Instantly recreate issues in your Android apps.

java null assignment

LogRocket is an Android monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your Android apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your Android apps — try LogRocket for free .

Share this:

  • Click to share on Twitter (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Facebook (Opens in new window)

java null assignment

Stop guessing about your digital experience with LogRocket

Recent posts:.

Comparing Mutative Vs Immer Vs Reducers For Data Handling In React

Comparing React state tools: Mutative vs. Immer vs. reducers

Mutative processes data with better performance than both Immer and native reducers. Let’s compare these data handling options in React.

java null assignment

Radix UI adoption guide: Overview, examples, and alternatives

Radix UI is quickly rising in popularity and has become an excellent go-to solution for building modern design systems and websites.

java null assignment

Understanding the CSS revert-layer keyword

In this article, we’ll explore CSS cascade layers — and, specifically, the revert-layer keyword — to help you refine your styling strategy.

java null assignment

Exploring Nushell, a Rust-powered, cross-platform shell

Nushell is a modern, performant, extensible shell built with Rust. Explore its pros, cons, and how to install and get started with it.

java null assignment

Leave a Reply Cancel reply

Navigation Menu

Search code, repositories, users, issues, pull requests..., provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

  • Notifications

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[java] Null assignment with developer intent #2455

@dailyco

dailyco commented Apr 29, 2020

@dailyco

jsotuyod commented Apr 29, 2020

Sorry, something went wrong.

dailyco commented Apr 30, 2020

No branches or pull requests

@jsotuyod

IMAGES

  1. How to Check Null in Java (with Pictures)

    java null assignment

  2. How to Check if an Object is Null in Java

    java null assignment

  3. How to Check if an Object is Null in Java

    java null assignment

  4. What does null mean in Java

    java null assignment

  5. What is null in Java

    java null assignment

  6. Comment évaluer les types null en Java: 6 étapes

    java null assignment

VIDEO

  1. Java Programming # 44

  2. Flutter Dart Null safety: Null Aware Access and Null Aware Assignment operator

  3. Methods with Argument and without Return values in Java|lec 25| Java Tutorials| BhanuPriya

  4. Core

  5. Исключение Деление на 0 в Java

  6. Java для начинающих

COMMENTS

  1. Avoid Check for Null Statement in Java

    This causes a NullPointerException at line 6. So, accessing any field, method, or index of a null object causes a NullPointerException, as can be seen from the examples above. A common way of avoiding the NullPointerException is to check for null: public void doSomething() {. String result = doSomethingElse();

  2. Best way to check for null values in Java?

    5. Method 4 is far and away the best as it clearly indicates what will happen and uses the minimum of code. Method 3 is just wrong on every level. You know the item may be null so it's not an exceptional situation it's something you should check for. Method 2 is just making it more complicated than it needs to be.

  3. Check If All the Variables of an Object Are Null

    Another option is to use the utility class ObjectUtils from the Apache commons-lang3 library. The ObjectUtils's allNull() method has a generic API that handles any type and number of parameters. That method receives an array of Objects and returns true if all values in that array are null.. Otherwise, return false.Let's first add the latest version of the commons-lang3 dependency to our ...

  4. Java Assignment Operators

    Employee a = null; Compound Assignment Operators. Sometime we need to modify the same variable value and reassigned it to a same reference variable. Java allows you to combine assignment and addition operators using a shorthand operator. For example, the preceding statement can be written as: i +=8; //This is same as i = i+8;

  5. Java Assignment Operators with Examples

    variable operator value; Types of Assignment Operators in Java. The Assignment Operator is generally of two types. They are: 1. Simple Assignment Operator: The Simple Assignment Operator is used with the "=" sign where the left side consists of the operand and the right side consists of a value. The value of the right side must be of the same data type that has been defined on the left side.

  6. Java

    In Java 9, if you have an object which has another object as property and that nested objects has a method yielding a string, then you can use this construct to return an empty string if the embeded object is null : String label = Optional.ofNullable(org.getDiffusion()).map(Diffusion::getLabel).orElse("") In this example :

  7. Chapter 5. Conversions and Contexts

    The contexts are: Assignment contexts ( §5.2 , §15.26 ), in which an expression's value is bound to a named variable. Primitive and reference types are subject to widening, values may be boxed or unboxed, and some primitive constant expressions may be subject to narrowing. An unchecked conversion may also occur.

  8. Nullish coalescing assignment (??=)

    No assignment is performed if the left-hand side is not nullish, due to short-circuiting of the nullish coalescing operator. For example, the following does not throw an error, despite x being const :

  9. All Java Assignment Operators (Explained With Examples)

    There are mainly two types of assignment operators in Java, which are as follows: Simple Assignment Operator ; We use the simple assignment operator with the "=" sign, where the left side consists of an operand and the right side is a value. The value of the operand on the right side must be of the same data type defined on the left side.

  10. What is the advantage of null assignment in Java?

    9. This is an common used idiom, you have to initialize the connection with null, because Java only support initialization for class members, in this scope you have to initialize it with null, because ConnectionFactory.create() maybe also throws an exception. You use this to widen the scope of your variable and use it later, for example to ...

  11. Null Pointer Exception In Java

    Null is a special value used in Java. It is mainly used to indicate that no value is assigned to a reference variable. One application of null is in implementing data structures like linked lists and trees. Other applications include the Null Object pattern (See this for details) and the Singleton pattern. The Singleton pattern ensures that ...

  12. A complete guide to null safety in Kotlin

    This is because Kotlin imposes strict null-safety by default. Let's see what this means: // fooString is a non-nullable reference var fooString: String = "foo". The real difference between Java and Kotlin when dealing with null values becomes clear when trying to give fooString a null value, as follows: fooString = null.

  13. Introduction to the Null Object Pattern

    This is when the Null Object Pattern may come in handy. The intent of the Null Object Pattern is to minimize that kind of null check. Instead, we can identify the null behavior and encapsulate it in the type expected by the client code. More often then not, such neutral logic is very simple - do nothing.

  14. Shortest way to check for null and assign another value if not

    You can also use the null-coalescing operator as other have said - since no one has given an example that works with your code here is one: ... null; variable-assignment; or ask your own question. ... Equivalent to Java's Optional.orElse in C#. 5. Shortest null check in c#. 1. Shortest way of assigning only if source variable is not null ...

  15. [java] Null assignment with developer intent #2455

    dailyco changed the title [java] NullAssignment False Positive Issue [java] Null assignment with developer intent Apr 29, 2020. Copy link Member. jsotuyod commented ... However, as you commented, given the purpose of the Null assignment rule itself, our point of view may be a little off. Thank you for your sincere comment and creating a ...

  16. java

    What is the difference between a variable assigned to null and others not assigned?. An uninitialized variable does not have a value, not even null (which is why it can't be read); An initialized variable does have a value (for instance null, 5 or "hello").; Note that member variables get default values assigned to them automatically (and the default value for a reference type is null).

  17. [Java] Null pointer exception on assignment, while trying to implement

    [Java] Null pointer exception on assignment, while trying to implement a method to return the objects string. ( C background) I took a programming course last term which was C and another one this term being Java, I haven't got the syntax in my head as of now.

  18. Initialize an ArrayList with Zeroes or Null in Java

    The asList() is a method of java.util.Arrays class. Using this method, we can convert an array to a collection. So, for this method, we should initialize an array. Because our array contains only null values at the initialization, we use the method fill() to populate it with our desired value, 0, in