assignment operator expression to complete expression

  • Table of Contents
  • Course Home
  • Assignments
  • Peer Instruction (Instructor)
  • Peer Instruction (Student)
  • Change Course
  • Instructor's Page
  • Progress Page
  • Edit Profile
  • Change Password
  • Scratch ActiveCode
  • Scratch Activecode
  • Instructors Guide
  • About Runestone
  • Report A Problem
  • 1.1 Preface
  • 1.2 Why Programming? Why Java?
  • 1.3 Variables and Data Types
  • 1.4 Expressions and Assignment Statements
  • 1.5 Compound Assignment Operators
  • 1.6 Casting and Ranges of Variables
  • 1.7 Java Development Environments (optional)
  • 1.8 Unit 1 Summary
  • 1.9 Unit 1 Mixed Up Code Practice
  • 1.10 Unit 1 Coding Practice
  • 1.11 Multiple Choice Exercises
  • 1.12 Lesson Workspace
  • 1.3. Variables and Data Types" data-toggle="tooltip">
  • 1.5. Compound Assignment Operators' data-toggle="tooltip" >

Before you keep reading...

Runestone Academy can only continue if we get support from individuals like you. As a student you are well aware of the high cost of textbooks. Our mission is to provide great books to you for free, but we ask that you consider a $10 donation, more if you can or less if $10 is a burden.

Making great stuff takes time and $$. If you appreciate the book you are reading now and want to keep quality materials free for other students please consider a donation to Runestone Academy. We ask that you consider a $10 donation, but if you can give more thats great, if $10 is too much for your budget we would be happy with whatever you can afford as a show of support.

1.4. Expressions and Assignment Statements ¶

In this lesson, you will learn about assignment statements and expressions that contain math operators and variables.

1.4.1. Assignment Statements ¶

Remember that a variable holds a value that can change or vary. Assignment statements initialize or change the value stored in a variable using the assignment operator = . An assignment statement always has a single variable on the left hand side of the = sign. The value of the expression on the right hand side of the = sign (which can contain math operators and other variables) is copied into the memory location of the variable on the left hand side.

Assignment statement

Figure 1: Assignment Statement (variable = expression) ¶

Instead of saying equals for the = operator in an assignment statement, say “gets” or “is assigned” to remember that the variable on the left hand side gets or is assigned the value on the right. In the figure above, score is assigned the value of 10 times points (which is another variable) plus 5.

The following video by Dr. Colleen Lewis shows how variables can change values in memory using assignment statements.

As we saw in the video, we can set one variable to a copy of the value of another variable like y = x;. This won’t change the value of the variable that you are copying from.

coding exercise

Click on the Show CodeLens button to step through the code and see how the values of the variables change.

The program is supposed to figure out the total money value given the number of dimes, quarters and nickels. There is an error in the calculation of the total. Fix the error to compute the correct amount.

Calculate and print the total pay given the weekly salary and the number of weeks worked. Use string concatenation with the totalPay variable to produce the output Total Pay = $3000 . Don’t hardcode the number 3000 in your print statement.

exercise

Assume you have a package with a given height 3 inches and width 5 inches. If the package is rotated 90 degrees, you should swap the values for the height and width. The code below makes an attempt to swap the values stored in two variables h and w, which represent height and width. Variable h should end up with w’s initial value of 5 and w should get h’s initial value of 3. Unfortunately this code has an error and does not work. Use the CodeLens to step through the code to understand why it fails to swap the values in h and w.

1-4-7: Explain in your own words why the ErrorSwap program code does not swap the values stored in h and w.

Swapping two variables requires a third variable. Before assigning h = w , you need to store the original value of h in the temporary variable. In the mixed up programs below, drag the blocks to the right to put them in the right order.

The following has the correct code that uses a third variable named “temp” to swap the values in h and w.

The code is mixed up and contains one extra block which is not needed in a correct solution. Drag the needed blocks from the left into the correct order on the right, then check your solution. You will be told if any of the blocks are in the wrong order or if you need to remove one or more blocks.

After three incorrect attempts you will be able to use the Help Me button to make the problem easier.

Fix the code below to perform a correct swap of h and w. You need to add a new variable named temp to use for the swap.

1.4.2. Incrementing the value of a variable ¶

If you use a variable to keep score you would probably increment it (add one to the current value) whenever score should go up. You can do this by setting the variable to the current value of the variable plus one (score = score + 1) as shown below. The formula looks a little crazy in math class, but it makes sense in coding because the variable on the left is set to the value of the arithmetic expression on the right. So, the score variable is set to the previous value of score + 1.

Click on the Show CodeLens button to step through the code and see how the score value changes.

1-4-11: What is the value of b after the following code executes?

  • It sets the value for the variable on the left to the value from evaluating the right side. What is 5 * 2?
  • Correct. 5 * 2 is 10.

1-4-12: What are the values of x, y, and z after the following code executes?

  • x = 0, y = 1, z = 2
  • These are the initial values in the variable, but the values are changed.
  • x = 1, y = 2, z = 3
  • x changes to y's initial value, y's value is doubled, and z is set to 3
  • x = 2, y = 2, z = 3
  • Remember that the equal sign doesn't mean that the two sides are equal. It sets the value for the variable on the left to the value from evaluating the right side.
  • x = 1, y = 0, z = 3

1.4.3. Operators ¶

Java uses the standard mathematical operators for addition ( + ), subtraction ( - ), multiplication ( * ), and division ( / ). Arithmetic expressions can be of type int or double. An arithmetic operation that uses two int values will evaluate to an int value. An arithmetic operation that uses at least one double value will evaluate to a double value. (You may have noticed that + was also used to put text together in the input program above – more on this when we talk about strings.)

Java uses the operator == to test if the value on the left is equal to the value on the right and != to test if two items are not equal. Don’t get one equal sign = confused with two equal signs == ! They mean different things in Java. One equal sign is used to assign a value to a variable. Two equal signs are used to test a variable to see if it is a certain value and that returns true or false as you’ll see below. Use == and != only with int values and not doubles because double values are an approximation and 3.3333 will not equal 3.3334 even though they are very close.

Run the code below to see all the operators in action. Do all of those operators do what you expected? What about 2 / 3 ? Isn’t surprising that it prints 0 ? See the note below.

When Java sees you doing integer division (or any operation with integers) it assumes you want an integer result so it throws away anything after the decimal point in the answer, essentially rounding down the answer to a whole number. If you need a double answer, you should make at least one of the values in the expression a double like 2.0.

With division, another thing to watch out for is dividing by 0. An attempt to divide an integer by zero will result in an ArithmeticException error message. Try it in one of the active code windows above.

Operators can be used to create compound expressions with more than one operator. You can either use a literal value which is a fixed value like 2, or variables in them. When compound expressions are evaluated, operator precedence rules are used, so that *, /, and % are done before + and -. However, anything in parentheses is done first. It doesn’t hurt to put in extra parentheses if you are unsure as to what will be done first.

In the example below, try to guess what it will print out and then run it to see if you are right. Remember to consider operator precedence .

1-4-15: Consider the following code segment. Be careful about integer division.

What is printed when the code segment is executed?

  • 0.666666666666667
  • Don't forget that division and multiplication will be done first due to operator precedence.
  • Yes, this is equivalent to (5 + ((a/b)*c) - 1).
  • Don't forget that division and multiplication will be done first due to operator precedence, and that an int/int gives an int result where it is rounded down to the nearest int.

1-4-16: Consider the following code segment.

What is the value of the expression?

  • Dividing an integer by an integer results in an integer
  • Correct. Dividing an integer by an integer results in an integer
  • The value 5.5 will be rounded down to 5

1-4-17: Consider the following code segment.

  • Correct. Dividing a double by an integer results in a double
  • Dividing a double by an integer results in a double

1-4-18: Consider the following code segment.

  • Correct. Dividing an integer by an double results in a double
  • Dividing an integer by an double results in a double

1.4.4. The Modulo Operator ¶

The percent sign operator ( % ) is the mod (modulo) or remainder operator. The mod operator ( x % y ) returns the remainder after you divide x (first number) by y (second number) so 5 % 2 will return 1 since 2 goes into 5 two times with a remainder of 1. Remember long division when you had to specify how many times one number went into another evenly and the remainder? That remainder is what is returned by the modulo operator.

../_images/mod-py.png

Figure 2: Long division showing the whole number result and the remainder ¶

In the example below, try to guess what it will print out and then run it to see if you are right.

The result of x % y when x is smaller than y is always x . The value y can’t go into x at all (goes in 0 times), since x is smaller than y , so the result is just x . So if you see 2 % 3 the result is 2 .

1-4-21: What is the result of 158 % 10?

  • This would be the result of 158 divided by 10. modulo gives you the remainder.
  • modulo gives you the remainder after the division.
  • When you divide 158 by 10 you get a remainder of 8.

1-4-22: What is the result of 3 % 8?

  • 8 goes into 3 no times so the remainder is 3. The remainder of a smaller number divided by a larger number is always the smaller number!
  • This would be the remainder if the question was 8 % 3 but here we are asking for the reminder after we divide 3 by 8.
  • What is the remainder after you divide 3 by 8?

1.4.5. FlowCharting ¶

Assume you have 16 pieces of pizza and 5 people. If everyone gets the same number of slices, how many slices does each person get? Are there any leftover pieces?

In industry, a flowchart is used to describe a process through symbols and text. A flowchart usually does not show variable declarations, but it can show assignment statements (drawn as rectangle) and output statements (drawn as rhomboid).

The flowchart in figure 3 shows a process to compute the fair distribution of pizza slices among a number of people. The process relies on integer division to determine slices per person, and the mod operator to determine remaining slices.

Flow Chart

Figure 3: Example Flow Chart ¶

A flowchart shows pseudo-code, which is like Java but not exactly the same. Syntactic details like semi-colons are omitted, and input and output is described in abstract terms.

Complete the program based on the process shown in the Figure 3 flowchart. Note the first line of code declares all 4 variables as type int. Add assignment statements and print statements to compute and print the slices per person and leftover slices. Use System.out.println for output.

1.4.6. Storing User Input in Variables ¶

Variables are a powerful abstraction in programming because the same algorithm can be used with different input values saved in variables.

Program input and output

Figure 4: Program input and output ¶

A Java program can ask the user to type in one or more values. The Java class Scanner is used to read from the keyboard input stream, which is referenced by System.in . Normally the keyboard input is typed into a console window, but since this is running in a browser you will type in a small textbox window displayed below the code. The code below shows an example of prompting the user to enter a name and then printing a greeting. The code String name = scan.nextLine() gets the string value you enter as program input and then stores the value in a variable.

Run the program a few times, typing in a different name. The code works for any name: behold, the power of variables!

Run this program to read in a name from the input stream. You can type a different name in the input window shown below the code.

Try stepping through the code with the CodeLens tool to see how the name variable is assigned to the value read by the scanner. You will have to click “Hide CodeLens” and then “Show in CodeLens” to enter a different name for input.

The Scanner class has several useful methods for reading user input. A token is a sequence of characters separated by white space.

Method

Description

nextLine()

Scans all input up to the line break as a String

next()

Scans the next token of the input as a String

nextInt()

Scans the next token of the input as an int

nextDouble()

Scans the next token of the input as a double

nextBoolean()

Scans the next token of the input as a boolean

Run this program to read in an integer from the input stream. You can type a different integer value in the input window shown below the code.

A rhomboid (slanted rectangle) is used in a flowchart to depict data flowing into and out of a program. The previous flowchart in Figure 3 used a rhomboid to indicate program output. A rhomboid is also used to denote reading a value from the input stream.

Flow Chart

Figure 5: Flow Chart Reading User Input ¶

Figure 5 contains an updated version of the pizza calculator process. The first two steps have been altered to initialize the pizzaSlices and numPeople variables by reading two values from the input stream. In Java this will be done using a Scanner object and reading from System.in.

Complete the program based on the process shown in the Figure 5 flowchart. The program should scan two integer values to initialize pizzaSlices and numPeople. Run the program a few times to experiment with different values for input. What happens if you enter 0 for the number of people? The program will bomb due to division by zero! We will see how to prevent this in a later lesson.

The program below reads two integer values from the input stream and attempts to print the sum. Unfortunately there is a problem with the last line of code that prints the sum.

Run the program and look at the result. When the input is 5 and 7 , the output is Sum is 57 . Both of the + operators in the print statement are performing string concatenation. While the first + operator should perform string concatenation, the second + operator should perform addition. You can force the second + operator to perform addition by putting the arithmetic expression in parentheses ( num1 + num2 ) .

More information on using the Scanner class can be found here https://www.w3schools.com/java/java_user_input.asp

1.4.7. Programming Challenge : Dog Years ¶

In this programming challenge, you will calculate your age, and your pet’s age from your birthdates, and your pet’s age in dog years. In the code below, type in the current year, the year you were born, the year your dog or cat was born (if you don’t have one, make one up!) in the variables below. Then write formulas in assignment statements to calculate how old you are, how old your dog or cat is, and how old they are in dog years which is 7 times a human year. Finally, print it all out.

Calculate your age and your pet’s age from the birthdates, and then your pet’s age in dog years. If you want an extra challenge, try reading the values using a Scanner.

1.4.8. Summary ¶

Arithmetic expressions include expressions of type int and double.

The arithmetic operators consist of +, -, * , /, and % (modulo for the remainder in division).

An arithmetic operation that uses two int values will evaluate to an int value. With integer division, any decimal part in the result will be thrown away, essentially rounding down the answer to a whole number.

An arithmetic operation that uses at least one double value will evaluate to a double value.

Operators can be used to construct compound expressions.

During evaluation, operands are associated with operators according to operator precedence to determine how they are grouped. (*, /, % have precedence over + and -, unless parentheses are used to group those.)

An attempt to divide an integer by zero will result in an ArithmeticException to occur.

The assignment operator (=) allows a program to initialize or change the value stored in a variable. The value of the expression on the right is stored in the variable on the left.

During execution, expressions are evaluated to produce a single value.

The value of an expression has a type based on the evaluation of the expression.




  • A named space for holding data/information
  • The name is often referred to as the identifier
  • A representation of a datum
  • A symbol indicating that an operation is to be performed (on one or more operands)
  • A combination of variables, operators, and literals that represent a single value
  • The smallest syntactically valid construct that conveys a complete command
  • Placing a value into the memory identified by a variable/constant
  • The assignment operator is a binary operator; the left-side operand is a variable/constant and the right-side operand is a literal or an expression (i.e., something that evaluates to a value)
  • initial = 'H'
  • initial = 'H';
  • ok = false;
  • A variable can only contain one value at a time
  • int i; i = 5; // i contains the value 5 i = 27; // i now contains the value 27
  • Confusing the assignment operator with the notion of "equality"
  • Attempting to use expressions like 21 = age (which has an inappropriate left-side operand)
  • The assignment operation evaluates to the value of the right-side operand (so, is an expression)
  • int i, j; i = j = 5;
  • It can cause confusion in more complicated statements, especially those involving arithmetic operators and relational operators
  • In the previous example, which assignment is performed first?
  • Associativity - determines whether (in the absence of other determinants) an expression is evaluated from left to right or right to left
  • The assignment operator has right to left associativity, so i = j = 5 is equivalent to i = (j = 5)
  • Ensuring that the type of the right-side operand is the same as the type of the left-side operand
  • Java does not allow implicit losses of precision
  • Java does allow widenings (though you should refrain from using them)
  • double weight; int age; age = 21.0; // Not allowed (will generate a compile-time error) weight = 155; // Allowed but not recommended (use 155. instead)
  • ( type ) expression
  • Examples: double real; int small; long large; // ... small = (int)large; // ... small = (int)real;
  • Loss of precision
  • Possible loss of magnitude
  • Possible change of sign
  • Indicate that a value can only be assigned to a variable once
  • final type variable [, variable ]... ;
  • final boolean CORRECT;
  • final double BUDGET;
  • final int CAPACITY;
  • Same as for other variables
  • Must be all uppercase
  • Underscores between "words" improve readability
  • An error will be generated if an identifier that is declared to be final is the left-side operand of more than one assignment operator
  • Include the assignment in the declaration
  • The value of the right-side operand is assigned to the left-side operand
  • The address of the right-side operand is assigned to the left-side operand

Python's Assignment Operator: Write Robust Assignments

Python's Assignment Operator: Write Robust Assignments

Table of Contents

The Assignment Statement Syntax

The assignment operator, assignments and variables, other assignment syntax, initializing and updating variables, making multiple variables refer to the same object, updating lists through indices and slices, adding and updating dictionary keys, doing parallel assignments, unpacking iterables, providing default argument values, augmented mathematical assignment operators, augmented assignments for concatenation and repetition, augmented bitwise assignment operators, annotated assignment statements, assignment expressions with the walrus operator, managed attribute assignments, define or call a function, work with classes, import modules and objects, use a decorator, access the control variable in a for loop or a comprehension, use the as keyword, access the _ special variable in an interactive session, built-in objects, named constants.

Python’s assignment operators allow you to define assignment statements . This type of statement lets you create, initialize, and update variables throughout your code. Variables are a fundamental cornerstone in every piece of code, and assignment statements give you complete control over variable creation and mutation.

Learning about the Python assignment operator and its use for writing assignment statements will arm you with powerful tools for writing better and more robust Python code.

In this tutorial, you’ll:

  • Use Python’s assignment operator to write assignment statements
  • Take advantage of augmented assignments in Python
  • Explore assignment variants, like assignment expressions and managed attributes
  • Become aware of illegal and dangerous assignments in Python

You’ll dive deep into Python’s assignment statements. To get the most out of this tutorial, you should be comfortable with several basic topics, including variables , built-in data types , comprehensions , functions , and Python keywords . Before diving into some of the later sections, you should also be familiar with intermediate topics, such as object-oriented programming , constants , imports , type hints , properties , descriptors , and decorators .

Free Source Code: Click here to download the free assignment operator source code that you’ll use to write assignment statements that allow you to create, initialize, and update variables in your code.

Assignment Statements and the Assignment Operator

One of the most powerful programming language features is the ability to create, access, and mutate variables . In Python, a variable is a name that refers to a concrete value or object, allowing you to reuse that value or object throughout your code.

To create a new variable or to update the value of an existing one in Python, you’ll use an assignment statement . This statement has the following three components:

  • A left operand, which must be a variable
  • The assignment operator ( = )
  • A right operand, which can be a concrete value , an object , or an expression

Here’s how an assignment statement will generally look in Python:

Here, variable represents a generic Python variable, while expression represents any Python object that you can provide as a concrete value—also known as a literal —or an expression that evaluates to a value.

To execute an assignment statement like the above, Python runs the following steps:

  • Evaluate the right-hand expression to produce a concrete value or object . This value will live at a specific memory address in your computer.
  • Store the object’s memory address in the left-hand variable . This step creates a new variable if the current one doesn’t already exist or updates the value of an existing variable.

The second step shows that variables work differently in Python than in other programming languages. In Python, variables aren’t containers for objects. Python variables point to a value or object through its memory address. They store memory addresses rather than objects.

This behavior difference directly impacts how data moves around in Python, which is always by reference . In most cases, this difference is irrelevant in your day-to-day coding, but it’s still good to know.

The central component of an assignment statement is the assignment operator . This operator is represented by the = symbol, which separates two operands:

  • A value or an expression that evaluates to a concrete value

Operators are special symbols that perform mathematical , logical , and bitwise operations in a programming language. The objects (or object) on which an operator operates are called operands .

Unary operators, like the not Boolean operator, operate on a single object or operand, while binary operators act on two. That means the assignment operator is a binary operator.

Note: Like C , Python uses == for equality comparisons and = for assignments. Unlike C, Python doesn’t allow you to accidentally use the assignment operator ( = ) in an equality comparison.

Equality is a symmetrical relationship, and assignment is not. For example, the expression a == 42 is equivalent to 42 == a . In contrast, the statement a = 42 is correct and legal, while 42 = a isn’t allowed. You’ll learn more about illegal assignments later on.

The right-hand operand in an assignment statement can be any Python object, such as a number , list , string , dictionary , or even a user-defined object. It can also be an expression. In the end, expressions always evaluate to concrete objects, which is their return value.

Here are a few examples of assignments in Python:

The first two sample assignments in this code snippet use concrete values, also known as literals , to create and initialize number and greeting . The third example assigns the result of a math expression to the total variable, while the last example uses a Boolean expression.

Note: You can use the built-in id() function to inspect the memory address stored in a given variable.

Here’s a short example of how this function works:

The number in your output represents the memory address stored in number . Through this address, Python can access the content of number , which is the integer 42 in this example.

If you run this code on your computer, then you’ll get a different memory address because this value varies from execution to execution and computer to computer.

Unlike expressions, assignment statements don’t have a return value because their purpose is to make the association between the variable and its value. That’s why the Python interpreter doesn’t issue any output in the above examples.

Now that you know the basics of how to write an assignment statement, it’s time to tackle why you would want to use one.

The assignment statement is the explicit way for you to associate a name with an object in Python. You can use this statement for two main purposes:

  • Creating and initializing new variables
  • Updating the values of existing variables

When you use a variable name as the left operand in an assignment statement for the first time, you’re creating a new variable. At the same time, you’re initializing the variable to point to the value of the right operand.

On the other hand, when you use an existing variable in a new assignment, you’re updating or mutating the variable’s value. Strictly speaking, every new assignment will make the variable refer to a new value and stop referring to the old one. Python will garbage-collect all the values that are no longer referenced by any existing variable.

Assignment statements not only assign a value to a variable but also determine the data type of the variable at hand. This additional behavior is another important detail to consider in this kind of statement.

Because Python is a dynamically typed language, successive assignments to a given variable can change the variable’s data type. Changing the data type of a variable during a program’s execution is considered bad practice and highly discouraged. It can lead to subtle bugs that can be difficult to track down.

Unlike in math equations, in Python assignments, the left operand must be a variable rather than an expression or a value. For example, the following construct is illegal, and Python flags it as invalid syntax:

In this example, you have expressions on both sides of the = sign, and this isn’t allowed in Python code. The error message suggests that you may be confusing the equality operator with the assignment one, but that’s not the case. You’re really running an invalid assignment.

To correct this construct and convert it into a valid assignment, you’ll have to do something like the following:

In this code snippet, you first import the sqrt() function from the math module. Then you isolate the hypotenuse variable in the original equation by using the sqrt() function. Now your code works correctly.

Now you know what kind of syntax is invalid. But don’t get the idea that assignment statements are rigid and inflexible. In fact, they offer lots of room for customization, as you’ll learn next.

Python’s assignment statements are pretty flexible and versatile. You can write them in several ways, depending on your specific needs and preferences. Here’s a quick summary of the main ways to write assignments in Python:

Up to this point, you’ve mostly learned about the base assignment syntax in the above code snippet. In the following sections, you’ll learn about multiple, parallel, and augmented assignments. You’ll also learn about assignments with iterable unpacking.

Read on to see the assignment statements in action!

Assignment Statements in Action

You’ll find and use assignment statements everywhere in your Python code. They’re a fundamental part of the language, providing an explicit way to create, initialize, and mutate variables.

You can use assignment statements with plain names, like number or counter . You can also use assignments in more complicated scenarios, such as with:

  • Qualified attribute names , like user.name
  • Indices and slices of mutable sequences, like a_list[i] and a_list[i:j]
  • Dictionary keys , like a_dict[key]

This list isn’t exhaustive. However, it gives you some idea of how flexible these statements are. You can even assign multiple values to an equal number of variables in a single line, commonly known as parallel assignment . Additionally, you can simultaneously assign the values in an iterable to a comma-separated group of variables in what’s known as an iterable unpacking operation.

In the following sections, you’ll dive deeper into all these topics and a few other exciting things that you can do with assignment statements in Python.

The most elementary use case of an assignment statement is to create a new variable and initialize it using a particular value or expression:

All these statements create new variables, assigning them initial values or expressions. For an initial value, you should always use the most sensible and least surprising value that you can think of. For example, initializing a counter to something different from 0 may be confusing and unexpected because counters almost always start having counted no objects.

Updating a variable’s current value or state is another common use case of assignment statements. In Python, assigning a new value to an existing variable doesn’t modify the variable’s current value. Instead, it causes the variable to refer to a different value. The previous value will be garbage-collected if no other variable refers to it.

Consider the following examples:

These examples run two consecutive assignments on the same variable. The first one assigns the string "Hello, World!" to a new variable named greeting .

The second assignment updates the value of greeting by reassigning it the "Hi, Pythonistas!" string. In this example, the original value of greeting —the "Hello, World!" string— is lost and garbage-collected. From this point on, you can’t access the old "Hello, World!" string.

Even though running multiple assignments on the same variable during a program’s execution is common practice, you should use this feature with caution. Changing the value of a variable can make your code difficult to read, understand, and debug. To comprehend the code fully, you’ll have to remember all the places where the variable was changed and the sequential order of those changes.

Because assignments also define the data type of their target variables, it’s also possible for your code to accidentally change the type of a given variable at runtime. A change like this can lead to breaking errors, like AttributeError exceptions. Remember that strings don’t have the same methods and attributes as lists or dictionaries, for example.

In Python, you can make several variables reference the same object in a multiple-assignment line. This can be useful when you want to initialize several similar variables using the same initial value:

In this example, you chain two assignment operators in a single line. This way, your two variables refer to the same initial value of 0 . Note how both variables hold the same memory address, so they point to the same instance of 0 .

When it comes to integer variables, Python exhibits a curious behavior. It provides a numeric interval where multiple assignments behave the same as independent assignments. Consider the following examples:

To create n and m , you use independent assignments. Therefore, they should point to different instances of the number 42 . However, both variables hold the same object, which you confirm by comparing their corresponding memory addresses.

Now check what happens when you use a greater initial value:

Now n and m hold different memory addresses, which means they point to different instances of the integer number 300 . In contrast, when you use multiple assignments, both variables refer to the same object. This tiny difference can save you small bits of memory if you frequently initialize integer variables in your code.

The implicit behavior of making independent assignments point to the same integer number is actually an optimization called interning . It consists of globally caching the most commonly used integer values in day-to-day programming.

Under the hood, Python defines a numeric interval in which interning takes place. That’s the interning interval for integer numbers. You can determine this interval using a small script like the following:

This script helps you determine the interning interval by comparing integer numbers from -10 to 500 . If you run the script from your command line, then you’ll get an output like the following:

This output means that if you use a single number between -5 and 256 to initialize several variables in independent statements, then all these variables will point to the same object, which will help you save small bits of memory in your code.

In contrast, if you use a number that falls outside of the interning interval, then your variables will point to different objects instead. Each of these objects will occupy a different memory spot.

You can use the assignment operator to mutate the value stored at a given index in a Python list. The operator also works with list slices . The syntax to write these types of assignment statements is the following:

In the first construct, expression can return any Python object, including another list. In the second construct, expression must return a series of values as a list, tuple, or any other sequence. You’ll get a TypeError if expression returns a single value.

Note: When creating slice objects, you can use up to three arguments. These arguments are start , stop , and step . They define the number that starts the slice, the number at which the slicing must stop retrieving values, and the step between values.

Here’s an example of updating an individual value in a list:

In this example, you update the value at index 2 using an assignment statement. The original number at that index was 7 , and after the assignment, the number is 3 .

Note: Using indices and the assignment operator to update a value in a tuple or a character in a string isn’t possible because tuples and strings are immutable data types in Python.

Their immutability means that you can’t change their items in place :

You can’t use the assignment operator to change individual items in tuples or strings. These data types are immutable and don’t support item assignments.

It’s important to note that you can’t add new values to a list by using indices that don’t exist in the target list:

In this example, you try to add a new value to the end of numbers by using an index that doesn’t exist. This assignment isn’t allowed because there’s no way to guarantee that new indices will be consecutive. If you ever want to add a single value to the end of a list, then use the .append() method.

If you want to update several consecutive values in a list, then you can use slicing and an assignment statement:

In the first example, you update the letters between indices 1 and 3 without including the letter at 3 . The second example updates the letters from index 3 until the end of the list. Note that this slicing appends a new value to the list because the target slice is shorter than the assigned values.

Also note that the new values were provided through a tuple, which means that this type of assignment allows you to use other types of sequences to update your target list.

The third example updates a single value using a slice where both indices are equal. In this example, the assignment inserts a new item into your target list.

In the final example, you use a step of 2 to replace alternating letters with their lowercase counterparts. This slicing starts at index 1 and runs through the whole list, stepping by two items each time.

Updating the value of an existing key or adding new key-value pairs to a dictionary is another common use case of assignment statements. To do these operations, you can use the following syntax:

The first construct helps you update the current value of an existing key, while the second construct allows you to add a new key-value pair to the dictionary.

For example, to update an existing key, you can do something like this:

In this example, you update the current inventory of oranges in your store using an assignment. The left operand is the existing dictionary key, and the right operand is the desired new value.

While you can’t add new values to a list by assignment, dictionaries do allow you to add new key-value pairs using the assignment operator. In the example below, you add a lemon key to inventory :

In this example, you successfully add a new key-value pair to your inventory with 100 units. This addition is possible because dictionaries don’t have consecutive indices but unique keys, which are safe to add by assignment.

The assignment statement does more than assign the result of a single expression to a single variable. It can also cope nicely with assigning multiple values to multiple variables simultaneously in what’s known as a parallel assignment .

Here’s the general syntax for parallel assignments in Python:

Note that the left side of the statement can be either a tuple or a list of variables. Remember that to create a tuple, you just need a series of comma-separated elements. In this case, these elements must be variables.

The right side of the statement must be a sequence or iterable of values or expressions. In any case, the number of elements in the right operand must match the number of variables on the left. Otherwise, you’ll get a ValueError exception.

In the following example, you compute the two solutions of a quadratic equation using a parallel assignment:

In this example, you first import sqrt() from the math module. Then you initialize the equation’s coefficients in a parallel assignment.

The equation’s solution is computed in another parallel assignment. The left operand contains a tuple of two variables, x1 and x2 . The right operand consists of a tuple of expressions that compute the solutions for the equation. Note how each result is assigned to each variable by position.

A classical use case of parallel assignment is to swap values between variables:

The highlighted line does the magic and swaps the values of previous_value and next_value at the same time. Note that in a programming language that doesn’t support this kind of assignment, you’d have to use a temporary variable to produce the same effect:

In this example, instead of using parallel assignment to swap values between variables, you use a new variable to temporarily store the value of previous_value to avoid losing its reference.

For a concrete example of when you’d need to swap values between variables, say you’re learning how to implement the bubble sort algorithm , and you come up with the following function:

In the highlighted line, you use a parallel assignment to swap values in place if the current value is less than the next value in the input list. To dive deeper into the bubble sort algorithm and into sorting algorithms in general, check out Sorting Algorithms in Python .

You can use assignment statements for iterable unpacking in Python. Unpacking an iterable means assigning its values to a series of variables one by one. The iterable must be the right operand in the assignment, while the variables must be the left operand.

Like in parallel assignments, the variables must come as a tuple or list. The number of variables must match the number of values in the iterable. Alternatively, you can use the unpacking operator ( * ) to grab several values in a variable if the number of variables doesn’t match the iterable length.

Here’s the general syntax for iterable unpacking in Python:

Iterable unpacking is a powerful feature that you can use all around your code. It can help you write more readable and concise code. For example, you may find yourself doing something like this:

Whenever you do something like this in your code, go ahead and replace it with a more readable iterable unpacking using a single and elegant assignment, like in the following code snippet:

The numbers list on the right side contains four values. The assignment operator unpacks these values into the four variables on the left side of the statement. The values in numbers get assigned to variables in the same order that they appear in the iterable. The assignment is done by position.

Note: Because Python sets are also iterables, you can use them in an iterable unpacking operation. However, it won’t be clear which value goes to which variable because sets are unordered data structures.

The above example shows the most common form of iterable unpacking in Python. The main condition for the example to work is that the number of variables matches the number of values in the iterable.

What if you don’t know the iterable length upfront? Will the unpacking work? It’ll work if you use the * operator to pack several values into one of your target variables.

For example, say that you want to unpack the first and second values in numbers into two different variables. Additionally, you would like to pack the rest of the values in a single variable conveniently called rest . In this case, you can use the unpacking operator like in the following code:

In this example, first and second hold the first and second values in numbers , respectively. These values are assigned by position. The * operator packs all the remaining values in the input iterable into rest .

The unpacking operator ( * ) can appear at any position in your series of target variables. However, you can only use one instance of the operator:

The iterable unpacking operator works in any position in your list of variables. Note that you can only use one unpacking operator per assignment. Using more than one unpacking operator isn’t allowed and raises a SyntaxError .

Dropping away unwanted values from the iterable is a common use case for the iterable unpacking operator. Consider the following example:

In Python, if you want to signal that a variable won’t be used, then you use an underscore ( _ ) as the variable’s name. In this example, useful holds the only value that you need to use from the input iterable. The _ variable is a placeholder that guarantees that the unpacking works correctly. You won’t use the values that end up in this disposable variable.

Note: In the example above, if your target iterable is a sequence data type, such as a list or tuple, then it’s best to access its last item directly.

To do this, you can use the -1 index:

Using -1 gives you access to the last item of any sequence data type. In contrast, if you’re dealing with iterators , then you won’t be able to use indices. That’s when the *_ syntax comes to your rescue.

The pattern used in the above example comes in handy when you have a function that returns multiple values, and you only need a few of these values in your code. The os.walk() function may provide a good example of this situation.

This function allows you to iterate over the content of a directory recursively. The function returns a generator object that yields three-item tuples. Each tuple contains the following items:

  • The path to the current directory as a string
  • The names of all the immediate subdirectories as a list of strings
  • The names of all the files in the current directory as a list of strings

Now say that you want to iterate over your home directory and list only the files. You can do something like this:

This code will issue a long output depending on the current content of your home directory. Note that you need to provide a string with the path to your user folder for the example to work. The _ placeholder variable will hold the unwanted data.

In contrast, the filenames variable will hold the list of files in the current directory, which is the data that you need. The code will print the list of filenames. Go ahead and give it a try!

The assignment operator also comes in handy when you need to provide default argument values in your functions and methods. Default argument values allow you to define functions that take arguments with sensible defaults. These defaults allow you to call the function with specific values or to simply rely on the defaults.

As an example, consider the following function:

This function takes one argument, called name . This argument has a sensible default value that’ll be used when you call the function without arguments. To provide this sensible default value, you use an assignment.

Note: According to PEP 8 , the style guide for Python code, you shouldn’t use spaces around the assignment operator when providing default argument values in function definitions.

Here’s how the function works:

If you don’t provide a name during the call to greet() , then the function uses the default value provided in the definition. If you provide a name, then the function uses it instead of the default one.

Up to this point, you’ve learned a lot about the Python assignment operator and how to use it for writing different types of assignment statements. In the following sections, you’ll dive into a great feature of assignment statements in Python. You’ll learn about augmented assignments .

Augmented Assignment Operators in Python

Python supports what are known as augmented assignments . An augmented assignment combines the assignment operator with another operator to make the statement more concise. Most Python math and bitwise operators have an augmented assignment variation that looks something like this:

Note that $ isn’t a valid Python operator. In this example, it’s a placeholder for a generic operator. This statement works as follows:

  • Evaluate expression to produce a value.
  • Run the operation defined by the operator that prefixes the = sign, using the previous value of variable and the return value of expression as operands.
  • Assign the resulting value back to variable .

In practice, an augmented assignment like the above is equivalent to the following statement:

As you can conclude, augmented assignments are syntactic sugar . They provide a shorthand notation for a specific and popular kind of assignment.

For example, say that you need to define a counter variable to count some stuff in your code. You can use the += operator to increment counter by 1 using the following code:

In this example, the += operator, known as augmented addition , adds 1 to the previous value in counter each time you run the statement counter += 1 .

It’s important to note that unlike regular assignments, augmented assignments don’t create new variables. They only allow you to update existing variables. If you use an augmented assignment with an undefined variable, then you get a NameError :

Python evaluates the right side of the statement before assigning the resulting value back to the target variable. In this specific example, when Python tries to compute x + 1 , it finds that x isn’t defined.

Great! You now know that an augmented assignment consists of combining the assignment operator with another operator, like a math or bitwise operator. To continue this discussion, you’ll learn which math operators have an augmented variation in Python.

An equation like x = x + b doesn’t make sense in math. But in programming, a statement like x = x + b is perfectly valid and can be extremely useful. It adds b to x and reassigns the result back to x .

As you already learned, Python provides an operator to shorten x = x + b . Yes, the += operator allows you to write x += b instead. Python also offers augmented assignment operators for most math operators. Here’s a summary:

Operator Description Example Equivalent
Adds the right operand to the left operand and stores the result in the left operand
Subtracts the right operand from the left operand and stores the result in the left operand
Multiplies the right operand with the left operand and stores the result in the left operand
Divides the left operand by the right operand and stores the result in the left operand
Performs of the left operand by the right operand and stores the result in the left operand
Finds the remainder of dividing the left operand by the right operand and stores the result in the left operand
Raises the left operand to the power of the right operand and stores the result in the left operand

The Example column provides generic examples of how to use the operators in actual code. Note that x must be previously defined for the operators to work correctly. On the other hand, y can be either a concrete value or an expression that returns a value.

Note: The matrix multiplication operator ( @ ) doesn’t support augmented assignments yet.

Consider the following example of matrix multiplication using NumPy arrays:

Note that the exception traceback indicates that the operation isn’t supported yet.

To illustrate how augmented assignment operators work, say that you need to create a function that takes an iterable of numeric values and returns their sum. You can write this function like in the code below:

In this function, you first initialize total to 0 . In each iteration, the loop adds a new number to total using the augmented addition operator ( += ). When the loop terminates, total holds the sum of all the input numbers. Variables like total are known as accumulators . The += operator is typically used to update accumulators.

Note: Computing the sum of a series of numeric values is a common operation in programming. Python provides the built-in sum() function for this specific computation.

Another interesting example of using an augmented assignment is when you need to implement a countdown while loop to reverse an iterable. In this case, you can use the -= operator:

In this example, custom_reversed() is a generator function because it uses yield . Calling the function creates an iterator that yields items from the input iterable in reverse order. To decrement the control variable, index , you use an augmented subtraction statement that subtracts 1 from the variable in every iteration.

Note: Similar to summing the values in an iterable, reversing an iterable is also a common requirement. Python provides the built-in reversed() function for this specific computation, so you don’t have to implement your own. The above example only intends to show the -= operator in action.

Finally, counters are a special type of accumulators that allow you to count objects. Here’s an example of a letter counter:

To create this counter, you use a Python dictionary. The keys store the letters. The values store the counts. Again, to increment the counter, you use an augmented addition.

Counters are so common in programming that Python provides a tool specially designed to facilitate the task of counting. Check out Python’s Counter: The Pythonic Way to Count Objects for a complete guide on how to use this tool.

The += and *= augmented assignment operators also work with sequences , such as lists, tuples, and strings. The += operator performs augmented concatenations , while the *= operator performs augmented repetition .

These operators behave differently with mutable and immutable data types:

Operator Description Example
Runs an augmented concatenation operation on the target sequence. Mutable sequences are updated in place. If the sequence is immutable, then a new sequence is created and assigned back to the target name.
Adds to itself times. Mutable sequences are updated in place. If the sequence is immutable, then a new sequence is created and assigned back to the target name.

Note that the augmented concatenation operator operates on two sequences, while the augmented repetition operator works on a sequence and an integer number.

Consider the following examples and pay attention to the result of calling the id() function:

Mutable sequences like lists support the += augmented assignment operator through the .__iadd__() method, which performs an in-place addition. This method mutates the underlying list, appending new values to its end.

Note: If the left operand is mutable, then x += y may not be completely equivalent to x = x + y . For example, if you do list_1 = list_1 + list_2 instead of list_1 += list_2 above, then you’ll create a new list instead of mutating the existing one. This may be important if other variables refer to the same list.

Immutable sequences, such as tuples and strings, don’t provide an .__iadd__() method. Therefore, augmented concatenations fall back to the .__add__() method, which doesn’t modify the sequence in place but returns a new sequence.

There’s another difference between mutable and immutable sequences when you use them in an augmented concatenation. Consider the following examples:

With mutable sequences, the data to be concatenated can come as a list, tuple, string, or any other iterable. In contrast, with immutable sequences, the data can only come as objects of the same type. You can concatenate tuples to tuples and strings to strings, for example.

Again, the augmented repetition operator works with a sequence on the left side of the operator and an integer on the right side. This integer value represents the number of repetitions to get in the resulting sequence:

When the *= operator operates on a mutable sequence, it falls back to the .__imul__() method, which performs the operation in place, modifying the underlying sequence. In contrast, if *= operates on an immutable sequence, then .__mul__() is called, returning a new sequence of the same type.

Note: Values of n less than 0 are treated as 0 , which returns an empty sequence of the same data type as the target sequence on the left side of the *= operand.

Note that a_list[0] is a_list[3] returns True . This is because the *= operator doesn’t make a copy of the repeated data. It only reflects the data. This behavior can be a source of issues when you use the operator with mutable values.

For example, say that you want to create a list of lists to represent a matrix, and you need to initialize the list with n empty lists, like in the following code:

In this example, you use the *= operator to populate matrix with three empty lists. Now check out what happens when you try to populate the first sublist in matrix :

The appended values are reflected in the three sublists. This happens because the *= operator doesn’t make copies of the data that you want to repeat. It only reflects the data. Therefore, every sublist in matrix points to the same object and memory address.

If you ever need to initialize a list with a bunch of empty sublists, then use a list comprehension :

This time, when you populate the first sublist of matrix , your changes aren’t propagated to the other sublists. This is because all the sublists are different objects that live in different memory addresses.

Bitwise operators also have their augmented versions. The logic behind them is similar to that of the math operators. The following table summarizes the augmented bitwise operators that Python provides:

Operator Operation Example Equivalent
Augmented bitwise AND ( )
Augmented bitwise OR ( )
Augmented bitwise XOR ( )
Augmented bitwise right shift
Augmented bitwise left shift

The augmented bitwise assignment operators perform the intended operation by taking the current value of the left operand as a starting point for the computation. Consider the following example, which uses the & and &= operators:

Programmers who work with high-level languages like Python rarely use bitwise operations in day-to-day coding. However, these types of operations can be useful in some situations.

For example, say that you’re implementing a Unix-style permission system for your users to access a given resource. In this case, you can use the characters "r" for reading, "w" for writing, and "x" for execution permissions, respectively. However, using bit-based permissions could be more memory efficient:

You can assign permissions to your users with the OR bitwise operator or the augmented OR bitwise operator. Finally, you can use the bitwise AND operator to check if a user has a certain permission, as you did in the final two examples.

You’ve learned a lot about augmented assignment operators and statements in this and the previous sections. These operators apply to math, concatenation, repetition, and bitwise operations. Now you’re ready to look at other assignment variants that you can use in your code or find in other developers’ code.

Other Assignment Variants

So far, you’ve learned that Python’s assignment statements and the assignment operator are present in many different scenarios and use cases. Those use cases include variable creation and initialization, parallel assignments, iterable unpacking, augmented assignments, and more.

In the following sections, you’ll learn about a few variants of assignment statements that can be useful in your future coding. You can also find these assignment variants in other developers’ code. So, you should be aware of them and know how they work in practice.

In short, you’ll learn about:

  • Annotated assignment statements with type hints
  • Assignment expressions with the walrus operator
  • Managed attribute assignments with properties and descriptors
  • Implicit assignments in Python

These topics will take you through several interesting and useful examples that showcase the power of Python’s assignment statements.

PEP 526 introduced a dedicated syntax for variable annotation back in Python 3.6 . The syntax consists of the variable name followed by a colon ( : ) and the variable type:

Even though these statements declare three variables with their corresponding data types, the variables aren’t actually created or initialized. So, for example, you can’t use any of these variables in an augmented assignment statement:

If you try to use one of the previously declared variables in an augmented assignment, then you get a NameError because the annotation syntax doesn’t define the variable. To actually define it, you need to use an assignment.

The good news is that you can use the variable annotation syntax in an assignment statement with the = operator:

The first statement in this example is what you can call an annotated assignment statement in Python. You may ask yourself why you should use type annotations in this type of assignment if everybody can see that counter holds an integer number. You’re right. In this example, the variable type is unambiguous.

However, imagine what would happen if you found a variable initialization like the following:

What would be the data type of each user in users ? If the initialization of users is far away from the definition of the User class, then there’s no quick way to answer this question. To clarify this ambiguity, you can provide the appropriate type hint for users :

Now you’re clearly communicating that users will hold a list of User instances. Using type hints in assignment statements that initialize variables to empty collection data types—such as lists, tuples, or dictionaries—allows you to provide more context about how your code works. This practice will make your code more explicit and less error-prone.

Up to this point, you’ve learned that regular assignment statements with the = operator don’t have a return value. They just create or update variables. Therefore, you can’t use a regular assignment to assign a value to a variable within the context of an expression.

Python 3.8 changed this by introducing a new type of assignment statement through PEP 572 . This new statement is known as an assignment expression or named expression .

Note: Expressions are a special type of statement in Python. Their distinguishing characteristic is that expressions always have a return value, which isn’t the case with all types of statements.

Unlike regular assignments, assignment expressions have a return value, which is why they’re called expressions in the first place. This return value is automatically assigned to a variable. To write an assignment expression, you must use the walrus operator ( := ), which was named for its resemblance to the eyes and tusks of a walrus lying on its side.

The general syntax of an assignment statement is as follows:

This expression looks like a regular assignment. However, instead of using the assignment operator ( = ), it uses the walrus operator ( := ). For the expression to work correctly, the enclosing parentheses are required in most use cases. However, there are certain situations in which these parentheses are superfluous. Either way, they won’t hurt you.

Assignment expressions come in handy when you want to reuse the result of an expression or part of an expression without using a dedicated assignment to grab this value beforehand.

Note: Assignment expressions with the walrus operator have several practical use cases. They also have a few restrictions. For example, they’re illegal in certain contexts, such as lambda functions, parallel assignments, and augmented assignments.

For a deep dive into this special type of assignment, check out The Walrus Operator: Python’s Assignment Expressions .

A particularly handy use case for assignment expressions is when you need to grab the result of an expression used in the context of a conditional statement. For example, say that you need to write a function to compute the mean of a sample of numeric values. Without the walrus operator, you could do something like this:

In this example, the sample size ( n ) is a value that you need to reuse in two different computations. First, you need to check whether the sample has data points or not. Then you need to use the sample size to compute the mean. To be able to reuse n , you wrote a dedicated assignment statement at the beginning of your function to grab the sample size.

You can avoid this extra step by combining it with the first use of the target value, len(sample) , using an assignment expression like the following:

The assignment expression introduced in the conditional computes the sample size and assigns it to n . This way, you guarantee that you have a reference to the sample size to use in further computations.

Because the assignment expression returns the sample size anyway, the conditional can check whether that size equals 0 or not and then take a certain course of action depending on the result of this check. The return statement computes the sample’s mean and sends the result back to the function caller.

Python provides a few tools that allow you to fine-tune the operations behind the assignment of attributes. The attributes that run implicit operations on assignments are commonly referred to as managed attributes .

Properties are the most commonly used tool for providing managed attributes in your classes. However, you can also use descriptors and, in some cases, the .__setitem__() special method.

To understand what fine-tuning the operation behind an assignment means, say that you need a Point class that only allows numeric values for its coordinates, x and y . To write this class, you must set up a validation mechanism to reject non-numeric values. You can use properties to attach the validation functionality on top of x and y .

Here’s how you can write your class:

In Point , you use properties for the .x and .y coordinates. Each property has a getter and a setter method . The getter method returns the attribute at hand. The setter method runs the input validation using a try … except block and the built-in float() function. Then the method assigns the result to the actual attribute.

Here’s how your class works in practice:

When you use a property-based attribute as the left operand in an assignment statement, Python automatically calls the property’s setter method, running any computation from it.

Because both .x and .y are properties, the input validation runs whenever you assign a value to either attribute. In the first example, the input values are valid numbers and the validation passes. In the final example, "one" isn’t a valid numeric value, so the validation fails.

If you look at your Point class, you’ll note that it follows a repetitive pattern, with the getter and setter methods looking quite similar. To avoid this repetition, you can use a descriptor instead of a property.

A descriptor is a class that implements the descriptor protocol , which consists of four special methods :

  • .__get__() runs when you access the attribute represented by the descriptor.
  • .__set__() runs when you use the attribute in an assignment statement.
  • .__delete__() runs when you use the attribute in a del statement.
  • .__set_name__() sets the attribute’s name, creating a name-aware attribute.

Here’s how your code may look if you use a descriptor to represent the coordinates of your Point class:

You’ve removed repetitive code by defining Coordinate as a descriptor that manages the input validation in a single place. Go ahead and run the following code to try out the new implementation of Point :

Great! The class works as expected. Thanks to the Coordinate descriptor, you now have a more concise and non-repetitive version of your original code.

Another way to fine-tune the operations behind an assignment statement is to provide a custom implementation of .__setitem__() in your class. You’ll use this method in classes representing mutable data collections, such as custom list-like or dictionary-like classes.

As an example, say that you need to create a dictionary-like class that stores its keys in lowercase letters:

In this example, you create a dictionary-like class by subclassing UserDict from collections . Your class implements a .__setitem__() method, which takes key and value as arguments. The method uses str.lower() to convert key into lowercase letters before storing it in the underlying dictionary.

Python implicitly calls .__setitem__() every time you use a key as the left operand in an assignment statement. This behavior allows you to tweak how you process the assignment of keys in your custom dictionary.

Implicit Assignments in Python

Python implicitly runs assignments in many different contexts. In most cases, these implicit assignments are part of the language syntax. In other cases, they support specific behaviors.

Whenever you complete an action in the following list, Python runs an implicit assignment for you:

  • Define or call a function
  • Define or instantiate a class
  • Use the current instance , self
  • Import modules and objects
  • Use a decorator
  • Use the control variable in a for loop or a comprehension
  • Use the as qualifier in with statements , imports, and try … except blocks
  • Access the _ special variable in an interactive session

Behind the scenes, Python performs an assignment in every one of the above situations. In the following subsections, you’ll take a tour of all these situations.

When you define a function, the def keyword implicitly assigns a function object to your function’s name. Here’s an example:

From this point on, the name greet refers to a function object that lives at a given memory address in your computer. You can call the function using its name and a pair of parentheses with appropriate arguments. This way, you can reuse greet() wherever you need it.

If you call your greet() function with fellow as an argument, then Python implicitly assigns the input argument value to the name parameter on the function’s definition. The parameter will hold a reference to the input arguments.

When you define a class with the class keyword, you’re assigning a specific name to a class object . You can later use this name to create instances of that class. Consider the following example:

In this example, the name User holds a reference to a class object, which was defined in __main__.User . Like with a function, when you call the class’s constructor with the appropriate arguments to create an instance, Python assigns the arguments to the parameters defined in the class initializer .

Another example of implicit assignments is the current instance of a class, which in Python is called self by convention. This name implicitly gets a reference to the current object whenever you instantiate a class. Thanks to this implicit assignment, you can access .name and .job from within the class without getting a NameError in your code.

Import statements are another variant of implicit assignments in Python. Through an import statement, you assign a name to a module object, class, function, or any other imported object. This name is then created in your current namespace so that you can access it later in your code:

In this example, you import the sys module object from the standard library and assign it to the sys name, which is now available in your namespace, as you can conclude from the second call to the built-in dir() function.

You also run an implicit assignment when you use a decorator in your code. The decorator syntax is just a shortcut for a formal assignment like the following:

Here, you call decorator() with a function object as an argument. This call will typically add functionality on top of the existing function, func() , and return a function object, which is then reassigned to the func name.

The decorator syntax is syntactic sugar for replacing the previous assignment, which you can now write as follows:

Even though this new code looks pretty different from the above assignment, the code implicitly runs the same steps.

Another situation in which Python automatically runs an implicit assignment is when you use a for loop or a comprehension. In both cases, you can have one or more control variables that you then use in the loop or comprehension body:

The memory address of control_variable changes on each iteration of the loop. This is because Python internally reassigns a new value from the loop iterable to the loop control variable on each cycle.

The same behavior appears in comprehensions:

In the end, comprehensions work like for loops but use a more concise syntax. This comprehension creates a new list of strings that mimic the output from the previous example.

The as keyword in with statements, except clauses, and import statements is another example of an implicit assignment in Python. This time, the assignment isn’t completely implicit because the as keyword provides an explicit way to define the target variable.

In a with statement, the target variable that follows the as keyword will hold a reference to the context manager that you’re working with. As an example, say that you have a hello.txt file with the following content:

You want to open this file and print each of its lines on your screen. In this case, you can use the with statement to open the file using the built-in open() function.

In the example below, you accomplish this. You also add some calls to print() that display information about the target variable defined by the as keyword:

This with statement uses the open() function to open hello.txt . The open() function is a context manager that returns a text file object represented by an io.TextIOWrapper instance.

Since you’ve defined a hello target variable with the as keyword, now that variable holds a reference to the file object itself. You confirm this by printing the object and its memory address. Finally, the for loop iterates over the lines and prints this content to the screen.

When it comes to using the as keyword in the context of an except clause, the target variable will contain an exception object if any exception occurs:

In this example, you run a division that raises a ZeroDivisionError . The as keyword assigns the raised exception to error . Note that when you print the exception object, you get only the message because exceptions have a custom .__str__() method that supports this behavior.

There’s a final detail to remember when using the as specifier in a try … except block like the one in the above example. Once you leave the except block, the target variable goes out of scope , and you can’t use it anymore.

Finally, Python’s import statements also support the as keyword. In this context, you can use as to import objects with a different name:

In these examples, you use the as keyword to import the numpy package with the np name and pandas with the name pd . If you call dir() , then you’ll realize that np and pd are now in your namespace. However, the numpy and pandas names are not.

Using the as keyword in your imports comes in handy when you want to use shorter names for your objects or when you need to use different objects that originally had the same name in your code. It’s also useful when you want to make your imported names non-public using a leading underscore, like in import sys as _sys .

The final implicit assignment that you’ll learn about in this tutorial only occurs when you’re using Python in an interactive session. Every time you run a statement that returns a value, the interpreter stores the result in a special variable denoted by a single underscore character ( _ ).

You can access this special variable as you’d access any other variable:

These examples cover several situations in which Python internally uses the _ variable. The first two examples evaluate expressions. Expressions always have a return value, which is automatically assigned to the _ variable every time.

When it comes to function calls, note that if your function returns a fruitful value, then _ will hold it. In contrast, if your function returns None , then the _ variable will remain untouched.

The next example consists of a regular assignment statement. As you already know, regular assignments don’t return any value, so the _ variable isn’t updated after these statements run. Finally, note that accessing a variable in an interactive session returns the value stored in the target variable. This value is then assigned to the _ variable.

Note that since _ is a regular variable, you can use it in other expressions:

In this example, you first create a list of values. Then you call len() to get the number of values in the list. Python automatically stores this value in the _ variable. Finally, you use _ to compute the mean of your list of values.

Now that you’ve learned about some of the implicit assignments that Python runs under the hood, it’s time to dig into a final assignment-related topic. In the following few sections, you’ll learn about some illegal and dangerous assignments that you should be aware of and avoid in your code.

Illegal and Dangerous Assignments in Python

In Python, you’ll find a few situations in which using assignments is either forbidden or dangerous. You must be aware of these special situations and try to avoid them in your code.

In the following sections, you’ll learn when using assignment statements isn’t allowed in Python. You’ll also learn about some situations in which using assignments should be avoided if you want to keep your code consistent and robust.

You can’t use Python keywords as variable names in assignment statements. This kind of assignment is explicitly forbidden. If you try to use a keyword as a variable name in an assignment, then you get a SyntaxError :

Whenever you try to use a keyword as the left operand in an assignment statement, you get a SyntaxError . Keywords are an intrinsic part of the language and can’t be overridden.

If you ever feel the need to name one of your variables using a Python keyword, then you can append an underscore to the name of your variable:

In this example, you’re using the desired name for your variables. Because you added a final underscore to the names, Python doesn’t recognize them as keywords, so it doesn’t raise an error.

Note: Even though adding an underscore at the end of a name is an officially recommended practice , it can be confusing sometimes. Therefore, try to find an alternative name or use a synonym whenever you find yourself using this convention.

For example, you can write something like this:

In this example, using the name booking_class for your variable is way clearer and more descriptive than using class_ .

You’ll also find that you can use only a few keywords as part of the right operand in an assignment statement. Those keywords will generally define simple statements that return a value or object. These include lambda , and , or , not , True , False , None , in , and is . You can also use the for keyword when it’s part of a comprehension and the if keyword when it’s used as part of a ternary operator .

In an assignment, you can never use a compound statement as the right operand. Compound statements are those that require an indented block, such as for and while loops, conditionals, with statements, try … except blocks, and class or function definitions.

Sometimes, you need to name variables, but the desired or ideal name is already taken and used as a built-in name. If this is your case, think harder and find another name. Don’t shadow the built-in.

Shadowing built-in names can cause hard-to-identify problems in your code. A common example of this issue is using list or dict to name user-defined variables. In this case, you override the corresponding built-in names, which won’t work as expected if you use them later in your code.

Consider the following example:

The exception in this example may sound surprising. How come you can’t use list() to build a list from a call to map() that returns a generator of square numbers?

By using the name list to identify your list of numbers, you shadowed the built-in list name. Now that name points to a list object rather than the built-in class. List objects aren’t callable, so your code no longer works.

In Python, you’ll have nothing that warns against using built-in, standard-library, or even relevant third-party names to identify your own variables. Therefore, you should keep an eye out for this practice. It can be a source of hard-to-debug errors.

In programming, a constant refers to a name associated with a value that never changes during a program’s execution. Unlike other programming languages, Python doesn’t have a dedicated syntax for defining constants. This fact implies that Python doesn’t have constants in the strict sense of the word.

Python only has variables. If you need a constant in Python, then you’ll have to define a variable and guarantee that it won’t change during your code’s execution. To do that, you must avoid using that variable as the left operand in an assignment statement.

To tell other Python programmers that a given variable should be treated as a constant, you must write your variable’s name in capital letters with underscores separating the words. This naming convention has been adopted by the Python community and is a recommendation that you’ll find in the Constants section of PEP 8 .

In the following examples, you define some constants in Python:

The problem with these constants is that they’re actually variables. Nothing prevents you from changing their value during your code’s execution. So, at any time, you can do something like the following:

These assignments modify the value of two of your original constants. Python doesn’t complain about these changes, which can cause issues later in your code. As a Python developer, you must guarantee that named constants in your code remain constant.

The only way to do that is never to use named constants in an assignment statement other than the constant definition.

You’ve learned a lot about Python’s assignment operators and how to use them for writing assignment statements . With this type of statement, you can create, initialize, and update variables according to your needs. Now you have the required skills to fully manage the creation and mutation of variables in your Python code.

In this tutorial, you’ve learned how to:

  • Write assignment statements using Python’s assignment operators
  • Work with augmented assignments in Python
  • Explore assignment variants, like assignment expression and managed attributes
  • Identify illegal and dangerous assignments in Python

Learning about the Python assignment operator and how to use it in assignment statements is a fundamental skill in Python. It empowers you to write reliable and effective Python code.

🐍 Python Tricks 💌

Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Python Tricks Dictionary Merge

About Leodanis Pozo Ramos

Leodanis Pozo Ramos

Leodanis is an industrial engineer who loves Python and software development. He's a self-taught Python developer with 6+ years of experience. He's an avid technical writer with a growing number of articles published on Real Python and other sites.

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Aldren Santos

Master Real-World Python Skills With Unlimited Access to Real Python

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

What Do You Think?

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal . Looking for a real-time conversation? Visit the Real Python Community Chat or join the next “Office Hours” Live Q&A Session . Happy Pythoning!

Keep Learning

Related Topics: intermediate best-practices python

Keep reading Real Python by creating a free account or signing in:

Already have an account? Sign-In

Almost there! Complete this form and click the button below to gain instant access:

Python's Assignment Operator: Write Robust Assignments (Source Code)

🔒 No spam. We take your privacy seriously.

assignment operator expression to complete expression

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

Assignment (=)

The assignment ( = ) operator is used to assign a value to a variable or property. The assignment expression itself has a value, which is the assigned value. This allows multiple assignments to be chained in order to assign a single value to multiple variables.

A valid assignment target, including an identifier or a property accessor . It can also be a destructuring assignment pattern .

An expression specifying the value to be assigned to x .

Return value

The value of y .

Thrown in strict mode if assigning to an identifier that is not declared in the scope.

Thrown in strict mode if assigning to a property that is not modifiable .

Description

The assignment operator is completely different from the equals ( = ) sign used as syntactic separators in other locations, which include:

  • Initializers of var , let , and const declarations
  • Default values of destructuring
  • Default parameters
  • Initializers of class fields

All these places accept an assignment expression on the right-hand side of the = , so if you have multiple equals signs chained together:

This is equivalent to:

Which means y must be a pre-existing variable, and x is a newly declared const variable. y is assigned the value 5 , and x is initialized with the value of the y = 5 expression, which is also 5 . If y is not a pre-existing variable, a global variable y is implicitly created in non-strict mode , or a ReferenceError is thrown in strict mode. To declare two variables within the same declaration, use:

Simple assignment and chaining

Value of assignment expressions.

The assignment expression itself evaluates to the value of the right-hand side, so you can log the value and assign to a variable at the same time.

Unqualified identifier assignment

The global object sits at the top of the scope chain. When attempting to resolve a name to a value, the scope chain is searched. This means that properties on the global object are conveniently visible from every scope, without having to qualify the names with globalThis. or window. or global. .

Because the global object has a String property ( Object.hasOwn(globalThis, "String") ), you can use the following code:

So the global object will ultimately be searched for unqualified identifiers. You don't have to type globalThis.String ; you can just type the unqualified String . To make this feature more conceptually consistent, assignment to unqualified identifiers will assume you want to create a property with that name on the global object (with globalThis. omitted), if there is no variable of the same name declared in the scope chain.

In strict mode , assignment to an unqualified identifier in strict mode will result in a ReferenceError , to avoid the accidental creation of properties on the global object.

Note that the implication of the above is that, contrary to popular misinformation, JavaScript does not have implicit or undeclared variables. It just conflates the global object with the global scope and allows omitting the global object qualifier during property creation.

Assignment with destructuring

The left-hand side of can also be an assignment pattern. This allows assigning to multiple variables at once.

For more information, see Destructuring assignment .

Specifications

Specification

Browser compatibility

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

  • Assignment operators in the JS guide
  • Destructuring assignment
  • Trending Now
  • Foundational Courses
  • Data Science
  • Practice Problem
  • Machine Learning
  • System Design
  • DevOps Tutorial

Assignment Operators in Programming

Assignment operators in programming are symbols used to assign values to variables. They offer shorthand notations for performing arithmetic operations and updating variable values in a single step. These operators are fundamental in most programming languages and help streamline code while improving readability.

Table of Content

What are Assignment Operators?

  • Types of Assignment Operators
  • Assignment Operators in C
  • Assignment Operators in C++
  • Assignment Operators in Java
  • Assignment Operators in Python
  • Assignment Operators in C#
  • Assignment Operators in JavaScript
  • Application of Assignment Operators

Assignment operators are used in programming to  assign values  to variables. We use an assignment operator to store and update data within a program. They enable programmers to store data in variables and manipulate that data. The most common assignment operator is the equals sign ( = ), which assigns the value on the right side of the operator to the variable on the left side.

Types of Assignment Operators:

  • Simple Assignment Operator ( = )
  • Addition Assignment Operator ( += )
  • Subtraction Assignment Operator ( -= )
  • Multiplication Assignment Operator ( *= )
  • Division Assignment Operator ( /= )
  • Modulus Assignment Operator ( %= )

Below is a table summarizing common assignment operators along with their symbols, description, and examples:

OperatorDescriptionExamples
= (Assignment)Assigns the value on the right to the variable on the left.  assigns the value 10 to the variable x.
+= (Addition Assignment)Adds the value on the right to the current value of the variable on the left and assigns the result to the variable.  is equivalent to 
-= (Subtraction Assignment)Subtracts the value on the right from the current value of the variable on the left and assigns the result to the variable.  is equivalent to 
*= (Multiplication Assignment)Multiplies the current value of the variable on the left by the value on the right and assigns the result to the variable.  is equivalent to 
/= (Division Assignment)Divides the current value of the variable on the left by the value on the right and assigns the result to the variable.  is equivalent to 
%= (Modulo Assignment)Calculates the modulo of the current value of the variable on the left and the value on the right, then assigns the result to the variable.  is equivalent to 

Assignment Operators in C:

Here are the implementation of Assignment Operator in C language:

Assignment Operators in C++:

Here are the implementation of Assignment Operator in C++ language:

Assignment Operators in Java:

Here are the implementation of Assignment Operator in java language:

Assignment Operators in Python:

Here are the implementation of Assignment Operator in python language:

Assignment Operators in C#:

Here are the implementation of Assignment Operator in C# language:

Assignment Operators in Javascript:

Here are the implementation of Assignment Operator in javascript language:

Application of Assignment Operators:

  • Variable Initialization : Setting initial values to variables during declaration.
  • Mathematical Operations : Combining arithmetic operations with assignment to update variable values.
  • Loop Control : Updating loop variables to control loop iterations.
  • Conditional Statements : Assigning different values based on conditions in conditional statements.
  • Function Return Values : Storing the return values of functions in variables.
  • Data Manipulation : Assigning values received from user input or retrieved from databases to variables.

Conclusion:

In conclusion, assignment operators in programming are essential tools for assigning values to variables and performing operations in a concise and efficient manner. They allow programmers to manipulate data and control the flow of their programs effectively. Understanding and using assignment operators correctly is fundamental to writing clear, efficient, and maintainable code in various programming languages.

Please Login to comment...

Similar reads.

  • Programming
  • 105 Funny Things to Do to Make Someone Laugh
  • Best PS5 SSDs in 2024: Top Picks for Expanding Your Storage
  • Best Nintendo Switch Controllers in 2024
  • Xbox Game Pass Ultimate: Features, Benefits, and Pricing in 2024
  • #geekstreak2024 – 21 Days POTD Challenge Powered By Deutsche Bank

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Assignment operators (C# reference)

  • 11 contributors

The assignment operator = assigns the value of its right-hand operand to a variable, a property , or an indexer element given by its left-hand operand. The result of an assignment expression is the value assigned to the left-hand operand. The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it.

The assignment operator = is right-associative, that is, an expression of the form

is evaluated as

The following example demonstrates the usage of the assignment operator with a local variable, a property, and an indexer element as its left-hand operand:

The left-hand operand of an assignment receives the value of the right-hand operand. When the operands are of value types , assignment copies the contents of the right-hand operand. When the operands are of reference types , assignment copies the reference to the object.

This is called value assignment : the value is assigned.

ref assignment

Ref assignment = ref makes its left-hand operand an alias to the right-hand operand, as the following example demonstrates:

In the preceding example, the local reference variable arrayElement is initialized as an alias to the first array element. Then, it's ref reassigned to refer to the last array element. As it's an alias, when you update its value with an ordinary assignment operator = , the corresponding array element is also updated.

The left-hand operand of ref assignment can be a local reference variable , a ref field , and a ref , out , or in method parameter. Both operands must be of the same type.

Compound assignment

For a binary operator op , a compound assignment expression of the form

is equivalent to

except that x is only evaluated once.

Compound assignment is supported by arithmetic , Boolean logical , and bitwise logical and shift operators.

Null-coalescing assignment

You can use the null-coalescing assignment operator ??= to assign the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null . For more information, see the ?? and ??= operators article.

Operator overloadability

A user-defined type can't overload the assignment operator. However, a user-defined type can define an implicit conversion to another type. That way, the value of a user-defined type can be assigned to a variable, a property, or an indexer element of another type. For more information, see User-defined conversion operators .

A user-defined type can't explicitly overload a compound assignment operator. However, if a user-defined type overloads a binary operator op , the op= operator, if it exists, is also implicitly overloaded.

C# language specification

For more information, see the Assignment operators section of the C# language specification .

  • C# operators and expressions
  • ref keyword
  • Use compound assignment (style rules IDE0054 and IDE0074)

Additional resources

Log in or Sign up

Solved syntax error, insert "assignmentoperator expression" to complete expression.

Discussion in ' Plugin Development ' started by Xp10d3 , Jan 26, 2020 .

I get an error at this part of my onEnable" Code: ((HashMap<String, List<String>>) getConfig().getValues(true).forEach((name, plugins) -> { WorldCreator name; final World world = Bukkit.createWorld(name); plugins.forEch(plugin -> supress(Bukkit.getPlugin(name), world)); })); I am confused on how to fix this error... I just ran the plugin for then sake of getting the console error so here it is: Code: [16:35:37] [Server thread/ERROR]: Error occurred while enabling DisablePlugin v0.1 (Is it up to date?) java.lang.Error: Unresolved compilation problem: Syntax error, insert "AssignmentOperator Expression" to complete Expression at play.corelia.online.Core.onEnable(Core.java:43) ~[?:?] at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:263) ~[server.jar:git-Spigot-f39a89e-4633e6c] at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:352) [server.jar:git-Spigot-f39a89e-4633e6c] at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:417) [server.jar:git-Spigot-f39a89e-4633e6c] at org.bukkit.craftbukkit.v1_15_R1.CraftServer.enablePlugin(CraftServer.java:462) [server.jar:git-Spigot-f39a89e-4633e6c] at org.bukkit.craftbukkit.v1_15_R1.CraftServer.enablePlugins(CraftServer.java:376) [server.jar:git-Spigot-f39a89e-4633e6c] at net.minecraft.server.v1_15_R1.MinecraftServer.a(MinecraftServer.java:456) [server.jar:git-Spigot-f39a89e-4633e6c] at net.minecraft.server.v1_15_R1.DedicatedServer.init(DedicatedServer.java:266) [server.jar:git-Spigot-f39a89e-4633e6c] at net.minecraft.server.v1_15_R1.MinecraftServer.run(MinecraftServer.java:783) [server.jar:git-Spigot-f39a89e-4633e6c] at java.lang.Thread.run(Unknown Source) [?:1.8.0_221] And my full class: Code: package play.corelia.online; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.function.BiPredicate; import java.util.logging.Level; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.WorldCreator; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; import org.bukkit.plugin.java.JavaPlugin; public class Core extends JavaPlugin implements Listener { FileConfiguration config = getConfig(); @Override public void onEnable() { saveDefaultConfig(); /* ((map<String, List<String>>) getConfig().getValues(true)).forEach((name, plugins) -> { final World world = Bukkit.createWorld(name); plugins.forEach(plugin -> supress(Bukkit.getPlugin(name), world)); }); */ ((HashMap<String, List<String>>) getConfig().getValues(true).forEach((name, plugins) -> { WorldCreator name; final World world = Bukkit.createWorld(name); plugins.forEch(plugin -> supress(Bukkit.getPlugin(name), world)); })); } @SuppressWarnings("unchecked") static <Type extends Event> void filter(Class<Type> type, BiPredicate<Plugin, Type> filter) { HandlerList handler; try { handler = (HandlerList) type.getDeclaredMethod("getHandlerList").invoke(null); } catch (Throwable e) { throw new RuntimeException(e); } Arrays.asList(handler.getRegisteredListeners()).forEach(listener -> { handler.unregister(listener); handler.register(new RegisteredListener(listener.getListener(), ($, event) -> { if (filter.test(listener.getPlugin(), (Type) event)) listener.callEvent(event); }, listener.getPriority(), listener.getPlugin(), false)); }); } /* static <Type extends Event> void filter(HandlerList type, BiPredicate<Plugin, Type> filter) { for (final RegisteredListener listener : type.getRegisteredListeners()) { HandlerList handler = ; handler.unregister(listener); handler.register(new RegisteredListener(listener.getListener(), ($, event) -> { if (filter.test(listener.getPlugin(), (Type) event)) listener.callEvent(event); }, listener.getPriority(), listener.getPlugin(), false)); } } */ /* @SuppressWarnings("unlikely-arg-type") @EventHandler public void supress() { ConfigurationSection targetPlugin = config.getConfigurationSection("location.world"); for (String key : targetPlugin.getKeys(false)) { List<String> targetWorld = targetPlugin.getStringList(key); filter(PlayerInteractEvent.class, (plugin, event) -> plugin == targetPlugin && event.getPlayer().getWorld().equals(targetWorld)); } } */ @SuppressWarnings("unlikely-arg-type") public void supress(PlayerPortalEvent e) { Player player = (Player) e.getPlayer(); ConfigurationSection targetPlugin = config.getConfigurationSection("location.world"); for (String key : targetPlugin.getKeys(false)) { List<String> targetWorld = targetPlugin.getStringList(key); if (targetWorld != null) { for (int i = 0; i < targetWorld.size(); i++) { if (targetWorld.contains(player.getWorld())) { filter(PlayerInteractEvent.class, (plugin, event) -> plugin == targetPlugin && event.getPlayer().getWorld().equals(targetWorld)); } } } else { Bukkit.getServer().getLogger().info(Level.SEVERE + "ERROR! Target World is possibly null! This may crash the server."); } } } } EDIT: never mind solved  

Share This Page

  • No, create an account now.
  • Yes, my password is:
  • Forgot your password?

Bukkit Forums

  • Search titles only

Separate names with a comma.

  • Search this thread only
  • Display results as threads

Useful Searches

  • Recent Posts
  • Install App

New to Java

For appeals, questions and feedback about Oracle Forums, please email [email protected] . Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Syntax error, insert "AssignmentOperator Expression" to complete Expression

assignment operator expression to complete expression

Java SE > Java SE Specifications > Java Language Specification

Chapter 15. Expressions
     

Chapter 15. Expressions

Table of Contents

Much of the work in a program is done by evaluating expressions , either for their side effects, such as assignments to variables, or for their values, which can be used as arguments or operands in larger expressions, or to affect the execution sequence in statements, or both.

This chapter specifies the meanings of expressions and the rules for their evaluation.

15.1. Evaluation, Denotation, and Result

When an expression in a program is evaluated ( executed ), the result denotes one of three things:

A variable ( §4.12 ) (in C, this would be called an lvalue )

A value ( §4.2 , §4.3 )

Nothing (the expression is said to be void)

Evaluation of an expression can also produce side effects, because expressions may contain embedded assignments, increment operators, decrement operators, and method invocations.

An expression denotes nothing if and only if it is a method invocation ( §15.12 ) that invokes a method that does not return a value, that is, a method declared void ( §8.4 ). Such an expression can be used only as an expression statement ( §14.8 ), because every other context in which an expression can appear requires the expression to denote something. An expression statement that is a method invocation may also invoke a method that produces a result; in this case the value returned by the method is quietly discarded.

Value set conversion ( §5.1.13 ) is applied to the result of every expression that produces a value.

Each expression occurs in either:

The declaration of some (class or interface) type that is being declared: in a field initializer, in a static initializer, in an instance initializer, in a constructor declaration, in an annotation, or in the code for a method.

An annotation ( §9.7 ) of a package or of a top level type declaration.

15.2. Variables as Values

If an expression denotes a variable, and a value is required for use in further evaluation, then the value of that variable is used. In this context, if the expression denotes a variable or a value, we may speak simply of the value of the expression.

If the value of a variable of type float or double is used in this manner, then value set conversion ( §5.1.13 ) is applied to the value of the variable.

15.3. Type of an Expression

If an expression denotes a variable or a value, then the expression has a type known at compile time. The rules for determining the type of an expression are explained separately below for each kind of expression.

The value of an expression is assignment compatible ( §5.2 ) with the type of the expression, unless heap pollution ( §4.12.2 ) occurs.

Likewise, the value stored in a variable is always compatible with the type of the variable, unless heap pollution occurs.

In other words, the value of an expression whose type is T is always suitable for assignment to a variable of type T .

Note that an expression whose type is a class type F that is declared final is guaranteed to have a value that is either a null reference or an object whose class is F itself, because final types have no subclasses.

15.4. FP-strict Expressions

If the type of an expression is float or double , then there is a question as to what value set ( §4.2.3 ) the value of the expression is drawn from. This is governed by the rules of value set conversion ( §5.1.13 ); these rules in turn depend on whether or not the expression is FP-strict .

Every compile-time constant expression ( §15.28 ) is FP-strict.

If an expression is not a compile-time constant expression, then consider all the class declarations, interface declarations, and method declarations that contain the expression. If any such declaration bears the strictfp modifier ( §8.1.1.3 , §8.4.3.5 , §9.1.1.2 ), then the expression is FP-strict.

If a class, interface, or method, X , is declared strictfp , then X and any class, interface, method, constructor, instance initializer, static initializer or variable initializer within X is said to be FP-strict .

Note that an annotation ( §9.7 ) element value ( §9.6 ) is always FP-strict, because it is always a compile-time constant expression.

It follows that an expression is not FP-strict if and only if it is not a compile-time constant expression and it does not appear within any declaration that has the strictfp modifier.

Within an FP-strict expression, all intermediate values must be elements of the float value set or the double value set, implying that the results of all FP-strict expressions must be those predicted by IEEE 754 arithmetic on operands represented using single and double formats.

Within an expression that is not FP-strict, some leeway is granted for an implementation to use an extended exponent range to represent intermediate results; the net effect, roughly speaking, is that a calculation might produce "the correct answer" in situations where exclusive use of the float value set or double value set might result in overflow or underflow.

15.5. Expressions and Run-Time Checks

If the type of an expression is a primitive type, then the value of the expression is of that same primitive type.

If the type of an expression is a reference type, then the class of the referenced object, or even whether the value is a reference to an object rather than null , is not necessarily known at compile time. There are a few places in the Java programming language where the actual class of a referenced object affects program execution in a manner that cannot be deduced from the type of the expression. They are as follows:

Method invocation ( §15.12 ). The particular method used for an invocation o.m(...) is chosen based on the methods that are part of the class or interface that is the type of o . For instance methods, the class of the object referenced by the run-time value of o participates because a subclass may override a specific method already declared in a parent class so that this overriding method is invoked. (The overriding method may or may not choose to further invoke the original overridden m method.)

The instanceof operator ( §15.20.2 ). An expression whose type is a reference type may be tested using instanceof to find out whether the class of the object referenced by the run-time value of the expression is assignment compatible ( §5.2 ) with some other reference type.

Casting ( §5.5 , §15.16 ). The class of the object referenced by the run-time value of the operand expression might not be compatible with the type specified by the cast. For reference types, this may require a run-time check that throws an exception if the class of the referenced object, as determined at run time, is not assignment compatible ( §5.2 ) with the target type.

Assignment to an array component of reference type ( §10.5 , §15.13 , §15.26.1 ). The type-checking rules allow the array type S [] to be treated as a subtype of T [] if S is a subtype of T , but this requires a run-time check for assignment to an array component, similar to the check performed for a cast.

Exception handling ( §14.20 ). An exception is caught by a catch clause only if the class of the thrown exception object is an instanceof the type of the formal parameter of the catch clause.

Situations where the class of an object is not statically known may lead to run-time type errors.

In addition, there are situations where the statically known type may not be accurate at run time. Such situations can arise in a program that gives rise to compile-time unchecked warnings. Such warnings are given in response to operations that cannot be statically guaranteed to be safe, and cannot immediately be subjected to dynamic checking because they involve non-reifiable ( §4.7 ) types. As a result, dynamic checks later in the course of program execution may detect inconsistencies and result in run-time type errors.

A run-time type error can occur only in these situations:

In a cast, when the actual class of the object referenced by the value of the operand expression is not compatible with the target type specified by the cast operator ( §5.5 , §15.16 ); in this case a ClassCastException is thrown.

In an automatically generated cast introduced to ensure the validity of an operation on a non-reifiable type ( §4.7 ).

In an assignment to an array component of reference type, when the actual class of the object referenced by the value to be assigned is not compatible with the actual run-time component type of the array ( §10.5 , §15.13 , §15.26.1 ); in this case an ArrayStoreException is thrown.

When an exception is not caught by any catch clause of a try statement ( §14.20 ); in this case the thread of control that encountered the exception first attempts to invoke an uncaught exception handler ( §11.3 ) and then terminates.

15.6. Normal and Abrupt Completion of Evaluation

Every expression has a normal mode of evaluation in which certain computational steps are carried out. The following sections describe the normal mode of evaluation for each kind of expression.

If all the steps are carried out without an exception being thrown, the expression is said to complete normally .

If, however, evaluation of an expression throws an exception, then the expression is said to complete abruptly . An abrupt completion always has an associated reason, which is always a throw with a given value.

Run-time exceptions are thrown by the predefined operators as follows:

A class instance creation expression ( §15.9 ), array creation expression ( §15.10 ), array initializer expression ( §10.6 ), or string concatenation operator expression ( §15.18.1 ) throws an OutOfMemoryError if there is insufficient memory available.

An array creation expression ( §15.10 ) throws a NegativeArraySizeException if the value of any dimension expression is less than zero.

A field access expression ( §15.11 ) throws a NullPointerException if the value of the object reference expression is null .

A method invocation expression ( §15.12 ) that invokes an instance method throws a NullPointerException if the target reference is null .

An array access expression ( §15.13 ) throws a NullPointerException if the value of the array reference expression is null .

An array access expression ( §15.13 ) throws an ArrayIndexOutOfBoundsException if the value of the array index expression is negative or greater than or equal to the length of the array.

A cast expression ( §15.16 ) throws a ClassCastException if a cast is found to be impermissible at run time.

An integer division ( §15.17.2 ) or integer remainder ( §15.17.3 ) operator throws an ArithmeticException if the value of the right-hand operand expression is zero.

An assignment to an array component of reference type ( §15.26.1 ), a method invocation expression ( §15.12 ), or a prefix or postfix increment ( §15.14.2 , §15.15.1 ) or decrement operator ( §15.14.3 , §15.15.2 ) may all throw an OutOfMemoryError as a result of boxing conversion ( §5.1.7 ).

An assignment to an array component of reference type ( §15.26.1 ) throws an ArrayStoreException when the value to be assigned is not compatible with the component type of the array ( §10.5 ).

A method invocation expression can also result in an exception being thrown if an exception occurs that causes execution of the method body to complete abruptly.

A class instance creation expression can also result in an exception being thrown if an exception occurs that causes execution of the constructor to complete abruptly.

Various linkage and virtual machine errors may also occur during the evaluation of an expression. By their nature, such errors are difficult to predict and difficult to handle.

If an exception occurs, then evaluation of one or more expressions may be terminated before all steps of their normal mode of evaluation are complete; such expressions are said to complete abruptly.

If evaluation of an expression requires evaluation of a subexpression, then abrupt completion of the subexpression always causes the immediate abrupt completion of the expression itself, with the same reason, and all succeeding steps in the normal mode of evaluation are not performed.

The terms "complete normally" and "complete abruptly" are also applied to the execution of statements ( §14.1 ). A statement may complete abruptly for a variety of reasons, not just because an exception is thrown.

15.7. Evaluation Order

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order , namely, from left to right.

It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation, and when code does not depend on exactly which exception arises as a consequence of the left-to-right evaluation of expressions.

15.7.1. Evaluate Left-Hand Operand First

The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.

If the operator is a compound-assignment operator ( §15.26.2 ), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.

If evaluation of the left-hand operand of a binary operator completes abruptly, no part of the right-hand operand appears to have been evaluated.

Example 15.7.1-1. Left-Hand Operand Is Evaluated First

In the following program, the * operator has a left-hand operand that contains an assignment to a variable and a right-hand operand that contains a reference to the same variable. The value produced by the reference will reflect the fact that the assignment occurred first.

This program produces the output:

It is not permitted for evaluation of the * operator to produce 6 instead of 9 .

Example 15.7.1-2. Implicit Left-Hand Operand In Operator Of Compound Assigment

In the following program, the two assignment statements both fetch and remember the value of the left-hand operand, which is 9 , before the right-hand operand of the addition operator is evaluated, at which point the variable is set to 3 .

It is not permitted for either assignment (compound for a , simple for b ) to produce the result 6 .

See also the example in §15.26.2 .

Example 15.7.1-3. Abrupt Completion of Evaluation of the Left-Hand Operand

That is, the left-hand operand forgetIt() of the operator / throws an exception before the right-hand operand is evaluated and its embedded assignment of 2 to j occurs.

15.7.2. Evaluate Operands before Operation

The Java programming language guarantees that every operand of an operator (except the conditional operators && , || , and ? : ) appears to be fully evaluated before any part of the operation itself is performed.

If the binary operator is an integer division / ( §15.17.2 ) or integer remainder % ( §15.17.3 ), then its execution may raise an ArithmeticException , but this exception is thrown only after both operands of the binary operator have been evaluated and only if these evaluations completed normally.

Example 15.7.2-1. Evaluation of Operands Before Operation

since no part of the division operation, including signaling of a divide-by-zero exception, may appear to occur before the invocation of loseBig completes, even though the implementation may be able to detect or infer that the division operation would certainly result in a divide-by-zero exception.

15.7.3. Evaluation Respects Parentheses and Precedence

The Java programming language respects the order of evaluation indicated explicitly by parentheses and implicitly by operator precedence.

An implementation of the Java programming language may not take advantage of algebraic identities such as the associative law to rewrite expressions into a more convenient computational order unless it can be proven that the replacement expression is equivalent in value and in its observable side effects, even in the presence of multiple threads of execution (using the thread execution model in §17 ), for all possible computational values that might be involved.

In the case of floating-point calculations, this rule applies also for infinity and not-a-number (NaN) values.

For example, !(x<y) may not be rewritten as x>=y , because these expressions have different values if either x or y is NaN or both are NaN.

Specifically, floating-point calculations that appear to be mathematically associative are unlikely to be computationally associative. Such computations must not be naively reordered.

For example, it is not correct for a Java compiler to rewrite 4.0*x*0.5 as 2.0*x ; while roundoff happens not to be an issue here, there are large values of x for which the first expression produces infinity (because of overflow) but the second expression produces a finite result.

So, for example, the test program:

because the first expression overflows and the second does not.

In contrast, integer addition and multiplication are provably associative in the Java programming language.

For example a+b+c , where a , b , and c are local variables (this simplifying assumption avoids issues involving multiple threads and volatile variables), will always produce the same answer whether evaluated as (a+b)+c or a+(b+c) ; if the expression b+c occurs nearby in the code, a smart Java compiler may be able to use this common subexpression.

15.7.4. Argument Lists are Evaluated Left-to-Right

In a method or constructor invocation or class instance creation expression, argument expressions may appear within the parentheses, separated by commas. Each argument expression appears to be fully evaluated before any part of any argument expression to its right.

If evaluation of an argument expression completes abruptly, no part of any argument expression to its right appears to have been evaluated.

Example 15.7.4-1. Evaluation Order At Method Invocation

because the assignment of the string " gone " to s occurs after the first two arguments to print3 have been evaluated.

Example 15.7.4-2. Abrupt Completion of Argument Expression

because the assignment of 3 to id is not executed.

15.7.5. Evaluation Order for Other Expressions

The order of evaluation for some expressions is not completely covered by these general rules, because these expressions may raise exceptional conditions at times that must be specified. See the detailed explanations of evaluation order for the following kinds of expressions:

class instance creation expressions ( §15.9.4 )

array creation expressions ( §15.10.1 )

method invocation expressions ( §15.12.4 )

array access expressions ( §15.13.1 )

assignments involving array components ( §15.26 )

15.8. Primary Expressions

Primary expressions include most of the simplest kinds of expressions, from which all others are constructed: literals, class literals, field accesses, method invocations, and array accesses. A parenthesized expression is also treated syntactically as a primary expression.

Primary:     PrimaryNoNewArray     ArrayCreationExpression PrimaryNoNewArray:     Literal     Type  .   class      void   .   class      this     ClassName  .   this      (  Expression  )     ClassInstanceCreationExpression     FieldAccess     MethodInvocation     ArrayAccess

This part of the grammar of the Java programming language is unusual, in two ways. First, one might expect simple names, such as names of local variables and method parameters, to be primary expressions. For technical reasons, names are grouped together with primary expressions a little later when postfix expressions are introduced ( §15.14 ).

The technical reasons have to do with allowing left-to-right parsing of Java programs with only one-token lookahead. Consider the expressions (z[3]) and (z[]) . The first is a parenthesized array access ( §15.13 ) and the second is the start of a cast ( §15.16 ). At the point that the look-ahead symbol is [ , a left-to-right parse will have reduced the z to the nonterminal Name . In the context of a cast we prefer not to have to reduce the name to a Primary , but if Name were one of the alternatives for Primary , then we could not tell whether to do the reduction (that is, we could not determine whether the current situation would turn out to be a parenthesized array access or a cast) without looking ahead two tokens, to the token following the [ . The Java grammar presented here avoids the problem by keeping Name and Primary separate and allowing either in certain other syntax rules (those for MethodInvocation , ArrayAccess , PostfixExpression , but not for FieldAccess , because this uses an identifier directly). This strategy effectively defers the question of whether a Name should be treated as a Primary until more context can be examined.

The second unusual feature avoids a potential grammatical ambiguity in the expression " new int[3][3] " which in Java always means a single creation of a multidimensional array, but which, without appropriate grammatical finesse, might also be interpreted as meaning the same as " (new int[3])[3] ".

This ambiguity is eliminated by splitting the expected definition of Primary into Primary and PrimaryNoNewArray . (This may be compared to the splitting of Statement into Statement and StatementNoShortIf ( §14.5 ) to avoid the "dangling else" problem.)

15.8.1. Lexical Literals

A literal ( §3.10 ) denotes a fixed, unchanging value.

The following production from §3.10 is repeated here for convenience:

Literal:     IntegerLiteral     FloatingPointLiteral     BooleanLiteral     CharacterLiteral     StringLiteral     NullLiteral

The type of a literal is determined as follows:

The type of an integer literal ( §3.10.1 ) that ends with L or l is long ( §4.2.1 ).

The type of any other integer literal is int ( §4.2.1 ).

The type of a floating-point literal ( §3.10.2 ) that ends with F or f is float and its value must be an element of the float value set ( §4.2.3 ).

The type of any other floating-point literal is double and its value must be an element of the double value set ( §4.2.3 ).

The type of a boolean literal ( §3.10.3 ) is boolean ( §4.2.5 ).

The type of a character literal ( §3.10.4 ) is char ( §4.2.1 ).

The type of a string literal ( §3.10.5 ) is String ( §4.3.3 ).

The type of the null literal null ( §3.10.7 ) is the null type ( §4.1 ); its value is the null reference.

Evaluation of a lexical literal always completes normally.

15.8.2. Class Literals

A class literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-type void , followed by a ' . ' and the token class .

The type of C . class , where C is the name of a class, interface, or array type ( §4.3 ), is Class < C > .

The type of p . class , where p is the name of a primitive type ( §4.2 ), is Class < B > , where B is the type of an expression of type p after boxing conversion ( §5.1.7 ).

The type of void . class ( §8.4.5 ) is Class < Void > .

It is a compile-time error if the named type is a type variable ( §4.4 ) or a parameterized type ( §4.5 ) or an array whose element type is a type variable or parameterized type.

It is a compile-time error if the named type does not denote a type that is accessible ( §6.6 ) and in scope ( §6.3 ) at the point where the class literal appears.

A class literal evaluates to the Class object for the named type (or for void ) as defined by the defining class loader ( §12.2 ) of the class of the current instance.

15.8.3.  this

The keyword this may be used only in the body of an instance method, instance initializer, or constructor, or in the initializer of an instance variable of a class. If it appears anywhere else, a compile-time error occurs.

When used as a primary expression, the keyword this denotes a value that is a reference to the object for which the instance method was invoked ( §15.12 ), or to the object being constructed.

The type of this is the class C within which the keyword this occurs.

At run time, the class of the actual object referred to may be the class C or any subclass of C .

The keyword this is also used in a special explicit constructor invocation statement, which can appear at the beginning of a constructor body ( §8.8.7 ).

Example 15.8.3-1. The this Expression

Here, the class IntVector implements a method equals , which compares two vectors. If the other vector is the same vector object as the one for which the equals method was invoked, then the check can skip the length and value comparisons. The equals method implements this check by comparing the reference to the other object to this .

15.8.4. Qualified this

Any lexically enclosing instance ( §8.1.3 ) can be referred to by explicitly qualifying the keyword this .

Let C be the class denoted by ClassName . Let n be an integer such that C is the n 'th lexically enclosing class of the class in which the qualified this expression appears.

The value of an expression of the form ClassName . this is the n 'th lexically enclosing instance of this .

The type of the expression is C .

It is a compile-time error if the current class is not an inner class of class C or C itself.

15.8.5. Parenthesized Expressions

A parenthesized expression is a primary expression whose type is the type of the contained expression and whose value at run time is the value of the contained expression. If the contained expression denotes a variable then the parenthesized expression also denotes that variable.

The use of parentheses affects only the order of evaluation, except for a corner case whereby (-2147483648) and (-9223372036854775808L) are legal but -(2147483648) and -(9223372036854775808L) are illegal.

This is because the decimal literals 2147483648 and 9223372036854775808L are allowed only as an operand of the unary minus operator ( §3.10.1 ).

In particular, the presence or absence of parentheses around an expression does not (except for the case noted above) affect in any way:

the choice of value set ( §4.2.3 ) for the value of an expression of type float or double .

whether a variable is definitely assigned, definitely assigned when true , definitely assigned when false , definitely unassigned, definitely unassigned when true , or definitely unassigned when false ( §16 ).

15.9. Class Instance Creation Expressions

A class instance creation expression is used to create new objects that are instances of classes.

ClassInstanceCreationExpression:      new  TypeArguments opt  TypeDeclSpecifier TypeArgumentsOrDiamond opt                                                              (  ArgumentList opt   )  ClassBody opt     Primary  .   new  TypeArguments opt  Identifier TypeArgumentsOrDiamond opt                                                              (  ArgumentList opt   )  ClassBody opt TypeArgumentsOrDiamond:     TypeArguments      <>   ArgumentList:     Expression     ArgumentList  ,  Expression

A class instance creation expression specifies a class to be instantiated, possibly followed by type arguments ( §4.5.1 ) or a diamond (" <> ") if the class being instantiated is generic ( §8.1.2 ), followed by (a possibly empty) list of actual value arguments to the constructor.

If the type argument list to the class is empty — the diamond form " <> " — the type arguments of the class are inferred. It is legal, though strongly discouraged as a matter of style, to have white space between the " < " and " > " of a diamond.

If the constructor is generic ( §8.8.4 ), the type arguments to the constructor may similarly either be inferred or passed explicitly. If passed explicitly, the type arguments to the constructor immediately follow the keyword new .

It is a compile-time error if a class instance creation expression provides a constructor type argument list but uses " <> " in place of a class type argument list.

This rule is introduced because inference of a generic class's type arguments may influence the constraints on a generic constructor's type arguments.

It is a compile-time error if any of the type arguments used in a class instance creation expression are wildcard type arguments ( §4.5.1 ).

The exception types that a class instance creation expression can throw are specified in §11.2.1 .

Class instance creation expressions have two forms:

Unqualified class instance creation expressions begin with the keyword new .

An unqualified class instance creation expression may be used to create an instance of a class, regardless of whether the class is a top level ( §7.6 ), member ( §8.5 , §9.5 ), local ( §14.3 ) or anonymous class ( §15.9.5 ).

Qualified class instance creation expressions begin with a Primary .

A qualified class instance creation expression enables the creation of instances of inner member classes and their anonymous subclasses.

Both unqualified and qualified class instance creation expressions may optionally end with a class body. Such a class instance creation expression declares an anonymous class ( §15.9.5 ) and creates an instance of it.

It is a compile-time error if a class instance creation expression declares an anonymous class using the " <> " form for the class's type arguments.

We say that a class is instantiated when an instance of the class is created by a class instance creation expression. Class instantiation involves determining what class is to be instantiated, what the enclosing instances (if any) of the newly created instance are, what constructor should be invoked to create the new instance, and what arguments should be passed to that constructor.

15.9.1. Determining the Class being Instantiated

If the class instance creation expression ends in a class body, then the class being instantiated is an anonymous class. Then:

If the class instance creation expression is an unqualified class instance creation expression, then TypeDeclSpecifier TypeArgumentsOrDiamond opt must denote a type, T ( §4.3 , §4.5 ), or a compile-time error occurs.

It is a compile-time error if the class or interface named by T is not accessible ( §6.6 ) or if T is an enum type ( §8.9 ).

If T denotes a class, then an anonymous direct subclass of the class named by T is declared. It is a compile-time error if the class denoted by T is a final class.

If T denotes an interface, then an anonymous direct subclass of Object that implements the interface named by T is declared.

In either case, the body of the subclass is the ClassBody given in the class instance creation expression.

The class being instantiated is the anonymous subclass.

Otherwise, the class instance creation expression is a qualified class instance creation expression.

It is a compile-time error if the Identifier after the new token is not the simple name ( §6.2 ) of an accessible ( §6.6 ) non- final inner class ( §8.1.3 ) that is a member of the compile-time type of the Primary .

It is a compile-time error if the name is ambiguous ( §8.5 ) or denotes an enum type.

When TypeArguments are provided after the name, it is a compile-time error if the type arguments, when applied to the named class, do not denote a well-formed parameterized type ( §4.5 ).

Let T be the type named by the Identifier and any type arguments. An anonymous direct subclass of the class named by T is declared. The body of the subclass is the ClassBody given in the class instance creation expression.

If a class instance creation expression does not declare an anonymous class, then:

If the class instance creation expression is an unqualified class instance creation expression, then the TypeDeclSpecifier must denote a class that is accessible ( §6.6 ) and is not an enum type and not abstract , or a compile-time error occurs.

When TypeArguments are provided after the class name, it is a compile-time error if the type arguments, when applied to the class, do not denote a well-formed parameterized type ( §4.5 ).

When " <> " is used to elide type arguments after the class name, it is a compile-time error if the class is not generic.

The class being instantiated is the class denoted by the TypeDeclSpecifier .

It is a compile-time error if the Identifier after the new token is not the simple name ( §6.2 ) of an accessible ( §6.6 ) non- abstract inner class ( §8.1.3 ) C that is a member of the compile-time type of the Primary .

It is a compile-time error if the name is ambiguous ( §8.5 ) or denotes an enum type ( §8.9 ).

When TypeArguments are provided after the name, it is a compile-time error if the type arguments, when applied to C , do not denote a well-formed parameterized type ( §4.5 ).

When " <> " is used to elide type arguments after the name, it is a compile-time error if C is not generic.

The class being instantiated is C .

The type of the class instance creation expression is the class type being instantiated, as defined above.

15.9.2. Determining Enclosing Instances

Let C be the class being instantiated, and let i be the instance being created. If C is an inner class then i may have an immediately enclosing instance. The immediately enclosing instance of i ( §8.1.3 ) is determined as follows.

If C is an anonymous class, then:

If the class instance creation expression occurs in a static context ( §8.1.3 ), then i has no immediately enclosing instance.

Otherwise, the immediately enclosing instance of i is this .

If C is a local class ( §14.3 ), then let O be the innermost lexically enclosing class of C . Let n be an integer such that O is the n 'th lexically enclosing class of the class in which the class instance creation expression appears. Then:

If C occurs in a static context, then i has no immediately enclosing instance.

Otherwise, if the class instance creation expression occurs in a static context, then a compile-time error occurs.

Otherwise, the immediately enclosing instance of i is the n 'th lexically enclosing instance of this ( §8.1.3 ).

Otherwise, C is an inner member class ( §8.5 ), and then:

If the class instance creation expression is an unqualified class instance creation expression, then:

If the class instance creation expression occurs in a static context, then a compile-time error occurs.

Otherwise, if C is a member of an enclosing class then let O be the innermost lexically enclosing class of which C is a member, and let n be an integer such that O is the n 'th lexically enclosing class of the class in which the class instance creation expression appears.

The immediately enclosing instance of i is the n 'th lexically enclosing instance of this .

Otherwise, a compile-time error occurs.

The immediately enclosing instance of i is the object that is the value of the Primary expression.

In addition, if C is an anonymous class, and the direct superclass of C , S , is an inner class, then i may have an immediately enclosing instance with respect to S . It is determined as follows.

If S is a local class ( §14.3 ), then let O be the innermost lexically enclosing class of S . Let n be an integer such that O is the n 'th lexically enclosing class of the class in which the class instance creation expression appears. Then:

If S occurs within a static context, then i has no immediately enclosing instance with respect to S .

Otherwise, the immediately enclosing instance of i with respect to S is the n 'th lexically enclosing instance of this .

Otherwise, S is an inner member class ( §8.5 ), and then:

Otherwise, if S is a member of an enclosing class, then let O be the innermost lexically enclosing class of which S is a member, and let n be an integer such that O is the n 'th lexically enclosing class of the class in which the class instance creation expression appears.

The immediately enclosing instance of i with respect to S is the n 'th lexically enclosing instance of this .

The immediately enclosing instance of i with respect to S is the object that is the value of the Primary expression.

15.9.3. Choosing the Constructor and its Arguments

Let C be the class being instantiated. To create an instance of C , i , a constructor of C is chosen at compile time by the following rules.

First, the actual arguments to the constructor invocation are determined:

If C is an anonymous class, and the direct superclass of C , S , is an inner class, then:

If S is a local class and S occurs in a static context, then the arguments in the argument list, if any, are the arguments to the constructor, in the order they appear in the expression.

Otherwise, the immediately enclosing instance of i with respect to S is the first argument to the constructor, followed by the arguments in the argument list of the class instance creation expression, if any, in the order they appear in the expression.

Otherwise the arguments in the argument list, if any, are the arguments to the constructor, in the order they appear in the expression.

Second, a constructor of C and corresponding result type and throws clause are determined:

If the class instance creation expression uses " <> " to elide class type arguments, a list of methods m 1 ... m n is defined for the purpose of overload resolution and type argument inference.

Let c 1 ... c n be the constructors of class C . Let #m be an automatically generated name that is distinct from all constructor and method names in C . For all j (1 ≤ j ≤ n ), m j is defined in terms of c j as follows:

A substitution θ j is first defined to instantiate the types in c j .

Let F 1 ... F p be the type parameters of C , and let G 1 ... G q be the type parameters (if any) of c j . Let X 1 ... X p and Y 1 ... Y q be type variables with distinct names that are not in scope in the body of C .

θ j is [ F 1 := X 1 , ..., F p := X p , G 1 := Y 1 , ..., G q := Y q ] .

The modifiers of m j are those of c j .

The type parameters of m j are X 1 ... X p , Y 1 ... Y q . The bound of each parameter, if any, is θ j applied to the corresponding parameter bound in C or c j .

The return type of m j is θ j applied to C < F 1 ,..., F p > .

The name of m j is #m .

The (possibly empty) list of argument types of m j is θ j applied to the argument types of c j .

The (possibly empty) list of thrown types of m j is θ j applied to the thrown types of c j .

The body of m j is irrelevant.

To choose a constructor, we temporarily consider m 1 ... m n to be members of C . Then one of m 1 ... m n is selected, as determined by the class instance creation's argument expressions, using the process described in §15.12.2 .

It is a compile-time error if there is no unique most-specific method that is both applicable and accessible.

Otherwise, where m j is the selected method, c j is the chosen constructor. The result type and throws clause of c j are the same as the return type and throws clause determined for m j ( §15.12.2.6 ).

Otherwise, the class instance creation expression does not use " <> " to elide class type arguments.

Let T be the type denoted by C followed by any class type arguments in the expression. The process described in §15.12.2 , modified to handle constructors, is used to select one of the constructors of T and determine its throws clause.

As in method invocations, it is a compile-time error if there is no unique most-specific constructor that is both applicable and accessible.

Otherwise, the result type is T .

Finally, the type of the class instance creation expression is the result type of the chosen constructor, as defined above.

Note that the type of the class instance creation expression may be an anonymous class type, in which case the constructor being invoked is an anonymous constructor ( §15.9.5.1 ).

15.9.4. Run-Time Evaluation of Class Instance Creation Expressions

At run time, evaluation of a class instance creation expression is as follows.

First, if the class instance creation expression is a qualified class instance creation expression, the qualifying primary expression is evaluated. If the qualifying expression evaluates to null , a NullPointerException is raised, and the class instance creation expression completes abruptly. If the qualifying expression completes abruptly, the class instance creation expression completes abruptly for the same reason.

Next, space is allocated for the new class instance. If there is insufficient space to allocate the object, evaluation of the class instance creation expression completes abruptly by throwing an OutOfMemoryError .

The new object contains new instances of all the fields declared in the specified class type and all its superclasses. As each new field instance is created, it is initialized to its default value ( §4.12.5 ).

Next, the actual arguments to the constructor are evaluated, left-to-right. If any of the argument evaluations completes abruptly, any argument expressions to its right are not evaluated, and the class instance creation expression completes abruptly for the same reason.

Next, the selected constructor of the specified class type is invoked. This results in invoking at least one constructor for each superclass of the class type. This process can be directed by explicit constructor invocation statements ( §8.8 ) and is described in detail in §12.5 .

The value of a class instance creation expression is a reference to the newly created object of the specified class. Every time the expression is evaluated, a fresh object is created.

Example 15.9.4-1. Evaluation Order and Out-Of-Memory Detection

If evaluation of a class instance creation expression finds there is insufficient memory to perform the creation operation, then an OutOfMemoryError is thrown. This check occurs before any argument expressions are evaluated.

because the out-of-memory condition is detected before the argument expression oldid = id is evaluated.

Compare this to the treatment of array creation expressions ( §15.10 ), for which the out-of-memory condition is detected after evaluation of the dimension expressions ( §15.10.1 ).

15.9.5. Anonymous Class Declarations

An anonymous class declaration is automatically derived from a class instance creation expression by the Java compiler.

An anonymous class is never abstract ( §8.1.1.1 ).

An anonymous class is always implicitly final ( §8.1.1.2 ).

An anonymous class is always an inner class ( §8.1.3 ); it is never static ( §8.1.1 , §8.5.1 ).

15.9.5.1. Anonymous Constructors

An anonymous class cannot have an explicitly declared constructor. Instead, a Java compiler must automatically provide an anonymous constructor for the anonymous class. The form of the anonymous constructor of an anonymous class C with direct superclass S is as follows:

If S is not an inner class, or if S is a local class that occurs in a static context, then the anonymous constructor has one formal parameter for each actual argument to the class instance creation expression in which C is declared.

The actual arguments to the class instance creation expression are used to determine a constructor cs of S , using the same rules as for method invocations ( §15.12 ).

The type of each formal parameter of the anonymous constructor must be identical to the corresponding formal parameter of cs .

The body of the constructor consists of an explicit constructor invocation ( §8.8.7.1 ) of the form super(...) , where the actual arguments are the formal parameters of the constructor, in the order they were declared.

Otherwise, the first formal parameter of the constructor of C represents the value of the immediately enclosing instance of i with respect to S . The type of this parameter is the class type that immediately encloses the declaration of S .

The constructor has an additional formal parameter for each actual argument to the class instance creation expression that declared the anonymous class. The n 'th formal parameter e corresponds to the n-1 'th actual argument.

The body of the constructor consists of an explicit constructor invocation ( §8.8.7.1 ) of the form o.super(...) , where o is the first formal parameter of the constructor, and the actual arguments are the subsequent formal parameters of the constructor, in the order they were declared.

In all cases, the throws clause of an anonymous constructor must list all the checked exceptions thrown by the explicit superclass constructor invocation statement contained within the anonymous constructor, and all checked exceptions thrown by any instance initializers or instance variable initializers of the anonymous class.

Note that it is possible for the signature of the anonymous constructor to refer to an inaccessible type (for example, if such a type occurred in the signature of the superclass constructor cs ). This does not, in itself, cause any errors at either compile-time or run-time.

15.10. Array Creation Expressions

An array creation expression is used to create new arrays ( §10 ).

ArrayCreationExpression:      new  PrimitiveType DimExprs Dims opt      new  ClassOrInterfaceType DimExprs Dims opt      new  PrimitiveType Dims ArrayInitializer       new  ClassOrInterfaceType Dims ArrayInitializer DimExprs:     DimExpr     DimExprs DimExpr DimExpr:      [  Expression  ] Dims:      [   ]     Dims  [   ]

An array creation expression creates an object that is a new array whose elements are of the type specified by the PrimitiveType or ClassOrInterfaceType .

It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type ( §4.7 ). Otherwise, the ClassOrInterfaceType may name any named reference type, even an abstract class type ( §8.1.1.1 ) or an interface type ( §9 ).

The rules above imply that the element type in an array creation expression cannot be a parameterized type, other than an unbounded wildcard.

The type of each dimension expression within a DimExpr must be a type that is convertible ( §5.1.8 ) to an integral type, or a compile-time error occurs.

Each dimension expression undergoes unary numeric promotion ( §5.6.1 ). The promoted type must be int , or a compile-time error occurs.

The type of the array creation expression is an array type that can denoted by a copy of the array creation expression from which the new keyword and every DimExpr expression and array initializer have been deleted.

For example, the type of the creation expression:

15.10.1. Run-Time Evaluation of Array Creation Expressions

At run time, evaluation of an array creation expression behaves as follows:

If there are no dimension expressions, then there must be an array initializer.

A newly allocated array will be initialized with the values provided by the array initializer as described in §10.6 .

The value of the array initializer becomes the value of the array creation expression.

Otherwise, there is no array initializer, and:

First, the dimension expressions are evaluated, left-to-right. If any of the expression evaluations completes abruptly, the expressions to the right of it are not evaluated.

Next, the values of the dimension expressions are checked. If the value of any DimExpr expression is less than zero, then a NegativeArraySizeException is thrown.

Next, space is allocated for the new array. If there is insufficient space to allocate the array, evaluation of the array creation expression completes abruptly by throwing an OutOfMemoryError .

Then, if a single DimExpr appears, a one-dimensional array is created of the specified length, and each component of the array is initialized to its default value ( §4.12.5 ).

Otherwise, if n DimExpr expressions appear, then array creation effectively executes a set of nested loops of depth n -1 to create the implied arrays of arrays.

A multidimensional array need not have arrays of the same length at each level.

Example 15.10.1-1. Array Creation Evaluation

In an array creation expression with one or more dimension expressions, each dimension expression is fully evaluated before any part of any dimension expression to its right. Thus:

because the first dimension is calculated as 4 before the second dimension expression sets i to 3 .

If evaluation of a dimension expression completes abruptly, no part of any dimension expression to its right will appear to have been evaluated. Thus:

because the embedded assignment that sets i to 1 is never executed.

Example 15.10.1-2. Multi-Dimensional Array Creation

The declaration:

is equivalent in behavior to:

is equivalent to:

with d , d1 , d2 , and d3 replaced by names that are not already locally declared. Thus, a single new expression actually creates one array of length 6, 6 arrays of length 10, 6x10 = 60 arrays of length 8, and 6x10x8 = 480 arrays of length 12. This example leaves the fifth dimension, which would be arrays containing the actual array elements (references to Age objects), initialized only to null references. These arrays can be filled in later by other code, such as:

A triangular matrix may be created by:

If evaluation of an array creation expression finds there is insufficient memory to perform the creation operation, then an OutOfMemoryError is thrown. If the array creation expression does not have an array initializer, then this check occurs only after evaluation of all dimension expressions has completed normally. If the array creation expression does have an array initializer, then an OutOfMemoryError can occur when an object of reference type is allocated during evaluation of a variable initializer expression, or when space is allocated for an array to hold the values of a (possibly nested) array initializer.

Example 15.10.1-3.  OutOfMemoryError and Dimension Expression Evaluation

because the out-of-memory condition is detected after the dimension expression oldlen = len is evaluated.

Compare this to class instance creation expressions ( §15.9 ), which detect the out-of-memory condition before evaluating argument expressions ( §15.9.4 ).

15.11. Field Access Expressions

A field access expression may access a field of an object or array, a reference to which is the value of either an expression or the special keyword super .

FieldAccess:      Primary  .  Identifier      super   .  Identifier     ClassName  .   super   .  Identifier

The meaning of a field access expression is determined using the same rules as for qualified names ( §6.5.6.2 ), but limited by the fact that an expression cannot denote a package, class type, or interface type.

It is also possible to refer to a field of the current instance or current class by using a simple name ( §6.5.6.1 ).

15.11.1. Field Access Using a Primary

The type of the Primary must be a reference type T , or a compile-time error occurs.

The meaning of the field access expression is determined as follows:

If the identifier names several accessible ( §6.6 ) member fields in type T , then the field access is ambiguous and a compile-time error occurs.

If the identifier does not name an accessible member field in type T , then the field access is undefined and a compile-time error occurs.

Otherwise, the identifier names a single accessible member field in type T , and the type of the field access expression is the type of the member field after capture conversion ( §5.1.10 ).

At run time, the result of the field access expression is computed as follows: (assuming that the program is correct with respect to definite assignment analysis, i.e. every blank final variable is definitely assigned before access)

If the field is static :

The Primary expression is evaluated, and the result is discarded. If evaluation of the Primary expression completes abruptly, the field access expression completes abruptly for the same reason.

If the field is a non-blank final field, then the result is the value of the specified class variable in the class or interface that is the type of the Primary expression.

If the field is not final , or is a blank final and the field access occurs in a constructor, then the result is a variable, namely, the specified class variable in the class that is the type of the Primary expression.

If the field is not static :

The Primary expression is evaluated. If evaluation of the Primary expression completes abruptly, the field access expression completes abruptly for the same reason.

If the value of the Primary is null , then a NullPointerException is thrown.

If the field is a non-blank final , then the result is the value of the named member field in type T found in the object referenced by the value of the Primary .

If the field is not final , or is a blank final and the field access occurs in a constructor, then the result is a variable, namely the named member field in type T found in the object referenced by the value of the Primary .

Note that only the type of the Primary expression, not the class of the actual object referred to at run time, is used in determining which field to use.

Example 15.11.1-1. Static Binding for Field Access

The last line shows that, indeed, the field that is accessed does not depend on the run-time class of the referenced object; even if s holds a reference to an object of class T , the expression s.x refers to the x field of class S , because the type of the expression s is S . Objects of class T contain two fields named x , one for class T and one for its superclass S .

This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used. Consider the same example using instance methods to access the fields:

Now the output is:

The last line shows that, indeed, the method that is accessed does depend on the run-time class of the referenced object; when s holds a reference to an object of class T , the expression s.z() refers to the z method of class T , despite the fact that the type of the expression s is S . Method z of class T overrides method z of class S .

Example 15.11.1-2. Receiver Variable Is Irrelevant For static Field Access

The following program demonstrates that a null reference may be used to access a class ( static ) variable without causing an exception:

It compiles, executes, and prints:

Even though the result of favorite() is null , a NullPointerException is not thrown. That " Mount " is printed demonstrates that the Primary expression is indeed fully evaluated at run time, despite the fact that only its type, not its value, is used to determine which field to access (because the field mountain is static ).

15.11.2. Accessing Superclass Members using super

The form super . Identifier refers to the field named Identifier of the current object, but with the current object viewed as an instance of the superclass of the current class.

The form T . super . Identifier refers to the field named Identifier of the lexically enclosing instance corresponding to T , but with that instance viewed as an instance of the superclass of T .

The forms using the keyword super are valid only in an instance method, instance initializer, or constructor, or in the initializer of an instance variable of a class. If they appear anywhere else, a compile-time error occurs.

These are exactly the same situations in which the keyword this may be used ( §15.8.3 ).

It is a compile-time error if the forms using the keyword super appear in the declaration of class Object , since Object has no superclass.

If a field access expression super . name appears within class C , and the immediate superclass of C is class S , then super . name is treated exactly as if it had been the expression this . name in the body of class S . Thus it can access the field name that is visible in class S , even if that field is hidden by a declaration of a field name in class C .

If a field access expression T . super . name appears within class C , and the immediate superclass of the class denoted by T is a class whose fully qualified name is S , then T . super . name is treated exactly as if it had been the expression this . name in the body of class S . Thus it can access the field name that is visible in class S , even if that field is hidden by a declaration of a field name in class T .

It is a compile-time error if the current class is not an inner class of class T or T itself.

Example 15.11.2-1. The super Expression

Within class T3 , the expression super.x is treated as if it were:

Note that super.x is not specified in terms of a cast, due to difficulties around access to protected members of the superclass.

15.12. Method Invocation Expressions

A method invocation expression is used to invoke a class or instance method.

MethodInvocation:     MethodName  (  ArgumentList opt   )     Primary  .  NonWildTypeArguments opt  Identifier  (  ArgumentList opt   )      super   .  NonWildTypeArguments opt  Identifier  (  ArgumentList opt   )     ClassName  .   super   .  NonWildTypeArguments opt  Identifier  (  ArgumentList opt   )     TypeName  .  NonWildTypeArguments Identifier  (  ArgumentList opt   )

The definition of ArgumentList from §15.9 is repeated here for convenience:

ArgumentList:     Expression     ArgumentList  ,  Expression

Resolving a method name at compile time is more complicated than resolving a field name because of the possibility of method overloading. Invoking a method at run time is also more complicated than accessing a field because of the possibility of instance method overriding.

Determining the method that will be invoked by a method invocation expression involves several steps. The following three sections describe the compile-time processing of a method invocation; the determination of the type of the method invocation expression is described in §15.12.3 .

15.12.1. Compile-Time Step 1: Determine Class or Interface to Search

The first step in processing a method invocation at compile time is to figure out the name of the method to be invoked and which class or interface to check for definitions of methods of that name. There are several cases to consider, depending on the form that precedes the left parenthesis, as follows.

If the form is MethodName , then there are three subcases:

If it is a simple name, that is, just an Identifier , then the name of the method is the Identifier .

If the Identifier appears within the scope of a visible method declaration with that name ( §6.3 , §6.4.1 ), then:

If there is an enclosing type declaration of which that method is a member, let T be the innermost such type declaration. The class or interface to search is T .

This search policy is called the "comb rule". It effectively looks for methods in a nested class's superclass hierarchy before looking for methods in an enclosing class and its superclass hierarchy. See §6.5.7.1 for an example.

Otherwise, the visible method declaration may be in scope due to one or more single-static-import or static-import-on-demand declarations ( §7.5.3 , §7.5.4 ). There is no class or interface to search, as the method to be invoked is determined later ( §15.12.2 ).

If it is a qualified name of the form TypeName . Identifier , then the name of the method is the Identifier and the class to search is the one named by the TypeName .

If TypeName is the name of an interface rather than a class, then a compile-time error occurs, because this form can invoke only static methods and interfaces have no static methods.

In all other cases, the qualified name has the form FieldName . Identifier .

The name of the method is the Identifier and the class or interface to search is the declared type T of the field named by the FieldName , if T is a class or interface type, or the upper bound of T if T is a type variable.

If the form is Primary . NonWildTypeArguments opt Identifier , then the name of the method is the Identifier .

Let T be the type of the Primary expression. The class or interface to be searched is T if T is a class or interface type, or the upper bound of T if T is a type variable.

It is a compile-time error if T is not a reference type.

If the form is super . NonWildTypeArguments opt Identifier , then the name of the method is the Identifier and the class to be searched is the superclass of the class whose declaration contains the method invocation.

Let T be the type declaration immediately enclosing the method invocation. It is a compile-time error if T is the class Object or T is an interface.

If the form is ClassName . super . NonWildTypeArguments opt Identifier , then the name of the method is the Identifier and the class to be searched is the superclass of the class C denoted by ClassName .

It is a compile-time error if C is not a lexically enclosing class of the current class.

It is a compile-time error if C is the class Object .

If the form is TypeName . NonWildTypeArguments Identifier , then the name of the method is the Identifier and the class to be searched is the class C denoted by TypeName .

15.12.2. Compile-Time Step 2: Determine Method Signature

The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the types of the argument expressions to locate methods that are both accessible and applicable , that is, declarations that can be correctly invoked on the given arguments.

There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is one used at run time to perform the method dispatch.

A method is applicable if it is either applicable by subtyping ( §15.12.2.2 ), applicable by method invocation conversion ( §15.12.2.3 ), or it is an applicable variable arity method ( §15.12.2.4 ).

The process of determining applicability begins by determining the potentially applicable methods ( §15.12.2.1 ).

The remainder of the process is split into three phases, to ensure compatibility with versions of the Java programming language prior to Java SE 5.0. The phases are:

The first phase ( §15.12.2.2 ) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. However, the declaration of a variable arity method ( §8.4.1 ) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. For example, declaring m(Object...) in a class which already declares m(Object) causes m(Object) to no longer be chosen for some invocation expressions (such as m(null) ), as m(Object[]) is more specific.

The second phase ( §15.12.2.3 ) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.

This ensures that a method is never chosen through variable arity method invocation if it is applicable through fixed arity method invocation.

The third phase ( §15.12.2.4 ) allows overloading to be combined with variable arity methods, boxing, and unboxing.

Deciding whether a method is applicable will, in the case of generic methods ( §8.4.4 ), require that type arguments be determined. Type arguments may be passed explicitly or implicitly. If they are passed implicitly, they must be inferred ( §15.12.2.7 ) from the types of the argument expressions.

If several applicable methods have been identified during one of the three phases of applicability testing, then the most specific one is chosen, as specified in section §15.12.2.5 .

Example 15.12.2-1. Method Applicability

For the method invocation two(1) within class Doubler , there are two accessible methods named two , but only the second one is applicable, and so that is the one invoked at run time.

For the method invocation two(3) within class Test , there are two applicable methods, but only the one in class Test is accessible, and so that is the one to be invoked at run time (the argument 3 is converted to type long ).

For the method invocation Doubler.two(3) , the class Doubler , not class Test , is searched for methods named two ; the only applicable method is not accessible, and so this method invocation causes a compile-time error.

Another example is:

Here, a compile-time error occurs for the second invocation of setColor , because no applicable method can be found at compile time. The type of the literal 37 is int , and int cannot be converted to byte by method invocation conversion. Assignment conversion, which is used in the initialization of the variable color , performs an implicit conversion of the constant from type int to byte , which is permitted because the value 37 is small enough to be represented in type byte ; but such a conversion is not allowed for method invocation conversion.

If the method setColor had, however, been declared to take an int instead of a byte , then both method invocations would be correct; the first invocation would be allowed because method invocation conversion does permit a widening conversion from byte to int . However, a narrowing cast would then be required in the body of setColor :

Here is an example of overloading ambiguity. Consider the program:

This example produces an error at compile time. The problem is that there are two declarations of test that are applicable and accessible, and neither is more specific than the other. Therefore, the method invocation is ambiguous.

If a third definition of test were added:

then it would be more specific than the other two, and the method invocation would no longer be ambiguous.

Example 15.12.2-2. Return Type Not Considered During Method Selection

Here, the most specific declaration of method test is the one taking a parameter of type ColoredPoint . Because the result type of the method is int , a compile-time error occurs because an int cannot be converted to a String by assignment conversion. This example shows that the result types of methods do not participate in resolving overloaded methods, so that the second test method, which returns a String , is not chosen, even though it has a result type that would allow the example program to compile without error.

Example 15.12.2-3. Choosing The Most Specific Method

The most specific method is chosen at compile time; its descriptor determines what method is actually executed at run time. If a new method is added to a class, then source code that was compiled with the old definition of the class might not use the new method, even if a recompilation would cause this method to be chosen.

So, for example, consider two compilation units, one for class Point :

and one for class ColoredPoint :

Now consider a third compilation unit that uses ColoredPoint :

The output is:

The programmer who coded class Test has expected to see the word green , because the actual argument, a ColoredPoint , has a color field, and color would seem to be a "relevant field". (Of course, the documentation for the package points ought to have been much more precise!)

Notice, by the way, that the most specific method (indeed, the only applicable method) for the method invocation of adopt has a signature that indicates a method of one parameter, and the parameter is of type Point . This signature becomes part of the binary representation of class Test produced by the Java compiler and is used by the method invocation at run time.

Suppose the programmer reported this software error and the maintainer of the points package decided, after due deliberation, to correct it by adding a method to class ColoredPoint :

If the programmer then runs the old binary file for Test with the new binary file for ColoredPoint , the output is still:

because the old binary file for Test still has the descriptor "one parameter, whose type is Point ; void " associated with the method call cp.adopt(cp2) . If the source code for Test is recompiled, the Java compiler will then discover that there are now two applicable adopt methods, and that the signature for the more specific one is "one parameter, whose type is ColoredPoint ; void "; running the program will then produce the desired output:

With forethought about such problems, the maintainer of the points package could fix the ColoredPoint class to work with both newly compiled and old code, by adding defensive code to the old adopt method for the sake of old code that still invokes it on ColoredPoint arguments:

Ideally, source code should be recompiled whenever code that it depends on is changed. However, in an environment where different classes are maintained by different organizations, this is not always feasible. Defensive programming with careful attention to the problems of class evolution can make upgraded code much more robust. See §13 for a detailed discussion of binary compatibility and type evolution.

15.12.2.1. Identify Potentially Applicable Methods

The class or interface determined by compile-time step 1 ( §15.12.1 ) is searched for all member methods that are potentially applicable to this method invocation; members inherited from superclasses and superinterfaces are included in this search.

In addition, if the method invocation has, before the left parenthesis, a MethodName of the form Identifier , then the search process also examines all member methods that are (a) imported by single-static-import declarations ( §7.5.3 ) and static-import-on-demand declarations ( §7.5.4 ) within the compilation unit ( §7.3 ) within which the method invocation occurs, and (b) not shadowed ( §6.4.1 ) at the place where the method invocation appears, to determine if they are potentially applicable.

A member method is potentially applicable to a method invocation if and only if all of the following are true:

The name of the member is identical to the name of the method in the method invocation.

The member is accessible ( §6.6 ) to the class or interface in which the method invocation appears.

Whether a member method is accessible at a method invocation depends on the access modifier ( public , none, protected , or private ) in the member's declaration and on where the method invocation appears.

If the member is a variable arity method with arity n , the arity of the method invocation is greater or equal to n -1 .

If the member is a fixed arity method with arity n , the arity of the method invocation is equal to n .

If the method invocation includes explicit type arguments, and the member is a generic method, then the number of type arguments is equal to the number of type parameters of the method.

This clause implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. Indeed, it may turn out to be applicable. In such a case, the type arguments will simply be ignored.

This rule stems from issues of compatibility and principles of substitutability. Since interfaces or superclasses may be generified independently of their subtypes, we may override a generic method with a non-generic one. However, the overriding (non-generic) method must be applicable to calls to the generic method, including calls that explicitly pass type arguments. Otherwise the subtype would not be substitutable for its generified supertype.

If the search does not yield at least one method that is potentially applicable, then a compile-time error occurs.

15.12.2.2. Phase 1: Identify Matching Arity Methods Applicable by Subtyping

Let m be a potentially applicable method ( §15.12.2.1 ), let e 1 , ..., e n be the actual argument expressions of the method invocation, and let A i be the type of e i (1 ≤ i ≤ n ). Then:

If m is a generic method, then let F 1 ... F n be the types of the formal parameters of m , and let R 1 ... R p ( p ≥ 1) be the type parameters of m , and let B l be the declared bound of R l (1 ≤ l ≤ p ). Then:

If the method invocation does not provide explicit type arguments, then let U 1 ... U p be the type arguments inferred ( §15.12.2.7 ) for this invocation of m , using a set of initial constraints consisting of the constraints A i << F i (1 ≤ i ≤ n ) for each actual argument expression e i whose type is a reference type.

Otherwise, let U 1 ... U p be the explicit type arguments given in the method invocation.

Then let S i = F i [ R 1 = U 1 ,..., R p = U p ] (1 ≤ i ≤ n ) be the types inferred for the formal parameters of m .

Otherwise, let S 1 ... S n be the types of the formal parameters of m .

The method m is applicable by subtyping if and only if both of the following conditions hold:

For 1 ≤ i ≤ n , either:

A i <: S i ( §4.10 ), or

A i is convertible to some type C i by unchecked conversion ( §5.1.9 ), and C i <: S i .

If m is a generic method as described above, then U l <: B l [ R 1 = U 1 ,..., R p = U p ] (1 ≤ l ≤ p ).

If no method applicable by subtyping is found, the search for applicable methods continues with phase 2 ( §15.12.2.3 ).

Otherwise, the most specific method ( §15.12.2.5 ) is chosen among the methods that are applicable by subtyping.

15.12.2.3. Phase 2: Identify Matching Arity Methods Applicable by Method Invocation Conversion

If the method invocation does not provide explicit type arguments, then let U 1 ... U p be the type arguments inferred ( §15.12.2.7 ) for this invocation of m , using a set of initial constraints consisting of the constraints A i << F i (1 ≤ i ≤ n ).

The method m is applicable by method invocation conversion if and only if both of the following conditions hold:

For 1 ≤ i ≤ n , the type of e i , A i , can be converted by method invocation conversion ( §5.3 ) to S i .

If no method applicable by method invocation conversion is found, the search for applicable methods continues with phase 3 ( §15.12.2.4 ).

Otherwise, the most specific method ( §15.12.2.5 ) is chosen among the methods that are applicable by method invocation conversion.

15.12.2.4. Phase 3: Identify Applicable Variable Arity Methods

Let m be a potentially applicable method ( §15.12.2.1 ) with variable arity, let e 1 , ..., e k be the actual argument expressions of the method invocation, and let A i be the type of e i (1 ≤ i ≤ k ). Then:

If m is a generic method, then let F 1 ... F n (1 ≤ n ≤ k +1) be the types of the formal parameters of m , where F n = T [] for some type T , and let R 1 ... R p ( p ≥ 1) be the type parameters of m , and let B l be the declared bound of R l (1 ≤ l ≤ p ). Then:

If the method invocation does not provide explicit type arguments then let U 1 ... U p be the type arguments inferred ( §15.12.2.7 ) for this invocation of m , using a set of initial constraints consisting of the constraints A i << F i (1 ≤ i < n ) and the constraints A j << T ( n ≤ j ≤ k ).

Otherwise let U 1 ... U p be the explicit type arguments given in the method invocation.

Otherwise, let S 1 ... S n (where n ≤ k +1) be the types of the formal parameters of m .

The method m is an applicable variable-arity method if and only if all of the following conditions hold:

For 1 ≤ i < n , the type of e i , A i , can be converted by method invocation conversion to S i .

If k ≥ n , then for n ≤ i ≤ k , the type of e i , A i , can be converted by method invocation conversion to the component type of S n .

If k != n , or if k = n and A n cannot be converted by method invocation conversion to S n [] , then the type which is the erasure ( §4.6 ) of S n is accessible at the point of invocation.

If m is a generic method as described above, then U l <: B l [ R 1 = U 1 ..., R p = U p ] (1 ≤ l ≤ p ).

If no applicable variable arity method is found, a compile-time error occurs.

Otherwise, the most specific method ( §15.12.2.5 ) is chosen among the applicable variable-arity methods.

15.12.2.5. Choosing the Most Specific Method

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.

One fixed-arity member method named m is more specific than another member method of the same name and arity if all of the following conditions hold:

The declared types of the parameters of the first member method are T 1 , ..., T n .

The declared types of the parameters of the other method are U 1 , ..., U n .

If the second method is generic, then let R 1 ... R p ( p ≥ 1) be its type parameters, let B l be the declared bound of R l (1 ≤ l ≤ p ), let A 1 ... A p be the type arguments inferred ( §15.12.2.7 ) for this invocation under the initial constraints T i << U i (1 ≤ i ≤ n ), and let S i = U i [ R 1 = A 1 ,..., R p = A p ] (1 ≤ i ≤ n ).

Otherwise, let S i = U i (1 ≤ i ≤ n ).

For all j from 1 to n , T j <: S j .

If the second method is a generic method as described above, then A l <: B l [ R 1 = A 1 ,..., R p = A p ] (1 ≤ l ≤ p ).

One variable arity member method named m is more specific than another variable arity member method of the same name if either:

One member method has n parameters and the other has k parameters, where n ≥ k , and:

The types of the parameters of the first member method are T 1 , ..., T n-1 , T n [] .

The types of the parameters of the other method are U 1 , ..., U k-1 , U k [] .

If the second method is generic then let R 1 ... R p ( p ≥ 1) be its type parameters, let B l be the declared bound of R l (1 ≤ l ≤ p ), let A 1 ... A p be the type arguments inferred ( §15.12.2.7 ) for this invocation under the initial constraints T i << U i (1 ≤ i ≤ k -1) and T i << U k ( k ≤ i ≤ n ), and let S i = U i [ R 1 = A 1 ,..., R p = A p ] (1 ≤ i ≤ k ).

Otherwise, let S i = U i (1 ≤ i ≤ k ).

For all j from 1 to k -1, T j <: S j , and,

For all j from k to n , T j <: S k , and,

One member method has k parameters and the other has n parameters, where n ≥ k , and:

The types of the parameters of the first method are U 1 , ..., U k-1 , U k [] .

The types of the parameters of the other method are T 1 , ..., T n-1 , T n [] .

If the second method is generic, then let R 1 ... R p ( p ≥ 1) be its type parameters, let B l be the declared bound of R l (1 ≤ l ≤ p ), let A 1 ... A p be the type arguments inferred ( §15.12.2.7 ) for this invocation under the initial constraints U i << T i (1 ≤ i ≤ k -1) and U k << T i ( k ≤ i ≤ n ), and let S i = T i [ R 1 = A 1 ,..., R p = A p ] (1 ≤ i ≤ n ).

Otherwise, let S i = T i (1 ≤ i ≤ n ).

For all j from 1 to k -1, U j <: S j , and,

For all j from k to n , U k <: S j , and,

The above conditions are the only circumstances under which one method may be more specific than another.

A method m 1 is strictly more specific than another method m 2 if and only if m 1 is more specific than m 2 and m 2 is not more specific than m 1 .

A method is said to be maximally specific for a method invocation if it is accessible and applicable and there is no other method that is applicable and accessible that is strictly more specific.

If there is exactly one maximally specific method, then that method is in fact the most specific method ; it is necessarily more specific than any other accessible method that is applicable. It is then subjected to some further compile-time checks as described in §15.12.3 .

It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case:

If all the maximally specific methods have override-equivalent ( §8.4.2 ) signatures, then:

If exactly one of the maximally specific methods is not declared abstract , it is the most specific method.

Otherwise, if all the maximally specific methods are declared abstract , and the signatures of all of the maximally specific methods have the same erasure ( §4.6 ), then the most specific method is chosen arbitrarily among the subset of the maximally specific methods that have the most specific return type.

However, the most specific method is considered to throw a checked exception if and only if that exception or its erasure is declared in the throws clauses of each of the maximally specific methods.

Otherwise, we say that the method invocation is ambiguous , and a compile-time error occurs.

15.12.2.6. Method Result and Throws Types

The result type of the chosen method is determined as follows:

If the chosen method is declared with a return type of void , then the result is void .

Otherwise, if unchecked conversion was necessary for the method to be applicable, then the result type is the erasure ( §4.6 ) of the method's declared return type.

Otherwise, if the chosen method is generic, then for 1 ≤ i ≤ n , let F i be the formal type parameters of the method, let A i be the actual type arguments inferred for the method invocation, and let R be the return type of the chosen method.

The result type is obtained by applying capture conversion ( §5.1.10 ) to R [ F 1 = A 1 ,..., F n = A n ] .

Otherwise, the result type is obtained by applying capture conversion ( §5.1.10 ) to the return type of the chosen method .

The exception types of the throws clause of the chosen method are determined as follows:

If unchecked conversion was necessary for the method to be applicable, then the throws clause is composed of the erasure ( §4.6 ) of the types in the method's declared throws clause.

Otherwise, if the method being invoked is generic, then for 1 ≤ i ≤ n , let F i be the type parameters of the method, let A i be the type arguments inferred for the method invocation, and let E j (1 ≤ j ≤ m ) be the exception types declared in the throws clause of the method being invoked.

The throws clause consists of the types E j [ F 1 = A 1 ,..., F n = A n ] .

Otherwise, the type of the throws clause is the type given in the method declaration.

The exception types that a method invocation expression can throw are specified in §11.2.1 .

15.12.2.7. Inferring Type Arguments Based on Actual Arguments

In this section, we describe the process of inferring type arguments for method and constructor invocations. This process is invoked as a subroutine when testing for method (or constructor) applicability ( §15.12.2.2 , §15.12.2.3 , §15.12.2.4 ).

The process of type inference is inherently complex. Therefore, it is useful to give an informal overview of the process before delving into the detailed specification.

Inference begins with an initial set of constraints. Generally, the constraints require that the statically known types of the actual arguments are acceptable given the declared formal parameter types. We discuss the meaning of "acceptable" below.

Given these initial constraints, one may derive a set of supertype and/or equality constraints on the type parameters of the method or constructor.

Next, one must try and find a solution that satisfies the constraints on the type parameters. As a first approximation, if a type parameter is constrained by an equality constraint, then that constraint gives its solution. Bear in mind that the constraint may equate one type parameter with another, and only when the entire set of constraints on all type variables is resolved will we have a solution.

A supertype constraint T :> X implies that the solution is one of supertypes of X . Given several such constraints on T , we can intersect the sets of supertypes implied by each of the constraints, since the type parameter must be a member of all of them. We can then choose the most specific type that is in the intersection.

Computing the intersection is more complicated than one might first realize. Given that a type parameter is constrained to be a supertype of two distinct invocations of a generic type, say List < Object > and List < String > , the naive intersection operation might yield Object . However, a more sophisticated analysis yields a set containing List < ? > . Similarly, if a type parameter T is constrained to be a supertype of two unrelated interfaces I and J , we might infer T must be Object , or we might obtain a tighter bound of I & J . These issues are discussed in more detail later in this section.

We use the following notational conventions in this section:

Type expressions are represented using the letters A , F , U , V , and W . The letter A is only used to denote the type of an actual argument, and F is only used to denote the type of a formal parameter.

Type parameters are represented using the letters S and T

Arguments to parameterized types are represented using the letters X and Y .

Generic type declarations are represented using the letters G and H .

Inference begins with a set of initial constraints of the form A << F , A = F , or A >> F , where U << V indicates that type U is convertible to type V by method invocation conversion ( §5.3 ), and U >> V indicates that type V is convertible to type U by method invocation conversion.

In a simpler world, the constraints could be of the form A <: F - simply requiring that the actual argument types be subtypes of the formal ones. However, reality is more involved. As discussed earlier, method applicability testing consists of up to three phases; this is required for compatibility reasons. Each phase imposes slightly different constraints. If a method is applicable by subtyping ( §15.12.2.2 ), the constraints are indeed subtyping constraints. If a method is applicable by method invocation conversion ( §15.12.2.3 ), the constraints imply that the actual type is convertible to the formal type by method invocation conversion. The situation is similar for the third phase ( §15.12.2.4 ), but the exact form of the constraints differ due to the variable arity.

It is worth noting that a constraint of the form A = F is never part of the initial constraints. However, it can arise as the algorithm recurses. We see this occur in the running example below, when the constraint A << F relates two parameterized types, as in G < V > << G < U > .

A constraint of the form A >> F also arises when the algorithm recurses, due to the contravariant subtyping rules associated with lower-bounded wildcards (those of the form G < ? super X > ).

It might be tempting to consider A >> F as being the same as F << A , but the problem of inference is not symmetric. We need to remember which participant in the relation includes a type to be inferred.

These constraints are then reduced to a set of simpler constraints of the forms T :> X , T = X , or T <: X , where T is a type parameter of the method. This reduction is achieved by the procedure given below.

It may be that the initial constraints are unsatisfiable; we say that inference is overconstrained . In that case, we do not necessarily derive unsatisfiable constraints on the type parameters. Instead, we may infer type arguments for the invocation, but once we substitute the type arguments for the type parameters, the applicability test may fail because the actual argument types are not acceptable given the substituted formal parameter types.

An alternative strategy would be to have type inference itself fail in such cases. A Java compiler may choose to do so, provided the effect is equivalent to that specified here.

Given a constraint of the form A << F , A = F , or A >> F :

If F does not involve a type parameter T j then no constraint is implied on T j .

Otherwise, F involves a type parameter T j , and there are four cases to consider.

1. If A is the type of null , no constraint is implied on T j .

2. Otherwise, if the constraint has the form A << F :

If A is a primitive type, then A is converted to a reference type U via boxing conversion and this algorithm is applied recursively to the constraint U << F .

Otherwise, if F = T j , then the constraint T j :> A is implied.

If F = U [] , where the type U involves T j , then if A is an array type V [] , or a type variable with an upper bound that is an array type V [] , where V is a reference type, this algorithm is applied recursively to the constraint V << U .

This follows from the covariant subtype relation among array types. The constraint A << F in this case means that A << U [] . A is therefore necessarily an array type V [] , or a type variable whose upper bound is an array type V [] - otherwise the relation A << U [] could never hold true. It follows that V [] << U [] . Since array subtyping is covariant, it must be the case that V << U .

If F has the form G < ..., Y k-1 , U , Y k+1 , ... > , where U is a type expression that involves T j , then if A has a supertype of the form G < ..., X k-1 , V , X k+1 , ... > where V is a type expression, this algorithm is applied recursively to the constraint V = U .

For simplicity, assume that G takes a single type argument. If the method invocation being examined is to be applicable, it must be the case that A is a subtype of some invocation of G . Otherwise, A << F would never be true.

In other words, A << F , where F = G < U > , implies that A << G < V > for some V . Now, since U is a type expression (and therefore, U is not a wildcard type argument), it must be the case that U = V , by the non-variance of ordinary parameterized type invocations.

The formulation above merely generalizes this reasoning to generics with an arbitrary number of type arguments.

If F has the form G < ..., Y k-1 , ? extends U , Y k+1 , ... > , where U involves T j , then if A has a supertype that is one of:

G < ..., X k-1 , V , X k+1 , ... > , where V is a type expression. Then this algorithm is applied recursively to the constraint V << U .

Again, let's keep things as simple as possible, and consider only the case where G has a single type argument.

A << F in this case means A << G < ? extends U > . As above, it must be the case that A is a subtype of some invocation of G . However, A may now be a subtype of either G < V > , or G < ? extends V > , or G < ? super V > . We examine these cases in turn. The first variation is described (generalized to multiple arguments) by the sub-bullet directly above. We therefore have A = G < V > << G < ? extends U > . The rules of subtyping for wildcards imply that V << U .

G < ..., X k-1 , ? extends V , X k+1 , ... > . Then this algorithm is applied recursively to the constraint V << U .

Extending the analysis above, we have A = G < ? extends V > << G < ? extends U > . The rules of subtyping for wildcards again imply that V << U .

Otherwise, no constraint is implied on T j .

Here, we have A = G < ? super V > << G < ? extends U > . In general, we cannot conclude anything in this case. However, it is not necessarily an error. It may be that U will eventually be inferred to be Object , in which case the call may indeed be valid. Therefore, we simply refrain from placing any constraint on U .

If F has the form G < ..., Y k-1 , ? super U , Y k+1 , ... > , where U involves T j , then if A has a supertype that is one of:

G < ..., X k-1 , V , X k+1 , ... > . Then this algorithm is applied recursively to the constraint V >> U .

As usual, we consider only the case where G has a single type argument.

A << F in this case means A << G < ? super U > . As above, it must be the case that A is a subtype of some invocation of G . A may now be a subtype of either G < V > , or G < ? extends V > , or G < ? super V > . We examine these cases in turn. The first variation is described (generalized to multiple arguments) by the sub-bullet directly above. We therefore have A = G < V > << G < ? super U > . The rules of subtyping for wildcards imply that V >> U .

G < ..., X k-1 , ? super V , X k+1 , ... > . Then this algorithm is applied recursively to the constraint V >> U .

We have A = G < ? super V > << G < ? super U > . The rules of subtyping for lower-bounded wildcards again imply that V >> U .

Here, we have A = G < ? extends V > << G < ? super U > . In general, we cannot conclude anything in this case. However, it is not necessarily an error. It may be that U will eventually be inferred to the null type, in which case the call may indeed be valid. Therefore, we simply refrain from placing any constraint on U .

3. Otherwise, if the constraint has the form A = F :

If F = T j , then the constraint T j = A is implied.

If F = U [] where the type U involves T j , then if A is an array type V [] , or a type variable with an upper bound that is an array type V [] , where V is a reference type, this algorithm is applied recursively to the constraint V = U .

If the array types U [] and V [] are the same, their component types must be the same.

If F has the form G < ..., Y k-1 , U , Y k+1 , ... > , where U is type expression that involves T j , then if A is of the form G < ..., X k-1 , V , X k+1 ,... > where V is a type expression, this algorithm is applied recursively to the constraint V = U .

If F has the form G < ..., Y k-1 , ? extends U , Y k+1 , ... > , where U involves T j , then if A is one of:

G < ..., X k-1 , ? extends V , X k+1 , ... > . Then this algorithm is applied recursively to the constraint V = U .

If F has the form G < ..., Y k-1 , ? super U , Y k+1 ,... > , where U involves T j , then if A is one of:

G < ..., X k-1 , ? super V , X k+1 , ... > . Then this algorithm is applied recursively to the constraint V = U .

4. Otherwise, if the constraint has the form A >> F :

If F = T j , then the constraint T j <: A is implied.

We do not make use of such constraints in the main body of the inference algorithm. However, they are used in §15.12.2.8 .

If F = U [] , where the type U involves T j , then if A is an array type V [] , or a type variable with an upper bound that is an array type V [] , where V is a reference type, this algorithm is applied recursively to the constraint V >> U . Otherwise, no constraint is implied on T j .

This follows from the covariant subtype relation among array types. The constraint A >> F in this case means that A >> U [] . A is therefore necessarily an array type V [] , or a type variable whose upper bound is an array type V [] - otherwise the relation A >> U [] could never hold true. It follows that V [] >> U [] . Since array subtyping is covariant, it must be the case that V >> U .

If F has the form G < ..., Y k-1 , U , Y k+1 , ... > , where U is a type expression that involves T j , then:

If A is an instance of a non-generic type, then no constraint is implied on T j .

In this case (once again restricting the analysis to the unary case), we have the constraint A >> F = G < U > . A must be a supertype of the generic type G . However, since A is not a parameterized type, it cannot depend upon the type argument U in any way. It is a supertype of G < X > for every X that is a valid type argument to G . No meaningful constraint on U can be derived from A .

If A is an invocation of a generic type declaration H , where H is either G or superclass or superinterface of G , then:

If H ≠ G , then let S 1 , ..., S n be the type parameters of G , and let H < U 1 , ..., U l > be the unique invocation of H that is a supertype of G < S 1 , ..., S n > , and let V = H < U 1 , ..., U l > [ S k = U ] . Then, if V :> F this algorithm is applied recursively to the constraint A >> V .

Our goal here is to simplify the relationship between A and F . We aim to recursively invoke the algorithm on a simpler case, where the type argument is known to be an invocation of the same generic type declaration as the formal.

Let's consider the case where both H and G have only a single type argument. Since we have the constraint A = H < X > >> F = G < U > , where H is distinct from G , it must be the case that H is some proper superclass or superinterface of G . There must be a (non-wildcard) invocation of H that is a supertype of F = G < U > . Call this invocation V .

If we replace F by V in the constraint, we will have accomplished the goal of relating two invocations of the same generic (as it happens, H ).

How do we compute V ? The declaration of G must introduce a type parameter S , and there must be some (non-wildcard) invocation of H , H < U 1 > , that is a supertype of G < S > . Substituting the type expression U for S will then yield a (non-wildcard) invocation of H , H < U 1 > [ S = U ] , that is a supertype of G < U > . For example, in the simplest instance, U 1 might be S , in which case we have G < S > <: H < S > , and G < U > <: H < U > = H < S > [ S = U ] = V .

It may be the case that H < U 1 > is independent of S - that is, S does not occur in U 1 at all. However, the substitution described above is still valid - in this situation, V = H < U 1 > [ S = U ] = H < U 1 > . Furthermore, in this circumstance, G < T > <: H < U 1 > for any T , and in particular G < U > <: H < U 1 > = V .

Regardless of whether U 1 depends on S , we have determined the type V , the invocation of H that is a supertype of G < U > . We can now invoke the algorithm recursively on the constraint H < X > = A >> V = H < U 1 > [ S = U ] . We will then be able to relate the type arguments of both invocations of H and extract the relevant constraints from them.

Otherwise, if A is of the form G < ..., X k-1 , W , X k+1 , ... > , where W is a type expression, this algorithm is applied recursively to the constraint W = U .

We have A = G < W > >> F = G < U > for some type expression W . Since W is a type expression (and not a wildcard type argument), it must be the case that W = U , by the invariance of parameterized types.

Otherwise, if A is of the form G < ..., X k-1 , ? extends W , X k+1 , ... > , this algorithm is applied recursively to the constraint W >> U .

We have A = G < ? extends W > >> F = G < U > for some type expression W . It must be the case that W >> U , by the subtyping rules for wildcard types.

Otherwise, if A is of the form G < ..., X k-1 , ? super W , X k+1 , ... > , this algorithm is applied recursively to the constraint W << U .

We have A = G < ? super W > >> F = G < U > for some type expression W . It must be the case that W << U , by the subtyping rules for wildcard types.

If F has the form G < ..., Y k-1 , ? extends U , Y k+1 , ... > , where U is a type expression that involves T j , then:

Once again restricting the analysis to the unary case, we have the constraint A >> F = G < ? extends U > . A must be a supertype of the generic type G . However, since A is not a parameterized type, it cannot depend upon U in any way. It is a supertype of the type G < ? extends X > for every X such that ? extends X is a valid type argument to G . No meaningful constraint on U can be derived from A .

If H ≠ G , then let S 1 , ..., S n be the type parameters of G , and let H < U 1 , ..., U l > be the unique invocation of H that is a supertype of G < S 1 , ..., S n > , and let V = H < ? extends U 1 , ..., ? extends U l > [ S k = U ] . Then this algorithm is applied recursively to the constraint A >> V .

Our goal here is once more to simplify the relationship between A and F , and recursively invoke the algorithm on a simpler case, where the type argument is known to be an invocation of the same generic type as the formal.

Assume both H and G have only a single type argument. Since we have the constraint A = H < X > >> F = G < ? extends U > , where H is distinct from G , it must be the case that H is some proper superclass or superinterface of G . There must be an invocation of H < Y > , such that H < X > >> H < Y > , that we can use instead of F = G < ? extends U > .

How do we compute H < Y > ? As before, note that the declaration of G must introduce a type parameter S , and there must be some (non-wildcard) invocation of H , H < U 1 > , that is a supertype of G < S > . However, substituting ? extends U for S is not generally valid. To see this, assume U 1 = T [] .

Instead, we produce an invocation of H , H < ? extends U 1 > [ S = U ] . In the simplest instance, U 1 might be S , in which case we have G < S > <: H < S > , and G < ? extends U > <: H < ? extends U > = H < ? extends S > [ S = U ] = V .

We have A = G < ? extends W > >> F = G < ? extends U > for some type expression W . By the subtyping rules for wildcards it must be the case that W >> U .

If F has the form G < ..., Y k-1 , ? super U , Y k+1 , ... > , where U is a type expression that involves T j , then A is either:

Restricting the analysis to the unary case, we have the constraint A >> F = G < ? super U > . A must be a supertype of the generic type G . However, since A is not a parameterized type, it cannot depend upon U in any way. It is a supertype of the type G < ? super X > for every X such that ? super X is a valid type argument to G . No meaningful constraint on U can be derived from A .

If H ≠ G , then let S 1 , ..., S n be the type parameters of G , and let H < U 1 , ..., U l > be the unique invocation of H that is a supertype of G < S 1 , ..., S n > , and let V = H < ? super U 1 , ..., ? super U l > [ S k = U ] . Then this algorithm is applied recursively to the constraint A >> V .

The treatment here is analogous to the case where A = G < ? extends U > . Here our example would produce an invocation H < ? super U 1 > [ S = U ] .

Otherwise, if A is of the form G < ..., X k-1 , ? super W , ..., X k+1 , ... > , this algorithm is applied recursively to the constraint W << U .

We have A = G < ? super W > >> F = G < ? super U > for some type expression W . It must be the case that W << U , by the subtyping rules for wildcard types.

This concludes the process of determining constraints on the type parameters of a method.

Note that this process does not impose any constraints on the type parameters based on their declared bounds. Once type arguments are inferred, they will be tested against the declared bounds of the type parameters as part of applicability testing.

Note also that type inference does not affect soundness in any way. If the types inferred are nonsensical, the invocation will yield a type error. The type inference algorithm should be viewed as a heuristic, designed to perform well in practice. If it fails to infer the desired result, explicit type paramneters may be used instead.

Next, for each type variable T j (1 ≤ j ≤ n ), the implied equality constraints are resolved as follows.

For each implied equality constraint T j = U or U = T j :

If U is not one of the type parameters of the method, then U is the type inferred for T j . Then all remaining constraints involving T j are rewritten such that T j is replaced with U . There are necessarily no further equality constraints involving T j , and processing continues with the next type parameter, if any.

Otherwise, if U is T j , then this constraint carries no information and may be discarded.

Otherwise, the constraint is of the form T j = T k for j ≠ k . Then all constraints involving T j are rewritten such that T j is replaced with T k , and processing continues with the next type variable.

Then, for each remaining type variable T j , the constraints T j :> U are considered. Given that these constraints are T j :> U 1 ... T j :> U k , the type of T j is inferred as lub( U 1 ... U k ), computed as follows:

For a type U , we write ST( U ) for the set of supertypes of U , and define the erased supertype set of U :

EST( U ) = { V | W in ST( U ) and V = | W | } where | W | is the erasure ( §4.6 ) of W .

The reason for computing the set of erased supertypes is to deal with situations where a type variable is constrained to be a supertype of several distinct invocations of a generic type declaration.

For example, if T :> List < String > and T :> List < Object > , simply intersecting the sets ST( List < String > ) = { List < String > , Collection < String > , Object } and ST( List < Object > ) = { List < Object > , Collection < Object > , Object } would yield a set { Object }, and we would have lost track of the fact that T can safely be assumed to be a List .

In contrast, intersecting EST( List < String > ) = { List , Collection , Object } and EST( List < Object > ) = { List , Collection , Object } yields { List , Collection , Object }, which we will eventually enable us to infer T = List < ? > as described below.

The erased candidate set for type parameter T j , EC, is the intersection of all the sets EST( U ) for each U in U 1 ... U k .

The minimal erased candidate set for T j is:

MEC = { V | V in EC, and for all W ≠ V in EC, it is not the case that W <: V }

Because we are seeking to infer more precise types, we wish to filter out any candidates that are supertypes of other candidates. This is what computing MEC accomplishes.

In our running example, we had EC = { List , Collection , Object }, and now MEC = { List }.

The next step will be to recover type arguments for the inferred types themselves.

For any element G of MEC that is a generic type declaration, define the relevant invocations of G , Inv(G), to be:

Inv( G ) = { V | 1 ≤ i ≤ k : V in ST( U i ), V = G < ... > }

In our running example, the only generic element of MEC is List , and Inv( List ) = { List < String > , List < Object > }. We now will seek to find a type argument for List that contains ( §4.5.1 ) both String and Object .

This is done by means of the least containing invocation (lci) operation defined below. The first line defines lci() on a set, such as Inv( List ), as an operation on a list of the elements of the set. The next line defines the operation on such lists, as a pairwise reduction on the elements of the list. The third line is the definition of lci() on pairs of parameterized types, which in turn relies on the notion of least containing type argument (lcta).

lcta() is defined for all six possible cases. Then CandidateInvocation( G ) defines the most specific invocation of the generic type G that contains all the invocations of G that are known to be supertypes of T j . This will be our candidate invocation of G in the bound we infer for T j .

Define CandidateInvocation( G ) = lci(Inv( G )), where lci, the least containing invocation, is defined:

lci( S ) = lci( e 1 , ..., e n ) where e i (1 ≤ i ≤ n ) in S

lci( e 1 , ..., e n ) = lci(lci( e 1 , e 2 ), e 3 , ..., e n )

lci( G < X 1 , ..., X n > , G < Y 1 , ..., Y n > ) = G < lcta( X 1 , Y 1 ), ..., lcta( X n , Y n ) >

lci( G < X 1 , ..., X n > ) = G < lcta( X 1 ), ..., lcta( X n ) >

where lcta() is the least containing type argument function defined (assuming U and V are type expressions) as:

lcta( U , V ) = U if U = V , otherwise ? extends lub( U , V )

lcta( U , ? extends V ) = ? extends lub( U , V )

lcta( U , ? super V ) = ? super glb( U , V )

lcta( ? extends U , ? extends V ) = ? extends lub( U , V )

lcta( ? extends U , ? super V ) = U if U = V , otherwise ?

lcta( ? super U , ? super V ) = ? super glb( U , V )

lcta( U ) = ? if U 's upper bound is Object , otherwise ? extends lub( U , Object )

where glb() is as defined in §5.1.10 .

Finally, we define a bound for T j based on on all the elements of the minimal erased candidate set of its supertypes. If any of these elements are generic, we use the CandidateInvocation() function to recover the type argument information.

Define Candidate( W ) = CandidateInvocation( W ) if W is generic, W otherwise.

The inferred type for T j , lub( U 1 ... U k ), is Candidate( W 1 ) & ... & Candidate( W r ), where W i (1 ≤ i ≤ r ) are the elements of MEC.

It is possible that the process above yields an infinite type. This is permissible, and a Java compiler must recognize such situations and represent them appropriately using cyclic data structures.

The possibility of an infinite type stems from the recursive calls to lub(). Readers familiar with recursive types should note that an infinite type is not the same as a recursive type.

15.12.2.8. Inferring Unresolved Type Arguments

If any of the method's type arguments were not inferred from the types of the actual arguments, they are now inferred as follows.

If the method result occurs in a context where it will be subject to assignment conversion ( §5.2 ) to a type S , then let R be the declared result type of the method, and let R ' = R [ T 1 =B( T 1 ) ... T n =B( T n ) ] , where B( T i ) is the type inferred for T i in the previous section or T i if no type was inferred.

If S is a reference type, then let S ' be S . Otherwise, if S is a primitive type, then let S ' be the result of applying boxing conversion ( §5.1.7 ) to S .

Then, a set of initial constraints consisting of:

the constraint S ' >> R ', provided R is not void ; and

additional constraints B i [ T 1 =B( T 1 ) ... T n =B( T n ) ] >> T i , where B i is the declared bound of T i ,

additional constraints B( T i ) << B i [ T 1 =B( T 1 ) ... T n =B( T n )], where B i is the declared bound of T i ,

for any constraint of the form V >> T i generated in §15.12.2.7 : a constraint V [ T 1 =B( T 1 ) ... T n =B( T n )] >> T i .

for any constraint of the form T i = V generated in §15.12.2.7 : a constraint T i = V [ T 1 =B( T 1 ) ... T n =B( T n )].

is created and used to infer constraints on the type arguments using the algorithm of §15.12.2.7 .

Any equality constraints are resolved, and then, for each remaining constraint of the form T i <: U k , the argument T i is inferred to be glb( U 1 , ..., U k ) ( §5.1.10 ).

If T i appears as a type argument in any U k , then T i is inferred to be a type variable X whose upper bound is the parameterized type given by glb( U 1 [ T i = X ], ..., U k [ T i = X ]) and whose lower bound is the null type.

Any remaining type variable T that has not yet been inferred is then inferred to have type Object . If a previously inferred type variable P uses T , then P is inferred to be P [ T = Object ].

Otherwise, the unresolved type arguments are inferred by invoking the procedure described in this section under the assumption that the method result was assigned to a variable of type Object .

15.12.3. Compile-Time Step 3: Is the Chosen Method Appropriate?

If there is a most specific method declaration for a method invocation, it is called the compile-time declaration for the method invocation.

If the method invocation has, before the left parenthesis, a MethodName of the form Identifier , and the compile-time declaration is an instance method, then:

If the method invocation occurs in a static context ( §8.1.3 ), then a compile-time error occurs.

The reason is that a method invocation of this form cannot be used to invoke an instance method in places where this ( §15.8.3 ) is not defined.

Otherwise, let C be the innermost enclosing class of which the compile-time declaration is a member.

If the invocation is not directly enclosed by C or an inner class of C , then a compile-time error occurs.

If the method invocation has, before the left parenthesis, a MethodName of the form TypeName . Identifier , or if the method invocation, before the left parenthesis, has the form TypeName . NonWildTypeArguments Identifier , then the compile-time declaration must be static , or a compile-time error occurs.

The reason is that a method invocation of this form does not specify a reference to an object that can serve as this within the instance method.

If the method invocation has, before the left parenthesis, the form super . NonWildTypeArguments opt Identifier , then:

If the compile-time declaration is abstract , a compile-time error occurs.

If the method invocation occurs in a static context, a compile-time error occurs.

If the method invocation has, before the left parenthesis, the form ClassName . super . NonWildTypeArguments opt Identifier , then:

Otherwise, let C be the class denoted by ClassName .

If the compile-time declaration is void , then the method invocation must be a top level expression (that is, the Expression in an expression statement ( §14.8 ) or in the ForInit or ForUpdate part of a for statement ( §14.14 )), or a compile-time error occurs.

The reason is that such a method invocation produces no value and so must be used only in a situation where a value is not needed.

A method is signature polymorphic if and only if all of the following conditions hold:

It is declared in the java.lang.invoke.MethodHandle class.

It takes a single variable arity parameter ( §8.4.1 ) whose declared type is Object [] .

It has a return type of Object .

It is native .

In Java SE 7, the only signature polymorphic methods are the invoke and invokeExact methods of the class java.lang.invoke.MethodHandle .

If the compile-time declaration for the method invocation is not a signature polymorphic method, then the types of its parameters are the types of its formal parameters, and the result type is its chosen result type.

Otherwise, if the compile-time declaration for the method invocation is a signature polymorphic method, then:

The types of its parameters are the static types of the actual argument expressions.

An argument expression which is the null literal null ( §3.10.7 ) is treated as having the static type Void .

The result type is determined as follows:

If the method invocation expression is an expression statement, the method is void .

Otherwise, if the method invocation expression is the operand of a cast expression ( §15.16 ), the return type is the erasure ( §4.6 ) of the type of the cast expression.

Otherwise, the return type is the method's declared return type, Object .

The following compile-time information is then associated with the method invocation for use at run time:

The name of the method.

The qualifying type of the method invocation ( §13.1 ).

The number of parameters and the types of the parameters, in order.

The result type, or void .

The invocation mode, computed as follows:

If the compile-time declaration has the static modifier, then the invocation mode is static .

Otherwise, if the compile-time declaration has the private modifier, then the invocation mode is nonvirtual .

Otherwise, if the part of the method invocation before the left parenthesis is of the form super . Identifier or of the form ClassName . super . Identifier , then the invocation mode is super .

Otherwise, if the compile-time declaration is in an interface, then the invocation mode is interface .

Otherwise, the invocation mode is virtual .

If the compile-time declaration for the method invocation is not void , then the type of the method invocation expression is the result type specified in the compile-time declaration.

15.12.4. Run-Time Evaluation of Method Invocation

At run time, method invocation requires five steps. First, a target reference may be computed. Second, the argument expressions are evaluated. Third, the accessibility of the method to be invoked is checked. Fourth, the actual code for the method to be executed is located. Fifth, a new activation frame is created, synchronization is performed if necessary, and control is transferred to the method code.

15.12.4.1. Compute Target Reference (If Necessary)

There are several cases to consider, depending on which of the five productions for MethodInvocation ( §15.12 ) is involved:

If the first production for MethodInvocation, which includes a MethodName , is involved, then there are three subcases:

If the MethodName is a simple name, that is, just an Identifier , then there are two subcases:

If the invocation mode is static , then there is no target reference.

Otherwise, let T be the enclosing type declaration of which the method is a member, and let n be an integer such that T is the n 'th lexically enclosing type declaration ( §8.1.3 ) of the class whose declaration immediately contains the method invocation. Then the target reference is the n 'th lexically enclosing instance ( §8.1.3 ) of this .

It is a compile-time error if the n 'th lexically enclosing instance ( §8.1.3 ) of this does not exist.

If the MethodName is a qualified name of the form TypeName . Identifier , then there is no target reference.

If the MethodName is a qualified name of the form FieldName . Identifier , then there are two subcases:

If the invocation mode is static , then there is no target reference. The expression FieldName is evaluated, but the result is then discarded.

Otherwise, the target reference is the value of the expression FieldName .

If the second production for MethodInvocation , which includes a Primary , is involved, then there are two subcases:

If the invocation mode is static , then there is no target reference. The expression Primary is evaluated, but the result is then discarded.

Otherwise, the expression Primary is evaluated and the result is used as the target reference.

In either case, if the evaluation of the Primary expression completes abruptly, then no part of any argument expression appears to have been evaluated, and the method invocation completes abruptly for the same reason.

If the third production for MethodInvocation , which includes the keyword super , is involved, then the target reference is the value of this .

If the fourth production for MethodInvocation , ClassName . super , is involved, then the target reference is the value of ClassName . this .

If the fifth production for MethodInvocation , beginning with TypeName . NonWildTypeArguments , is involved, then there is no target reference.

Example 15.12.4.1-1. Target References and static Methods

When a target reference is computed and then discarded because the invocation mode is static , the reference is not examined to see whether it is null :

which prints:

Here favorite() returns null , yet no NullPointerException is thrown.

Example 15.12.4.1-2. Evaluation Order During Method Invocation

As part of an instance method invocation ( §15.12 ), there is an expression that denotes the object to be invoked. This expression appears to be fully evaluated before any part of any argument expression to the method invocation is evaluated.

So, for example, in:

the occurrence of s before " .startsWith " is evaluated first, before the argument expression s = "two" . Therefore, a reference to the string "one" is remembered as the target reference before the local variable s is changed to refer to the string "two" . As a result, the startsWith method is invoked for target object "one" with argument "two" , so the result of the invocation is false , as the string "one" does not start with "two" . It follows that the test program does not print " oops ".

15.12.4.2. Evaluate Arguments

The process of evaluating the argument list differs, depending on whether the method being invoked is a fixed arity method or a variable arity method ( §8.4.1 ).

If the method being invoked is a variable arity method m , it necessarily has n > 0 formal parameters. The final formal parameter of m necessarily has type T [] for some T , and m is necessarily being invoked with k ≥ 0 actual argument expressions.

If m is being invoked with k ≠ n actual argument expressions, or, if m is being invoked with k = n actual argument expressions and the type of the k 'th argument expression is not assignment compatible with T [] , then the argument list ( e 1 , ..., e n-1 , e n , ..., e k ) is evaluated as if it were written as ( e 1 , ..., e n-1 , new | T [] | { e n , ..., e k } ), where | T [] | denotes the erasure ( §4.6 ) of T [] .

The preceding paragraphs are crafted to handle the interaction of parameterized types and array types that occurs in a Java Virtual Machine with erased generics. Namely, if the element type T of the variable array parameter is non-reifiable, e.g. List < String > , then special care must be taken with the array creation expression ( §15.10 ) because the created array's element type must be reifiable. By erasing the array type of the final expression in the argument list, we are guaranteed to obtain a reifiable element type. Then, since the array creation expression appears in a method invocation context, an unchecked conversion ( §5.1.9 ) is possible from the array type with reifiable element type to an array type with non-reifiable element type, specifically that of the variable arity parameter. A Java compiler is required by §5.1.9 to give a compile-time unchecked warning at this conversion. Oracle's reference implementation of a Java compiler identifies the unchecked warning here as a more informative unchecked generic array creation .

The argument expressions (possibly rewritten as described above) are now evaluated to yield argument values . Each argument value corresponds to exactly one of the method's n formal parameters.

The argument expressions, if any, are evaluated in order, from left to right. If the evaluation of any argument expression completes abruptly, then no part of any argument expression to its right appears to have been evaluated, and the method invocation completes abruptly for the same reason. The result of evaluating the j 'th argument expression is the j 'th argument value, for 1 ≤ j ≤ n . Evaluation then continues, using the argument values, as described below.

15.12.4.3. Check Accessibility of Type and Method

Let C be the class containing the method invocation, and let T be the qualifying type of the method invocation ( §13.1 ), and let m be the name of the method as determined at compile time ( §15.12.3 ).

An implementation of the Java programming language must ensure, as part of linkage, that the method m still exists in the type T . If this is not true, then a NoSuchMethodError (which is a subclass of IncompatibleClassChangeError ) occurs.

If the invocation mode is interface , then the implementation must also check that the target reference type still implements the specified interface. If the target reference type does not still implement the interface, then an IncompatibleClassChangeError occurs.

The implementation must also ensure, during linkage, that the type T and the method m are accessible:

For the type T :

If T is in the same package as C , then T is accessible.

If T is in a different package than C , and T is public , then T is accessible.

If T is in a different package than C , and T is protected , then T is accessible if and only if C is a subclass of T .

For the method m :

If m is public , then m is accessible. (All members of interfaces are public ( §9.2 ).)

If m is protected , then m is accessible if and only if either T is in the same package as C , or C is T or a subclass of T .

If m has default (package) access, then m is accessible if and only if T is in the same package as C .

If m is private , then m is accessible if and only if C is T , or C encloses T , or T encloses C , or T and C are both enclosed by a third class.

If either T or m is not accessible, then an IllegalAccessError occurs ( §12.3 ).

15.12.4.4. Locate Method to Invoke

The strategy for method lookup depends on the invocation mode.

If the invocation mode is static , no target reference is needed and overriding is not allowed. Method m of class T is the one to be invoked.

Otherwise, an instance method is to be invoked and there is a target reference. If the target reference is null , a NullPointerException is thrown at this point. Otherwise, the target reference is said to refer to a target object and will be used as the value of the keyword this in the invoked method. The other four possibilities for the invocation mode are then considered.

If the invocation mode is nonvirtual , overriding is not allowed. Method m of class T is the one to be invoked.

Otherwise, if the invocation mode is virtual , and T and m jointly indicate a signature polymorphic method ( §15.12.3 ), then the target object is an instance of java.lang.invoke.MethodHandle . The method handle encapsulates a type which is matched against the information associated with the method invocation at compile time ( §15.12.3 ). Details of this matching are given in The Java Virtual Machine Specification, Java SE 7 Edition and the Java SE platform API. If matching succeeds, the target method encapsulated by the method handle is directly and immediately invoked, and the procedure in §15.12.4.5 is not executed .

Otherwise, the invocation mode is interface , virtual , or super , and overriding may occur. A dynamic method lookup is used. The dynamic lookup process starts from a class S , determined as follows:

If the invocation mode is interface or virtual , then S is initially the actual run-time class R of the target object.

This is true even if the target object is an array instance. (Note that for invocation mode interface , R necessarily implements T ; for invocation mode virtual , R is necessarily either T or a subclass of T .)

If the invocation mode is super , then S is initially the qualifying type ( §13.1 ) of the method invocation.

The dynamic method lookup uses the following procedure to search class S , and then the superclasses of class S , as necessary, for method m .

Let X be the compile-time type of the target reference of the method invocation. Then:

If class S contains a declaration for a non- abstract method named m with the same descriptor (same number of parameters, the same parameter types, and the same return type) required by the method invocation as determined at compile time ( §15.12.3 ), then:

If the invocation mode is super or interface , then this is the method to be invoked, and the procedure terminates.

If the invocation mode is virtual , and the declaration in S overrides ( §8.4.8.1 ) X . m , then the method declared in S is the method to be invoked, and the procedure terminates.

If the invocation mode is virtual , and the declaration in S does not override X . m , and moreover X . m is declared abstract , then an AbstractMethodError is thrown.

Otherwise, if S has a superclass, this same lookup procedure is performed recursively using the direct superclass of S in place of S ; the method to be invoked is the result of the recursive invocation of this lookup procedure.

The above procedure (if it terminates without error) will find a non- abstract , accessible method to invoke, provided that all classes and interfaces in the program have been consistently compiled. However, if this is not the case, then various errors may occur. The specification of the behavior of a Java Virtual Machine under these circumstances is given by The Java Virtual Machine Specification, Java SE 7 Edition .

We note that the dynamic lookup process, while described here explicitly, will often be implemented implicitly, for example as a side-effect of the construction and use of per-class method dispatch tables, or the construction of other per-class structures used for efficient dispatch.

Example 15.12.4.4-1. Overriding and Method Invocation

Here, the subclass ColoredPoint extends the clear abstraction defined by its superclass Point . It does so by overriding the clear method with its own method, which invokes the clear method of its superclass, using the form super.clear() .

This method is then invoked whenever the target object for an invocation of clear is a ColoredPoint . Even the method move in Point invokes the clear method of class ColoredPoint when the class of this is ColoredPoint , as shown by the output of this test program:

Overriding is sometimes called "late-bound self-reference"; in this example it means that the reference to clear in the body of Point.move (which is really syntactic shorthand for this.clear ) invokes a method chosen "late" (at run time, based on the run-time class of the object referenced by this ) rather than a method chosen "early" (at compile time, based only on the type of this ). This provides the programmer a powerful way of extending abstractions and is a key idea in object-oriented programming.

Example 15.12.4.4-2. Method Invocation Using super

An overridden instance method of a superclass may be accessed by using the keyword super to access the members of the immediate superclass, bypassing any overriding declaration in the class that contains the method invocation.

When accessing an instance variable, super means the same as a cast of this ( §15.11.2 ), but this equivalence does not hold true for method invocation. This is demonstrated by the example:

which produces the output:

The casts to types T1 and T2 do not change the method that is invoked, because the instance method to be invoked is chosen according to the run-time class of the object referred to by this . A cast does not change the class of an object; it only checks that the class is compatible with the specified type.

15.12.4.5. Create Frame, Synchronize, Transfer Control

A method m in some class S has been identified as the one to be invoked.

Now a new activation frame is created, containing the target reference (if any) and the argument values (if any), as well as enough space for the local variables and stack for the method to be invoked and any other bookkeeping information that may be required by the implementation (stack pointer, program counter, reference to previous activation frame, and the like). If there is not sufficient memory available to create such an activation frame, a StackOverflowError is thrown.

The newly created activation frame becomes the current activation frame. The effect of this is to assign the argument values to corresponding freshly created parameter variables of the method, and to make the target reference available as this , if there is a target reference. Before each argument value is assigned to its corresponding parameter variable, it is subjected to method invocation conversion ( §5.3 ), which includes any required value set conversion ( §5.1.13 ).

If the erasure ( §4.6 ) of the type of the method being invoked differs in its signature from the erasure of the type of the compile-time declaration for the method invocation ( §15.12.3 ), then if any of the argument values is an object which is not an instance of a subclass or subinterface of the erasure of the corresponding formal parameter type in the compile-time declaration for the method invocation, then a ClassCastException is thrown.

If the method m is a native method but the necessary native, implementation-dependent binary code has not been loaded or otherwise cannot be dynamically linked, then an UnsatisfiedLinkError is thrown.

If the method m is not synchronized , control is transferred to the body of the method m to be invoked.

If the method m is synchronized , then an object must be locked before the transfer of control. No further progress can be made until the current thread can obtain the lock. If there is a target reference, then the target object must be locked; otherwise the Class object for class S , the class of the method m , must be locked. Control is then transferred to the body of the method m to be invoked. The object is automatically unlocked when execution of the body of the method has completed, whether normally or abruptly. The locking and unlocking behavior is exactly as if the body of the method were embedded in a synchronized statement ( §14.19 ).

Example 15.12.4.5-1. Invoked Method Signature Has Different Erasure Than Compile-Time Method Signature

Consider the declarations:

Now, given an invocation:

The erasure of the actual method being invoked, D.id() , differs in its signature from that of the compile-time method declaration, C.id() . The former takes an argument of type String while the latter takes an argument of type Object . The invocation fails with a ClassCastException before the body of the method is executed.

Such situations can only arise if the program gives rise to a compile-time unchecked warning ( §4.8 , §5.1.9 , §5.5.2 , §8.4.1 , §8.4.8.3 , §8.4.8.4 , §9.4.1.2 , §15.12.4.2 ).

Implementations can enforce these semantics by creating bridge methods . In the above example, the following bridge method would be created in class D :

This is the method that would actually be invoked by the Java Virtual Machine in response to the call c.id(new Object()) shown above, and it will execute the cast and fail, as required.

15.13. Array Access Expressions

An array access expression refers to a variable that is a component of an array.

ArrayAccess:     ExpressionName  [  Expression  ]     PrimaryNoNewArray  [  Expression  ]

An array access expression contains two subexpressions, the array reference expression (before the left bracket) and the index expression (within the brackets).

Note that the array reference expression may be a name or any primary expression that is not an array creation expression ( §15.10 ).

The type of the array reference expression must be an array type (call it T [] , an array whose components are of type T ), or a compile-time error occurs.

The index expression undergoes unary numeric promotion ( §5.6.1 ). The promoted type must be int , or a compile-time error occurs.

The type of the array access expression is the result of applying capture conversion ( §5.1.10 ) to T .

The result of an array access expression is a variable of type T , namely the variable within the array selected by the value of the index expression.

This resulting variable, which is a component of the array, is never considered final , even if the array reference expression denoted a final variable.

15.13.1. Run-Time Evaluation of Array Access

An array access expression is evaluated using the following procedure:

First, the array reference expression is evaluated. If this evaluation completes abruptly, then the array access completes abruptly for the same reason and the index expression is not evaluated.

Otherwise, the index expression is evaluated. If this evaluation completes abruptly, then the array access completes abruptly for the same reason.

Otherwise, if the value of the array reference expression is null , then a NullPointerException is thrown.

Otherwise, the value of the array reference expression indeed refers to an array. If the value of the index expression is less than zero, or greater than or equal to the array's length , then an ArrayIndexOutOfBoundsException is thrown.

Otherwise, the result of the array access is the variable of type T , within the array, selected by the value of the index expression.

Example 15.13-1. Array Reference Is Evaluated First

In an array access, the expression to the left of the brackets appears to be fully evaluated before any part of the expression within the brackets is evaluated. For example, in the (admittedly monstrous) expression a[(a=b)[3]] , the expression a is fully evaluated before the expression (a=b)[3] ; this means that the original value of a is fetched and remembered while the expression (a=b)[3] is evaluated. This array referenced by the original value of a is then subscripted by a value that is element 3 of another array (possibly the same array) that was referenced by b and is now also referenced by a .

Thus, the program:

because the monstrous expression's value is equivalent to a[b[3]] or a[3] or 14 .

Example 15.13-2. Abrupt Completion of Array Reference Evaluation

If evaluation of the expression to the left of the brackets completes abruptly, no part of the expression within the brackets will appear to have been evaluated. Thus, the program:

because the embedded assignment of 2 to index never occurs.

Example 15.13-3.  null Array Reference

If the array reference expression produces null instead of a reference to an array, then a NullPointerException is thrown at run time, but only after all parts of the array access expression have been evaluated and only if these evaluations completed normally. Thus, the program:

because the embedded assignment of 2 to index occurs before the check for a null array reference expression. As a related example, the program:

always prints:

A NullPointerException never occurs, because the index expression must be completely evaluated before any part of the array access occurs, and that includes the check as to whether the value of the array reference expression is null .

15.14. Postfix Expressions

Postfix expressions include uses of the postfix ++ and -- operators. Names are not considered to be primary expressions ( §15.8 ), but are handled separately in the grammar to avoid certain ambiguities. They become interchangeable only here, at the level of precedence of postfix expressions.

PostfixExpression:     Primary     ExpressionName     PostIncrementExpression     PostDecrementExpression

15.14.1. Expression Names

The rules for evaluating expression names are given in §6.5.6 .

15.14.2. Postfix Increment Operator ++

A postfix expression followed by a ++ operator is a postfix increment expression.

PostIncrementExpression:     PostfixExpression  ++

The result of the postfix expression must be a variable of a type that is convertible ( §5.1.8 ) to a numeric type, or a compile-time error occurs.

The type of the postfix increment expression is the type of the variable. The result of the postfix increment expression is not a variable, but a value.

At run time, if evaluation of the operand expression completes abruptly, then the postfix increment expression completes abruptly for the same reason and no incrementation occurs. Otherwise, the value 1 is added to the value of the variable and the sum is stored back into the variable. Before the addition, binary numeric promotion ( §5.6.2 ) is performed on the value 1 and the value of the variable. If necessary, the sum is narrowed by a narrowing primitive conversion ( §5.1.3 ) and/or subjected to boxing conversion ( §5.1.7 ) to the type of the variable before it is stored. The value of the postfix increment expression is the value of the variable before the new value is stored.

Note that the binary numeric promotion mentioned above may include unboxing conversion ( §5.1.8 ) and value set conversion ( §5.1.13 ). If necessary, value set conversion is applied to the sum prior to its being stored in the variable.

A variable that is declared final cannot be incremented because when an access of such a final variable is used as an expression, the result is a value, not a variable. Thus, it cannot be used as the operand of a postfix increment operator.

15.14.3. Postfix Decrement Operator --

A postfix expression followed by a -- operator is a postfix decrement expression.

PostDecrementExpression:     PostfixExpression  --

The type of the postfix decrement expression is the type of the variable. The result of the postfix decrement expression is not a variable, but a value.

At run time, if evaluation of the operand expression completes abruptly, then the postfix decrement expression completes abruptly for the same reason and no decrementation occurs. Otherwise, the value 1 is subtracted from the value of the variable and the difference is stored back into the variable. Before the subtraction, binary numeric promotion ( §5.6.2 ) is performed on the value 1 and the value of the variable. If necessary, the difference is narrowed by a narrowing primitive conversion ( §5.1.3 ) and/or subjected to boxing conversion ( §5.1.7 ) to the type of the variable before it is stored. The value of the postfix decrement expression is the value of the variable before the new value is stored.

Note that the binary numeric promotion mentioned above may include unboxing conversion ( §5.1.8 ) and value set conversion ( §5.1.13 ). If necessary, value set conversion is applied to the difference prior to its being stored in the variable.

A variable that is declared final cannot be decremented because when an access of such a final variable is used as an expression, the result is a value, not a variable. Thus, it cannot be used as the operand of a postfix decrement operator.

15.15. Unary Operators

The operators + , - , ++ , -- , ~ , ! , and the cast operator ( §15.16 ) are called the unary operators .

UnaryExpression:     PreIncrementExpression     PreDecrementExpression      +  UnaryExpression      -  UnaryExpression     UnaryExpressionNotPlusMinus PreIncrementExpression:      ++  UnaryExpression PreDecrementExpression:      --  UnaryExpression UnaryExpressionNotPlusMinus:     PostfixExpression      ~  UnaryExpression      !  UnaryExpression     CastExpression

Expressions with unary operators group right-to-left, so that -~x means the same as -(~x) .

15.15.1. Prefix Increment Operator ++

A unary expression preceded by a ++ operator is a prefix increment expression.

The result of the unary expression must be a variable of a type that is convertible ( §5.1.8 ) to a numeric type, or a compile-time error occurs.

The type of the prefix increment expression is the type of the variable. The result of the prefix increment expression is not a variable, but a value.

At run time, if evaluation of the operand expression completes abruptly, then the prefix increment expression completes abruptly for the same reason and no incrementation occurs. Otherwise, the value 1 is added to the value of the variable and the sum is stored back into the variable. Before the addition, binary numeric promotion ( §5.6.2 ) is performed on the value 1 and the value of the variable. If necessary, the sum is narrowed by a narrowing primitive conversion ( §5.1.3 ) and/or subjected to boxing conversion ( §5.1.7 ) to the type of the variable before it is stored. The value of the prefix increment expression is the value of the variable after the new value is stored.

A variable that is declared final cannot be incremented because when an access of such a final variable is used as an expression, the result is a value, not a variable. Thus, it cannot be used as the operand of a prefix increment operator.

15.15.2. Prefix Decrement Operator --

A unary expression preceded by a -- operator is a prefix decrement expression.

The type of the prefix decrement expression is the type of the variable. The result of the prefix decrement expression is not a variable, but a value.

At run time, if evaluation of the operand expression completes abruptly, then the prefix decrement expression completes abruptly for the same reason and no decrementation occurs. Otherwise, the value 1 is subtracted from the value of the variable and the difference is stored back into the variable. Before the subtraction, binary numeric promotion ( §5.6.2 ) is performed on the value 1 and the value of the variable. If necessary, the difference is narrowed by a narrowing primitive conversion ( §5.1.3 ) and/or subjected to boxing conversion ( §5.1.7 ) to the type of the variable before it is stored. The value of the prefix decrement expression is the value of the variable after the new value is stored.

Note that the binary numeric promotion mentioned above may include unboxing conversion ( §5.1.8 ) and value set conversion ( §5.1.13 ). If necessary, format conversion is applied to the difference prior to its being stored in the variable.

A variable that is declared final cannot be decremented because when an access of such a final variable is used as an expression, the result is a value, not a variable. Thus, it cannot be used as the operand of a prefix decrement operator.

15.15.3. Unary Plus Operator +

The type of the operand expression of the unary + operator must be a type that is convertible ( §5.1.8 ) to a primitive numeric type, or a compile-time error occurs.

Unary numeric promotion ( §5.6.1 ) is performed on the operand. The type of the unary plus expression is the promoted type of the operand. The result of the unary plus expression is not a variable, but a value, even if the result of the operand expression is a variable.

At run time, the value of the unary plus expression is the promoted value of the operand.

15.15.4. Unary Minus Operator -

The type of the operand expression of the unary - operator must be a type that is convertible ( §5.1.8 ) to a primitive numeric type, or a compile-time error occurs.

Unary numeric promotion ( §5.6.1 ) is performed on the operand.

The type of the unary minus expression is the promoted type of the operand.

Note that unary numeric promotion performs value set conversion ( §5.1.13 ). Whatever value set the promoted operand value is drawn from, the unary negation operation is carried out and the result is drawn from that same value set. That result is then subject to further value set conversion.

At run time, the value of the unary minus expression is the arithmetic negation of the promoted value of the operand.

For integer values, negation is the same as subtraction from zero. The Java programming language uses two's-complement representation for integers, and the range of two's-complement values is not symmetric, so negation of the maximum negative int or long results in that same maximum negative number. Overflow occurs in this case, but no exception is thrown. For all integer values x , -x equals (~x)+1 .

For floating-point values, negation is not the same as subtraction from zero, because if x is +0.0 , then 0.0-x is +0.0 , but -x is -0.0 . Unary minus merely inverts the sign of a floating-point number. Special cases of interest:

If the operand is NaN, the result is NaN. (Recall that NaN has no sign ( §4.2.3 ).)

If the operand is an infinity, the result is the infinity of opposite sign.

If the operand is a zero, the result is the zero of opposite sign.

15.15.5. Bitwise Complement Operator ~

The type of the operand expression of the unary ~ operator must be a type that is convertible ( §5.1.8 ) to a primitive integral type, or a compile-time error occurs.

Unary numeric promotion ( §5.6.1 ) is performed on the operand. The type of the unary bitwise complement expression is the promoted type of the operand.

At run time, the value of the unary bitwise complement expression is the bitwise complement of the promoted value of the operand. In all cases, ~x equals (-x)-1 .

15.15.6. Logical Complement Operator !

The type of the operand expression of the unary ! operator must be boolean or Boolean , or a compile-time error occurs.

The type of the unary logical complement expression is boolean .

At run time, the operand is subject to unboxing conversion ( §5.1.8 ) if necessary. The value of the unary logical complement expression is true if the (possibly converted) operand value is false , and false if the (possibly converted) operand value is true .

15.16. Cast Expressions

A cast expression converts, at run time, a value of one numeric type to a similar value of another numeric type; or confirms, at compile time, that the type of an expression is boolean ; or checks, at run time, that a reference value refers to an object whose class is compatible with a specified reference type.

The parentheses and the type they contain are sometimes called the cast operator .

CastExpression:      (  PrimitiveType  )  UnaryExpression      (  ReferenceType  )  UnaryExpressionNotPlusMinus

See §15.15 for a discussion of the distinction between UnaryExpression and UnaryExpressionNotPlusMinus .

The type of a cast expression is the result of applying capture conversion ( §5.1.10 ) to the type whose name appears within the parentheses.

The result of a cast expression is not a variable, but a value, even if the result of the operand expression is a variable.

A cast operator has no effect on the choice of value set ( §4.2.3 ) for a value of type float or type double . Consequently, a cast to type float within an expression that is not FP-strict ( §15.4 ) does not necessarily cause its value to be converted to an element of the float value set, and a cast to type double within an expression that is not FP-strict does not necessarily cause its value to be converted to an element of the double value set.

It is a compile-time error if the compile-time type of the operand may never be cast to the type specified by the cast operator according to the rules of casting conversion ( §5.5 ).

Some casts result in an error at compile time. Some casts can be proven, at compile time, always to be correct at run time. For example, it is always correct to convert a value of a class type to the type of its superclass; such a cast should require no special action at run time. Finally, some casts cannot be proven to be either always correct or always incorrect at compile time. Such casts require a test at run time. See §5.5 for details.

Otherwise, at run time, the operand value is converted (if necessary) by casting conversion to the type specified by the cast operator.

A ClassCastException is thrown if a cast is found at run time to be impermissible.

15.17. Multiplicative Operators

The operators * , / , and % are called the multiplicative operators .

MultiplicativeExpression:     UnaryExpression     MultiplicativeExpression  *  UnaryExpression     MultiplicativeExpression  /  UnaryExpression     MultiplicativeExpression  %  UnaryExpression

The multiplicative operators have the same precedence and are syntactically left-associative (they group left-to-right).

The type of each of the operands of a multiplicative operator must be a type that is convertible ( §5.1.8 ) to a primitive numeric type, or a compile-time error occurs.

Binary numeric promotion is performed on the operands ( §5.6.2 ).

Note that binary numeric promotion performs value set conversion ( §5.1.13 ) and may perform unboxing conversion ( §5.1.8 ).

The type of a multiplicative expression is the promoted type of its operands.

If the promoted type is int or long , then integer arithmetic is performed.

If the promoted type is float or double , then floating-point arithmetic is performed.

15.17.1. Multiplication Operator *

The binary * operator performs multiplication, producing the product of its operands.

Multiplication is a commutative operation if the operand expressions have no side effects.

Integer multiplication is associative when the operands are all of the same type.

Floating-point multiplication is not associative.

If an integer multiplication overflows, then the result is the low-order bits of the mathematical product as represented in some sufficiently large two's-complement format. As a result, if overflow occurs, then the sign of the result may not be the same as the sign of the mathematical product of the two operand values.

The result of a floating-point multiplication is determined by the rules of IEEE 754 arithmetic:

If either operand is NaN, the result is NaN.

If the result is not NaN, the sign of the result is positive if both operands have the same sign, and negative if the operands have different signs.

Multiplication of an infinity by a zero results in NaN.

Multiplication of an infinity by a finite value results in a signed infinity. The sign is determined by the rule stated above.

In the remaining cases, where neither an infinity nor NaN is involved, the exact mathematical product is computed. A floating-point value set is then chosen:

If the multiplication expression is FP-strict ( §15.4 ):

If the type of the multiplication expression is float , then the float value set must be chosen.

If the type of the multiplication expression is double , then the double value set must be chosen.

If the multiplication expression is not FP-strict:

If the type of the multiplication expression is float , then either the float value set or the float-extended-exponent value set may be chosen, at the whim of the implementation.

If the type of the multiplication expression is double , then either the double value set or the double-extended-exponent value set may be chosen, at the whim of the implementation.

Next, a value must be chosen from the chosen value set to represent the product.

If the magnitude of the product is too large to represent, we say the operation overflows; the result is then an infinity of appropriate sign.

Otherwise, the product is rounded to the nearest value in the chosen value set using IEEE 754 round-to-nearest mode. The Java programming language requires support of gradual underflow as defined by IEEE 754 ( §4.2.4 ).

Despite the fact that overflow, underflow, or loss of information may occur, evaluation of a multiplication operator * never throws a run-time exception.

15.17.2. Division Operator /

The binary / operator performs division, producing the quotient of its operands. The left-hand operand is the dividend and the right-hand operand is the divisor .

Integer division rounds toward 0 . That is, the quotient produced for operands n and d that are integers after binary numeric promotion ( §5.6.2 ) is an integer value q whose magnitude is as large as possible while satisfying | d · q | ≤ | n |. Moreover, q is positive when | n | ≥ | d | and n and d have the same sign, but q is negative when | n | ≥ | d | and n and d have opposite signs.

There is one special case that does not satisfy this rule: if the dividend is the negative integer of largest possible magnitude for its type, and the divisor is -1 , then integer overflow occurs and the result is equal to the dividend. Despite the overflow, no exception is thrown in this case. On the other hand, if the value of the divisor in an integer division is 0 , then an ArithmeticException is thrown.

The result of a floating-point division is determined by the rules of IEEE 754 arithmetic:

Division of an infinity by an infinity results in NaN.

Division of an infinity by a finite value results in a signed infinity. The sign is determined by the rule stated above.

Division of a finite value by an infinity results in a signed zero. The sign is determined by the rule stated above.

Division of a zero by a zero results in NaN; division of zero by any other finite value results in a signed zero. The sign is determined by the rule stated above.

Division of a nonzero finite value by a zero results in a signed infinity. The sign is determined by the rule stated above.

In the remaining cases, where neither an infinity nor NaN is involved, the exact mathematical quotient is computed. A floating-point value set is then chosen:

If the division expression is FP-strict ( §15.4 ):

If the type of the division expression is float , then the float value set must be chosen.

If the type of the division expression is double , then the double value set must be chosen.

If the division expression is not FP-strict:

If the type of the division expression is float , then either the float value set or the float-extended-exponent value set may be chosen, at the whim of the implementation.

If the type of the division expression is double , then either the double value set or the double-extended-exponent value set may be chosen, at the whim of the implementation.

Next, a value must be chosen from the chosen value set to represent the quotient.

If the magnitude of the quotient is too large to represent, we say the operation overflows; the result is then an infinity of appropriate sign.

Otherwise, the quotient is rounded to the nearest value in the chosen value set using IEEE 754 round-to-nearest mode. The Java programming language requires support of gradual underflow as defined by IEEE 754 ( §4.2.4 ).

Despite the fact that overflow, underflow, division by zero, or loss of information may occur, evaluation of a floating-point division operator / never throws a run-time exception.

15.17.3. Remainder Operator %

The binary % operator is said to yield the remainder of its operands from an implied division; the left-hand operand is the dividend and the right-hand operand is the divisor .

In C and C++, the remainder operator accepts only integral operands, but in the Java programming language, it also accepts floating-point operands.

The remainder operation for operands that are integers after binary numeric promotion ( §5.6.2 ) produces a result value such that (a/b)*b+(a%b) is equal to a .

This identity holds even in the special case that the dividend is the negative integer of largest possible magnitude for its type and the divisor is -1 (the remainder is 0 ).

It follows from this rule that the result of the remainder operation can be negative only if the dividend is negative, and can be positive only if the dividend is positive. Moreover, the magnitude of the result is always less than the magnitude of the divisor.

If the value of the divisor for an integer remainder operator is 0 , then an ArithmeticException is thrown.

Example 15.17.3-1. Integer Remainder Operator

The result of a floating-point remainder operation as computed by the % operator is not the same as that produced by the remainder operation defined by IEEE 754. The IEEE 754 remainder operation computes the remainder from a rounding division, not a truncating division, and so its behavior is not analogous to that of the usual integer remainder operator. Instead, the Java programming language defines % on floating-point operations to behave in a manner analogous to that of the integer remainder operator; this may be compared with the C library function fmod . The IEEE 754 remainder operation may be computed by the library routine Math.IEEEremainder .

The result of a floating-point remainder operation is determined by the rules of IEEE 754 arithmetic:

If the result is not NaN, the sign of the result equals the sign of the dividend.

If the dividend is an infinity, or the divisor is a zero, or both, the result is NaN.

If the dividend is finite and the divisor is an infinity, the result equals the dividend.

If the dividend is a zero and the divisor is finite, the result equals the dividend.

In the remaining cases, where neither an infinity, nor a zero, nor NaN is involved, the floating-point remainder r from the division of a dividend n by a divisor d is defined by the mathematical relation r = n - ( d · q ) where q is an integer that is negative only if n / d is negative and positive only if n / d is positive, and whose magnitude is as large as possible without exceeding the magnitude of the true mathematical quotient of n and d .

Evaluation of a floating-point remainder operator % never throws a run-time exception, even if the right-hand operand is zero. Overflow, underflow, or loss of precision cannot occur.

Example 15.17.3-2. Floating-Point Remainder Operator

15.18. Additive Operators

The operators + and - are called the additive operators .

AdditiveExpression:     MultiplicativeExpression     AdditiveExpression  +  MultiplicativeExpression     AdditiveExpression  -  MultiplicativeExpression

The additive operators have the same precedence and are syntactically left-associative (they group left-to-right).

If the type of either operand of a + operator is String , then the operation is string concatenation.

Otherwise, the type of each of the operands of the + operator must be a type that is convertible ( §5.1.8 ) to a primitive numeric type, or a compile-time error occurs.

In every case, the type of each of the operands of the binary - operator must be a type that is convertible ( §5.1.8 ) to a primitive numeric type, or a compile-time error occurs.

15.18.1. String Concatenation Operator +

If only one operand expression is of type String , then string conversion ( §5.1.11 ) is performed on the other operand to produce a string at run time.

The result of string concatenation is a reference to a String object that is the concatenation of the two operand strings. The characters of the left-hand operand precede the characters of the right-hand operand in the newly created string.

The String object is newly created ( §12.5 ) unless the expression is a compile-time constant expression ( §15.28 ).

An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.

For primitive types, an implementation may also optimize away the creation of a wrapper object by converting directly from a primitive type to a string.

Example 15.18.1-1. String Concatenation

The example expression:

produces the result:

The + operator is syntactically left-associative, no matter whether it is determined by type analysis to represent string concatenation or numeric addition. In some cases care is required to get the desired result. For example, the expression:

is always regarded as meaning:

Therefore the result of the expression:

but the result of:

Example 15.18.1-2. String Concatenation and Conditionals

In this jocular little example:

the method printSong will print a version of a children's song. Popular values for stuff include " pop " and " beer "; the most popular value for n is 100 . Here is the output that results from running the program:

In the code, note the careful conditional generation of the singular " bottle " when appropriate rather than the plural " bottles "; note also how the string concatenation operator was used to break the long constant string:

into two pieces to avoid an inconveniently long line in the source code.

15.18.2. Additive Operators ( + and - ) for Numeric Types

The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.

The binary - operator performs subtraction, producing the difference of two numeric operands.

The type of an additive expression on numeric operands is the promoted type of its operands.

If this promoted type is int or long , then integer arithmetic is performed.

If this promoted type is float or double , then floating-point arithmetic is performed.

Addition is a commutative operation if the operand expressions have no side effects.

Integer addition is associative when the operands are all of the same type.

Floating-point addition is not associative.

If an integer addition overflows, then the result is the low-order bits of the mathematical sum as represented in some sufficiently large two's-complement format. If overflow occurs, then the sign of the result is not the same as the sign of the mathematical sum of the two operand values.

The result of a floating-point addition is determined using the following rules of IEEE 754 arithmetic:

The sum of two infinities of opposite sign is NaN.

The sum of two infinities of the same sign is the infinity of that sign.

The sum of an infinity and a finite value is equal to the infinite operand.

The sum of two zeros of opposite sign is positive zero.

The sum of two zeros of the same sign is the zero of that sign.

The sum of a zero and a nonzero finite value is equal to the nonzero operand.

The sum of two nonzero finite values of the same magnitude and opposite sign is positive zero.

In the remaining cases, where neither an infinity, nor a zero, nor NaN is involved, and the operands have the same sign or have different magnitudes, the exact mathematical sum is computed. A floating-point value set is then chosen:

If the addition expression is FP-strict ( §15.4 ):

If the type of the addition expression is float , then the float value set must be chosen.

If the type of the addition expression is double , then the double value set must be chosen.

If the addition expression is not FP-strict:

If the type of the addition expression is float , then either the float value set or the float-extended-exponent value set may be chosen, at the whim of the implementation.

If the type of the addition expression is double , then either the double value set or the double-extended-exponent value set may be chosen, at the whim of the implementation.

Next, a value must be chosen from the chosen value set to represent the sum.

If the magnitude of the sum is too large to represent, we say the operation overflows; the result is then an infinity of appropriate sign.

Otherwise, the sum is rounded to the nearest value in the chosen value set using IEEE 754 round-to-nearest mode. The Java programming language requires support of gradual underflow as defined by IEEE 754 ( §4.2.4 ).

The binary - operator performs subtraction when applied to two operands of numeric type, producing the difference of its operands; the left-hand operand is the minuend and the right-hand operand is the subtrahend .

For both integer and floating-point subtraction, it is always the case that a-b produces the same result as a+(-b) .

Note that, for integer values, subtraction from zero is the same as negation. However, for floating-point operands, subtraction from zero is not the same as negation, because if x is +0.0 , then 0.0-x is +0.0 , but -x is -0.0 .

Despite the fact that overflow, underflow, or loss of information may occur, evaluation of a numeric additive operator never throws a run-time exception.

15.19. Shift Operators

The operators << (left shift), >> (signed right shift), and >>> (unsigned right shift) are called the shift operators . The left-hand operand of a shift operator is the value to be shifted; the right-hand operand specifies the shift distance.

ShiftExpression:     AdditiveExpression     ShiftExpression  <<  AdditiveExpression     ShiftExpression  >>  AdditiveExpression     ShiftExpression  >>>  AdditiveExpression

The shift operators are syntactically left-associative (they group left-to-right).

Unary numeric promotion ( §5.6.1 ) is performed on each operand separately. (Binary numeric promotion ( §5.6.2 ) is not performed on the operands.)

It is a compile-time error if the type of each of the operands of a shift operator, after unary numeric promotion, is not a primitive integral type.

The type of the shift expression is the promoted type of the left-hand operand.

If the promoted type of the left-hand operand is int , only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & ( §15.22.1 ) with the mask value 0x1f ( 0b11111 ). The shift distance actually used is therefore always in the range 0 to 31 , inclusive.

If the promoted type of the left-hand operand is long , then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & ( §15.22.1 ) with the mask value 0x3f ( 0b111111 ). The shift distance actually used is therefore always in the range 0 to 63 , inclusive.

At run time, shift operations are performed on the two's-complement integer representation of the value of the left operand.

The value of n << s is n left-shifted s bit positions; this is equivalent (even if overflow occurs) to multiplication by two to the power s .

The value of n >> s is n right-shifted s bit positions with sign-extension. The resulting value is ⌊ n / 2 s ⌋. For non-negative values of n , this is equivalent to truncating integer division, as computed by the integer division operator / , by two to the power s .

The value of n >>> s is n right-shifted s bit positions with zero-extension, where:

If n is positive, then the result is the same as that of n >> s .

If n is negative and the type of the left-hand operand is int , then the result is equal to that of the expression ( n >> s ) + ( 2 << ~ s ) .

If n is negative and the type of the left-hand operand is long , then the result is equal to that of the expression ( n >> s ) + ( 2L << ~ s ) .

The added term ( 2 << ~ s ) or ( 2L << ~ s ) cancels out the propagated sign bit.

Note that, because of the implicit masking of the right-hand operand of a shift operator, ~ s as a shift distance is equivalent to 31- s when shifting an int value and to 63- s when shifting a long value.

15.20. Relational Operators

The numerical comparison operators < , > , <= , and >= , and the instanceof operator, are called the relational operators .

RelationalExpression:     ShiftExpression     RelationalExpression  <  ShiftExpression     RelationalExpression  >  ShiftExpression     RelationalExpression  <=  ShiftExpression     RelationalExpression  >=  ShiftExpression     RelationalExpression  instanceof  ReferenceType

The relational operators are syntactically left-associative (they group left-to-right).

However, this fact is not useful. For example, a<b<c parses as (a<b)<c , which is always a compile-time error, because the type of a<b is always boolean and < is not an operator on boolean values.

The type of a relational expression is always boolean .

15.20.1. Numerical Comparison Operators < , <= , > , and >=

The type of each of the operands of a numerical comparison operator must be a type that is convertible ( §5.1.8 ) to a primitive numeric type, or a compile-time error occurs.

If the promoted type of the operands is int or long , then signed integer comparison is performed.

If the promoted type is float or double , then floating-point comparison is performed.

Comparison is carried out accurately on floating-point values, no matter what value sets their representing values were drawn from.

The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:

If either operand is NaN, then the result is false.

All values other than NaN are ordered, with negative infinity less than all finite values, and positive infinity greater than all finite values.

Positive zero and negative zero are considered equal.

For example, -0.0<0.0 is false , but -0.0<=0.0 is true .

Note, however, that the methods Math.min and Math.max treat negative zero as being strictly smaller than positive zero.

Subject to these considerations for floating-point numbers, the following rules then hold for integer operands or for floating-point operands other than NaN:

The value produced by the < operator is true if the value of the left-hand operand is less than the value of the right-hand operand, and otherwise is false .

The value produced by the <= operator is true if the value of the left-hand operand is less than or equal to the value of the right-hand operand, and otherwise is false .

The value produced by the > operator is true if the value of the left-hand operand is greater than the value of the right-hand operand, and otherwise is false .

The value produced by the >= operator is true if the value of the left-hand operand is greater than or equal to the value of the right-hand operand, and otherwise is false .

15.20.2. Type Comparison Operator instanceof

The type of the RelationalExpression operand of the instanceof operator must be a reference type or the null type; otherwise, a compile-time error occurs.

It is a compile-time error if the ReferenceType mentioned after the instanceof operator does not denote a reference type that is reifiable ( §4.7 ).

If a cast of the RelationalExpression to the ReferenceType would be rejected as a compile-time error, then the instanceof relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof expression could never be true.

At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast ( §15.16 ) to the ReferenceType without raising a ClassCastException . Otherwise the result is false .

Example 15.20.2-1. The instanceof Operator

This program results in two compile-time errors. The cast (Point)e is incorrect because no instance of Element or any of its possible subclasses (none are shown here) could possibly be an instance of any subclass of Point . The instanceof expression is incorrect for exactly the same reason. If, on the other hand, the class Point were a subclass of Element (an admittedly strange notion in this example):

then the cast would be possible, though it would require a run-time check, and the instanceof expression would then be sensible and valid. The cast (Point)e would never raise an exception because it would not be executed if the value of e could not correctly be cast to type Point .

15.21. Equality Operators

The operators == (equal to) and != (not equal to) are called the equality operators .

EqualityExpression:     RelationalExpression     EqualityExpression  ==  RelationalExpression     EqualityExpression  !=  RelationalExpression

The equality operators are syntactically left-associative (they group left-to-right).

However, this fact is essentially never useful. For example, a==b==c parses as (a==b)==c . The result type of a==b is always boolean , and c must therefore be of type boolean or a compile-time error occurs. Thus, a==b==c does not test to see whether a , b , and c are all equal.

The equality operators are commutative if the operand expressions have no side effects.

The equality operators are analogous to the relational operators except for their lower precedence. Thus, a<b==c<d is true whenever a<b and c<d have the same truth value.

The equality operators may be used to compare two operands that are convertible ( §5.1.8 ) to numeric type, or two operands of type boolean or Boolean , or two operands that are each of either reference type or the null type. All other cases result in a compile-time error.

The type of an equality expression is always boolean .

In all cases, a!=b produces the same result as !(a==b) .

15.21.1. Numerical Equality Operators == and !=

If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible ( §5.1.8 ) to numeric type, binary numeric promotion is performed on the operands ( §5.6.2 ).

If the promoted type of the operands is int or long , then an integer equality test is performed.

If the promoted type is float or double , then a floating-point equality test is performed.

Floating-point equality testing is performed in accordance with the rules of the IEEE 754 standard:

If either operand is NaN, then the result of == is false but the result of != is true .

Indeed, the test x!=x is true if and only if the value of x is NaN.

The methods Float.isNaN and Double.isNaN may also be used to test whether a value is NaN.

For example, -0.0==0.0 is true .

Otherwise, two distinct floating-point values are considered unequal by the equality operators.

In particular, there is one value representing positive infinity and one value representing negative infinity; each compares equal only to itself, and each compares unequal to all other values.

The value produced by the == operator is true if the value of the left-hand operand is equal to the value of the right-hand operand; otherwise, the result is false .

The value produced by the != operator is true if the value of the left-hand operand is not equal to the value of the right-hand operand; otherwise, the result is false .

15.21.2. Boolean Equality Operators == and !=

If the operands of an equality operator are both of type boolean , or if one operand is of type boolean and the other is of type Boolean , then the operation is boolean equality.

The boolean equality operators are associative.

If one of the operands is of type Boolean , it is subjected to unboxing conversion ( §5.1.8 ).

The result of == is true if the operands (after any required unboxing conversion) are both true or both false ; otherwise, the result is false .

The result of != is false if the operands are both true or both false ; otherwise, the result is true .

Thus != behaves the same as ^ ( §15.22.2 ) when applied to boolean operands.

15.21.3. Reference Equality Operators == and !=

If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.

It is a compile-time error if it is impossible to convert the type of either operand to the type of the other by a casting conversion ( §5.5 ). The run-time values of the two operands would necessarily be unequal.

At run time, the result of == is true if the operand values are both null or both refer to the same object or array; otherwise, the result is false .

The result of != is false if the operand values are both null or both refer to the same object or array; otherwise, the result is true .

While == may be used to compare references of type String , such an equality test determines whether or not the two operands refer to the same String object. The result is false if the operands are distinct String objects, even if they contain the same sequence of characters ( §3.10.5 ). The contents of two strings s and t can be tested for equality by the method invocation s.equals(t) .

15.22. Bitwise and Logical Operators

The bitwise operators and logical operators include the AND operator & , exclusive OR operator ^ , and inclusive OR operator | .

AndExpression:     EqualityExpression     AndExpression  &  EqualityExpression ExclusiveOrExpression:     AndExpression     ExclusiveOrExpression  ^  AndExpression InclusiveOrExpression:     ExclusiveOrExpression     InclusiveOrExpression  |  ExclusiveOrExpression

These operators have different precedence, with & having the highest precedence and | the lowest precedence.

Each of these operators is syntactically left-associative (each groups left-to-right).

Each operator is commutative if the operand expressions have no side effects.

Each operator is associative.

The bitwise and logical operators may be used to compare two operands of numeric type or two operands of type boolean . All other cases result in a compile-time error.

15.22.1. Integer Bitwise Operators & , ^ , and |

When both operands of an operator & , ^ , or | are of a type that is convertible ( §5.1.8 ) to a primitive integral type, binary numeric promotion is first performed on the operands ( §5.6.2 ).

The type of the bitwise operator expression is the promoted type of the operands.

For & , the result value is the bitwise AND of the operand values.

For ^ , the result value is the bitwise exclusive OR of the operand values.

For | , the result value is the bitwise inclusive OR of the operand values.

For example, the result of the expression:

The result of the expression:

15.22.2. Boolean Logical Operators & , ^ , and |

When both operands of a & , ^ , or | operator are of type boolean or Boolean , then the type of the bitwise operator expression is boolean . In all cases, the operands are subject to unboxing conversion ( §5.1.8 ) as necessary.

For & , the result value is true if both operand values are true ; otherwise, the result is false .

For ^ , the result value is true if the operand values are different; otherwise, the result is false .

For | , the result value is false if both operand values are false ; otherwise, the result is true .

15.23. Conditional-And Operator &&

The conditional-and operator && is like & ( §15.22.2 ), but evaluates its right-hand operand only if the value of its left-hand operand is true .

ConditionalAndExpression:     InclusiveOrExpression     ConditionalAndExpression  &&  InclusiveOrExpression

The conditional-and operator is syntactically left-associative (it groups left-to-right).

The conditional-and operator is fully associative with respect to both side effects and result value. That is, for any expressions a , b , and c , evaluation of the expression (( a ) && ( b )) && ( c ) produces the same result, with the same side effects occurring in the same order, as evaluation of the expression ( a ) && (( b ) && ( c )) .

Each operand of the conditional-and operator must be of type boolean or Boolean , or a compile-time error occurs.

The type of a conditional-and expression is always boolean .

At run time, the left-hand operand expression is evaluated first; if the result has type Boolean , it is subjected to unboxing conversion ( §5.1.8 ).

If the resulting value is false , the value of the conditional-and expression is false and the right-hand operand expression is not evaluated.

If the value of the left-hand operand is true , then the right-hand expression is evaluated; if the result has type Boolean , it is subjected to unboxing conversion ( §5.1.8 ). The resulting value becomes the value of the conditional-and expression.

Thus, && computes the same result as & on boolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

15.24. Conditional-Or Operator ||

The conditional-or operator || operator is like | ( §15.22.2 ), but evaluates its right-hand operand only if the value of its left-hand operand is false .

ConditionalOrExpression:     ConditionalAndExpression     ConditionalOrExpression  ||  ConditionalAndExpression

The conditional-or operator is syntactically left-associative (it groups left-to-right).

The conditional-or operator is fully associative with respect to both side effects and result value. That is, for any expressions a , b , and c , evaluation of the expression (( a ) || ( b )) || ( c ) produces the same result, with the same side effects occurring in the same order, as evaluation of the expression ( a ) || (( b ) || ( c )) .

Each operand of the conditional-or operator must be of type boolean or Boolean , or a compile-time error occurs.

The type of a conditional-or expression is always boolean .

If the resulting value is true , the value of the conditional-or expression is true and the right-hand operand expression is not evaluated.

If the value of the left-hand operand is false , then the right-hand expression is evaluated; if the result has type Boolean , it is subjected to unboxing conversion ( §5.1.8 ). The resulting value becomes the value of the conditional-or expression.

Thus, || compures the same result as | on boolean or Boolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

15.25. Conditional Operator ? :

The conditional operator ? : uses the boolean value of one expression to decide which of two other expressions should be evaluated.

ConditionalExpression:     ConditionalOrExpression     ConditionalOrExpression  ?  Expression  :  ConditionalExpression

The conditional operator is syntactically right-associative (it groups right-to-left). Thus, a?b:c?d:e?f:g means the same as a?b:(c?d:(e?f:g)) .

The conditional operator has three operand expressions. ? appears between the first and second expressions, and : appears between the second and third expressions.

The first expression must be of type boolean or Boolean , or a compile-time error occurs.

It is a compile-time error for either the second or the third operand expression to be an invocation of a void method.

In fact, by the grammar of expression statements ( §14.8 ), it is not permitted for a conditional expression to appear in any context where an invocation of a void method could appear.

The type of a conditional expression is determined as follows:

If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

If one of the second and third operands is of primitive type T , and the type of the other is the result of applying boxing conversion ( §5.1.7 ) to T , then the type of the conditional expression is T .

If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.

Otherwise, if the second and third operands have types that are convertible ( §5.1.8 ) to numeric types, then there are several cases:

If one of the operands is of type byte or Byte and the other is of type short or Short , then the type of the conditional expression is short .

If one of the operands is of type T where T is byte , short , or char , and the other operand is a constant expression ( §15.28 ) of type int whose value is representable in type T , then the type of the conditional expression is T .

If one of the operands is of type T , where T is Byte , Short , or Character , and the other operand is a constant expression ( §15.28 ) of type int whose value is representable in the type U which is the result of applying unboxing conversion to T , then the type of the conditional expression is U .

Otherwise, binary numeric promotion ( §5.6.2 ) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.

Otherwise, the second and third operands are of types S 1 and S 2 respectively. Let T 1 be the type that results from applying boxing conversion to S 1 , and let T 2 be the type that results from applying boxing conversion to S 2 .

The type of the conditional expression is the result of applying capture conversion ( §5.1.10 ) to lub( T 1 , T 2 ) ( §15.12.2.7 ).

At run time, the first operand expression of the conditional expression is evaluated first. If necessary, unboxing conversion is performed on the result.

The resulting boolean value is then used to choose either the second or the third operand expression:

If the value of the first operand is true , then the second operand expression is chosen.

If the value of the first operand is false , then the third operand expression is chosen.

The chosen operand expression is then evaluated and the resulting value is converted to the type of the conditional expression as determined by the rules stated above.

This conversion may include boxing ( §5.1.7 ) or unboxing ( §5.1.8 ) conversion.

The operand expression not chosen is not evaluated for that particular evaluation of the conditional expression.

15.26. Assignment Operators

There are 12 assignment operators ; all are syntactically right-associative (they group right-to-left). Thus, a=b=c means a=(b=c) , which assigns the value of c to b and then assigns the value of b to a .

AssignmentExpression:     ConditionalExpression     Assignment Assignment:     LeftHandSide AssignmentOperator AssignmentExpression LeftHandSide:     ExpressionName     FieldAccess     ArrayAccess AssignmentOperator: one of      = *= /= %= += -= <<= >>= >>>= &= ^= |=

The result of the first operand of an assignment operator must be a variable, or a compile-time error occurs.

This operand may be a named variable, such as a local variable or a field of the current object or class, or it may be a computed variable, as can result from a field access ( §15.11 ) or an array access ( §15.13 ).

The type of the assignment expression is the type of the variable after capture conversion ( §5.1.10 ).

At run time, the result of the assignment expression is the value of the variable after the assignment has occurred. The result of an assignment expression is not itself a variable.

A variable that is declared final cannot be assigned to (unless it is definitely unassigned ( §16 )), because when an access of such a final variable is used as an expression, the result is a value, not a variable, and so it cannot be used as the first operand of an assignment operator.

15.26.1. Simple Assignment Operator =

A compile-time error occurs if the type of the right-hand operand cannot be converted to the type of the variable by assignment conversion ( §5.2 ).

At run time, the expression is evaluated in one of three ways.

If the left-hand operand expression is a field access expression ( §15.11 ) e.f , possibly enclosed in one or more pairs of parentheses, then:

First, the expression e is evaluated. If evaluation of e completes abruptly, the assignment expression completes abruptly for the same reason.

Next, the right hand operand is evaluated. If evaluation of the right hand expression completes abruptly, the assignment expression completes abruptly for the same reason.

Then, if the field denoted by e.f is not static and the result of the evaluation of e above is null , then a NullPointerException is thrown.

Otherwise, the variable denoted by e.f is assigned the value of the right hand operand as computed above.

If the left-hand operand is an array access expression ( §15.13 ), possibly enclosed in one or more pairs of parentheses, then:

First, the array reference subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the index subexpression (of the left-hand operand array access expression) and the right-hand operand are not evaluated and no assignment occurs.

Otherwise, the index subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and the right-hand operand is not evaluated and no assignment occurs.

Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

Otherwise, if the value of the array reference subexpression is null , then no assignment occurs and a NullPointerException is thrown.

Otherwise, the value of the array reference subexpression indeed refers to an array. If the value of the index subexpression is less than zero, or greater than or equal to the length of the array, then no assignment occurs and an ArrayIndexOutOfBoundsException is thrown.

Otherwise, the value of the index subexpression is used to select a component of the array referred to by the value of the array reference subexpression.

This component is a variable; call its type SC . Also, let TC be the type of the left-hand operand of the assignment operator as determined at compile time. Then there are two possibilities:

If TC is a primitive type, then SC is necessarily the same as TC .

The value of the right-hand operand is converted to the type of the selected array component, is subjected to value set conversion ( §5.1.13 ) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the array component.

If TC is a reference type, then SC may not be the same as TC , but rather a type that extends or implements TC .

Let RC be the class of the object referred to by the value of the right-hand operand at run time.

A Java compiler may be able to prove at compile time that the array component will be of type TC exactly (for example, TC might be final ). But if a Java compiler cannot prove at compile time that the array component will be of type TC exactly, then a check must be performed at run time to ensure that the class RC is assignment compatible ( §5.2 ) with the actual type SC of the array component.

This check is similar to a narrowing cast ( §5.5 , §15.16 ), except that if the check fails, an ArrayStoreException is thrown rather than a ClassCastException .

If class RC is not assignable to type SC , then no assignment occurs and an ArrayStoreException is thrown.

Otherwise, the reference value of the right-hand operand is stored into the selected array component.

Otherwise, three steps are required:

First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.

Otherwise, the value of the right-hand operand is converted to the type of the left-hand variable, is subjected to value set conversion ( §5.1.13 ) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

Example 15.26.1-1. Simple Assignment To An Array Component

The most interesting case of the lot is thirteenth from the end:

which indicates that the attempt to store a reference to a StringBuffer into an array whose components are of type Thread throws an ArrayStoreException . The code is type-correct at compile time: the assignment has a left-hand side of type Object[] and a right-hand side of type Object . At run time, the first actual argument to method testFour is a reference to an instance of "array of Thread " and the third actual argument is a reference to an instance of class StringBuffer .

15.26.2. Compound Assignment Operators

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)) , where T is the type of E1 , except that E1 is evaluated only once.

For example, the following code is correct:

and results in x having the value 7 because it is equivalent to:

At run time, the expression is evaluated in one of two ways.

If the left-hand operand expression is not an array access expression, then:

Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

Otherwise, the result of the binary operation is converted to the type of the left-hand variable, subjected to value set conversion ( §5.1.13 ) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

If the left-hand operand expression is an array access expression ( §15.13 ), then:

Otherwise, the value of the index subexpression is used to select a component of the array referred to by the value of the array reference subexpression. The value of this component is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

For a simple assignment operator, the evaluation of the right-hand operand occurs before the checks of the array reference subexpression and the index subexpression, but for a compound assignment operator, the evaluation of the right-hand operand occurs after these checks.

Otherwise, consider the array component selected in the previous step, whose value was saved. This component is a variable; call its type S . Also, let T be the type of the left-hand operand of the assignment operator as determined at compile time.

If T is a primitive type, then S is necessarily the same as T .

The saved value of the array component and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator.

If this operation completes abruptly (the only possibility is an integer division by zero - see §15.17.2 ), then the assignment expression completes abruptly for the same reason and no assignment occurs.

Otherwise, the result of the binary operation is converted to the type of the selected array component, subjected to value set conversion ( §5.1.13 ) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the array component.

If T is a reference type, then it must be String . Because class String is a final class, S must also be String .

Therefore the run-time check that is sometimes required for the simple assignment operator is never required for a compound assignment operator.

The saved value of the array component and the value of the right-hand operand are used to perform the binary operation (string concatenation) indicated by the compound assignment operator (which is necessarily += ). If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

Otherwise, the String result of the binary operation is stored into the array component.

Example 15.26.2-1. Compound Assignment To An Array Component

The most interesting cases of the lot are eleventh and twelfth from the end:

They are the cases where a right-hand side that throws an exception actually gets to throw the exception; moreover, they are the only such cases in the lot. This demonstrates that the evaluation of the right-hand operand indeed occurs after the checks for a null array reference value and an out-of-bounds index value.

Example 15.26.2-2. Value Of Left-Hand Side Of Compound Assignment Is Saved Before Evaluation Of Right-Hand Side

The value 1 of k is saved by the compound assignment operator += before its right-hand operand (k = 4) * (k + 2) is evaluated. Evaluation of this right-hand operand then assigns 4 to k , calculates the value 6 for k + 2 , and then multiplies 4 by 6 to get 24 . This is added to the saved value 1 to get 25 , which is then stored into k by the += operator. An identical analysis applies to the case that uses a[0] .

In short, the statements:

behave in exactly the same manner as the statements:

15.27. Expression

An Expression is any assignment expression:

Expression:     AssignmentExpression

Unlike C and C++, the Java programming language has no comma operator.

15.28. Constant Expressions

ConstantExpression:     Expression

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

Literals of primitive type and literals of type String ( §3.10.1 , §3.10.2 , §3.10.3 , §3.10.4 , §3.10.5 )

Casts to primitive types and casts to type String ( §15.16 )

The unary operators + , - , ~ , and ! (but not ++ or -- ) ( §15.15.3 , §15.15.4 , §15.15.5 , §15.15.6 )

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

The additive operators + and - ( §15.18 )

The shift operators << , >> , and >>> ( §15.19 )

The relational operators < , <= , > , and >= (but not instanceof ) ( §15.20 )

The equality operators == and != ( §15.21 )

The bitwise and logical operators & , ^ , and | ( §15.22 )

The conditional-and operator && and the conditional-or operator || ( §15.23 , §15.24 )

The ternary conditional operator ? : ( §15.25 )

Parenthesized expressions ( §15.8.5 ) whose contained expression is a constant expression.

Simple names ( §6.5.6.1 ) that refer to constant variables ( §4.12.4 ).

Qualified names ( §6.5.6.2 ) of the form TypeName . Identifier that refer to constant variables ( §4.12.4 ).

Compile-time constant expressions of type String are always "interned" so as to share unique instances, using the method String.intern .

A compile-time constant expression is always treated as FP-strict ( §15.4 ), even if it occurs in a context where a non-constant expression would not be considered to be FP-strict.

Compile-time constant expressions are used in case labels in switch statements ( §14.11 ) and have a special significance for assignment conversion ( §5.2 ) and initialization of a class or interface ( §12.4.2 ). They may also govern the ability of a while , do , or for statement to complete normally ( §14.21 ), and the type of a conditional operator ? : with numeric operands.

Example 15.28-1. Constant Expressions

     
Chapter 14. Blocks and Statements   Chapter 16. Definite Assignment
  • Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand
  • OverflowAI GenAI features for Teams
  • OverflowAPI Train & fine-tune LLMs
  • Labs The future of collective knowledge sharing
  • About the company Visit the blog

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

"AssignmentOperator Expression" error on simple lambda expression code

I'm learning how to use lambda expressions now, and I've seen some tutorials with a simple example:

But my compiler is showing this error:

Am I forgetting something?

Rann Lifshitz's user avatar

  • You're not doing anything with the lambda, and Java's syntax tries to exclude statements that obviously don't do anything. –  user2357112 Commented Dec 2, 2016 at 0:06
  • What are you expecting that code to do? –  Andreas Commented Dec 2, 2016 at 0:48

4 Answers 4

Lambda expressions always have to be assigned to a reference type of Functional Interafces (also called single abstract method interfaces). Infact, they provide shortcut to the verbose anonymous class (with single method) implementations.

So, in simple words, Lambda expression = abstract method implementation (of the functional interface).

For example, your expression can be assigned to the below Functional Interface:

Vasu's user avatar

Lambdas are expressions that cannot be used as statements. From JLS8 §15.27 :

It is a compile-time error if a lambda expression occurs in a program in someplace other than an assignment context (§5.2), an invocation context (§5.3), or a casting context (§5.5).

Consider this example:

Andrey's user avatar

The issue is, as pointed out above, you are not doing anything with the lambda. This means that:

  • Your line of code is "not a statement" (another error message often emitted by the compiler). This is similar to something like this:

Which is not valid Java.

diesieben07's user avatar

A lambda expression cannot stand alone in Java, it need to be associated to a functional interface.

Note : This is the first and last time you will see implemention of interface without keyword "Implements" .

Play Around: try adding a new dummy method to your interface myinterface and you will see that your code will fail to compile, thus indicating that reference has to be only made from Functional interface not from general interfaces.

Compilation Error: The target type of this expression must be a functional interface

Vishwa Ratna's user avatar

Your Answer

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged java lambda or ask your own question .

  • The Overflow Blog
  • One of the best ways to get value for AI coding tools: generating tests
  • The world’s largest open-source business has plans for enhancing LLMs
  • Featured on Meta
  • User activation: Learnings and opportunities
  • Site maintenance - Mon, Sept 16 2024, 21:00 UTC to Tue, Sept 17 2024, 2:00...
  • What does a new user need in a homepage experience on Stack Overflow?
  • Announcing the new Staging Ground Reviewer Stats Widget

Hot Network Questions

  • O(nloglogn) Sorting Algorithm?
  • What’s the name of this horror movie where a girl dies and comes back to life evil?
  • What would be an appropriate translation of Solitude?
  • How to reply to a revise and resubmit review, saying is all good?
  • Is it feasible to create an online platform to effectively teach college-level math (abstract algebra, real analysis, etc.)?
  • History of the migration of ERA from AMS to AIMS in 2007
  • Can landlords require HVAC maintenance in New Mexico?
  • Is it true that before European modernity, there were no "nations"?
  • How to Place a Smooth "Breathing" Above the E with Textgreek?
  • What would a planet need for rain drops to trigger explosions upon making contact with the ground?
  • Negating a multiply quantified statement
  • "There is a bra for every ket, but there is not a ket for every bra"
  • Why is resonance such a widespread phenomenon?
  • What unintended side effects may arise from making bards count as both arcane and divine spellcasters?
  • If Act A repeals another Act B, and Act A is repealed, what happens to the Act B?
  • Why does counterattacking lead to a more drawish and less dynamic position than defending?
  • The consequence of a good letter of recommendation when things do not work out
  • mmrm R package : No optimizer led to a successful model fit
  • Copyright Fair Use: Is using the phrase "Courtesy of" legally acceptable when no permission has been given?
  • Is it defamatory to publish nonsense under somebody else's name?
  • Was Willy Wonka correct when he accused Charlie of stealing Fizzy Lifting Drinks?
  • How to deal with coauthors who just do a lot of unnecessary work and exploration to be seen as hard-working and grab authorship?
  • Longtable goes beyond the right margin and footnote does not fit under the table
  • security concerns of executing mariadb-dump with password over ssh

assignment operator expression to complete expression

COMMENTS

  1. What does `Syntax error, insert "AssignmentOperator Expression" to

    This is an expression, but not a statement; hence the complaint. If you want to examine the contents of nums , you can do something like: System.out.println(Arrays.toString(nums));

  2. Another Syntax error, insert "AssignmentOperator Expression" to

    The Java Language Specification forbids a line that does not conform to what it considers an expression. You don't call a method on the object or assign it to a variable, which is what the compiler is telling you.

  3. 1.4. Expressions and Assignment Statements

    In this lesson, you will learn about assignment statements and expressions that contain math operators and variables. 1.4.1. Assignment Statements ¶. Remember that a variable holds a value that can change or vary. Assignment statements initialize or change the value stored in a variable using the assignment operator =.

  4. Java Assignment Operators with Examples

    Compound-assignment operators provide a shorter syntax for assigning the result of an arithmetic or bitwise operator. They perform the operation on the two operands before assigning the result to the first operand. ... In Java logical operators, if the evaluation of a logical expression exits in between before complete evaluation, then it is ...

  5. The Assignment Operator

    JMU Computer Science Course Information

  6. Expressions and operators

    An assignment operator assigns a value to its left operand based on the value of its right operand. The simple assignment operator is equal (=), which assigns the value of its right operand to its left operand.That is, x = f() is an assignment expression that assigns the value of f() to x. There are also compound assignment operators that are shorthand for the operations listed in the ...

  7. Python's Assignment Operator: Write Robust Assignments

    Here, variable represents a generic Python variable, while expression represents any Python object that you can provide as a concrete value—also known as a literal—or an expression that evaluates to a value. To execute an assignment statement like the above, Python runs the following steps: Evaluate the right-hand expression to produce a concrete value or object.

  8. Assignment (=)

    The assignment operator is completely different from the equals (=) sign used as syntactic separators in other locations, which include:Initializers of var, let, and const declarations; Default values of destructuring; Default parameters; Initializers of class fields; All these places accept an assignment expression on the right-hand side of the =, so if you have multiple equals signs chained ...

  9. Assignment Operators in Programming

    Assignment operators are used in programming to assign values to variables. We use an assignment operator to store and update data within a program. They enable programmers to store data in variables and manipulate that data. The most common assignment operator is the equals sign (=), which assigns the value on the right side of the operator to ...

  10. Assignment operators

    In this article. The assignment operator = assigns the value of its right-hand operand to a variable, a property, or an indexer element given by its left-hand operand. The result of an assignment expression is the value assigned to the left-hand operand. The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it.

  11. Solved Syntax error, insert "AssignmentOperator Expression" to complete

    Solved Syntax error, insert "AssignmentOperator Expression" to complete Expression Discussion in ' Plugin Development ' started by Xp10d3 , Jan 26, 2020 . Thread Status:

  12. Chapter 15. Expressions

    The lowest precedence operator is the arrow of a lambda expression (->), followed by the assignment operators. Thus, all expressions are syntactically included in the LambdaExpression and AssignmentExpression nonterminals: Expression: LambdaExpression ... such expressions are said to complete abruptly. ...

  13. Syntax error, insert "AssignmentOperator Expression" to complete

    For appeals, questions and feedback about Oracle Forums, please email [email protected] questions should be asked in the appropriate category. Thank you!

  14. PDF Compile and Runtime Errors in Java

    2The value of an assignment statement considered as an expression is the value of the expression on the right-hand side that is assigned to the variable on the left-hand side. 3 The syntax of a programming language is defined in terms of tokens consisting of one or more

  15. Processing error: Syntax error, insert "AssignmentOperator Expression

    I pasted that code into a sketchpad.cc, and I didn't get any errors.

  16. Detail Message: Syntax error, insert "AssignmentOperator Expression" to

    Looking for Qlik Talend Support? Click here to log into our Support Portal. Looking for articles and discussions? We've moved to the Qlik Community!

  17. Chapter 15. Expressions

    Evaluation of an expression can also produce side effects, because expressions may contain embedded assignments, increment operators, decrement operators, and method invocations. An expression denotes nothing if and only if it is a method invocation ( §15.12 ) that invokes a method that does not return a value, that is, a method declared void ...

  18. java

    Lambda expressions always have to be assigned to a reference type of Functional Interafces (also called single abstract method interfaces). Infact, they provide shortcut to the verbose anonymous class (with single method) implementations. So, in simple words, Lambda expression = abstract method implementation (of the functional interface).