Values
- Values in programming languages are things like numbers, logical values, or text. Or more complex kinds of values made out of collections of those simpler values.
- Every value has a “type” which determines what you can do with it.
- Some data types are built into Java and some are defined by you.
- Java supports several built in data types we’ll learn about: two kinds of numbers,
int
and double
; logical values called booleans
; textual values called Strings
; as well as composite types such: arrays and objects.
Expressions
- An expression is any part of a program that can be evaluated to produce a value.
- Each expression has a "type" which is determined by the types of its sub-expressions and the operators involved. The type describes the kind of values it can produce.
- Anywhere a value of a given type is needed we can use any expression that produces values of that type.
- Operators operate on values (called the operands) to produce a new value.
- Each operator works on specific types of values.
- Compound expressions are made up of expressions and operators, e.g.
x + 2
, evaluate to a value determined by the operator and its operands.
- Literal values, e.g.
10
or "foo"
, evaluate to the value they denote.
- Variables, e.g.
x
or Math.PI
, evaluate to the current value of of the variable.
- Array access expressions, e.g
xs[0]
, evaluate to the value stored at the given position in the array.
- Field access expressions, e.g. foo.name or Math.PI evaluate to the value of the member variable of the given instance or class.
- Method calls to non-
void
methods, e.g. s.substring(1)
or Math.sqrt(2)
, evaluate to the value returned by the method when called with the given arguments.
- Object instantiations via the
new
keyword, e.g. new ArrayList<>()
, evaluate to a reference to a newly created object that has been initialized by running the appropriate constructor.
Data types
- A type is a set of values (a domain) and a set of operations on them.
- Every data type also has an in-memory representation.
- Data types in Java are either primitive or reference types.
Literal values
- The primitive data types and
String
s each have a syntax for writing literal values in Java programs, e.g. 1234
, 9.876
, true
, and "foobar"
.
Primitive types
- The primitive data types used in this course, which represent numbers and logical values, are
int
, double
, and boolean
.
- Integer values in Java are represented by the data type
int
. int
s are stored using four bytes (32 bits) of memory. Therefore, an int
value must be in the range from -2^32 to 2^31 - 1 (Integer.MIN_VALUE
) to Integer.MAX_ VALUE
inclusive.
- If an
int
expression would evaluate to a numeric value outside of the possible range for int
, an overflow occur resulting in a mathematically incorrect int
value. (For instance Integer.MAX_VALUE + 1
evaluates to Integer.MIN_VALUE
.)
- Numbers with fractional parts are represented by the data type
double
. A double
is stored in a 64-bit representation that encodes a significand, and exponent, and a sign, similar to the way scientific notation works.
- Logical values (true and false) are represented by the
boolean
data type. There are only two boolean
values: written as true
and false
.
Reference types
- All the other data types we will use are reference data types which means the values that are stored in variables and passed to and returned from methods are references to where the real value lives in memory.
- Reference types not stored directly in variables but instead the actual value is stored somewhere in memory and what is stored in variables is a “reference” to that memory.
- Some reference types (such as arrays,
ArrayList
s and other classes we will write) are mutable meaning their value can be changed.
- The main reference types we use in this course are
String
, arrays, ArrayList
and other classes that we write ourselves all of which extend Object
.
null
is a special reference value that represents “no object”. It can be written as a literal value as null
. It is the default value for uninitialized member variables and array elements with a reference type.
- Using the dot operator to call a method or access an instance variable on a
null
value causes a NullPointerException
to be thrown.
Arithmetic expressions
- Arithmetic expressions are expressions that produce an or
int
and double
value.
- The arithmetic operators consist of
+
, −
, *
, /
, and %
.
- An arithmetic operation on two
int
s will evaluate to an int
.
- An arithmetic operation with at least one
double
value will evaluate to a double
.
- During evaluation, operands are associated with operators according to operator precedence to determine how they are grouped.
- An attempt to divide an integer by zero will result in an
ArithmeticException
to occur.
- Using an
int
where a double
is expected, without a cast, causes the int
value to be automatically cast to a double
value.
- Values of type
double
can be rounded to the nearest int
by (int)(x + 0.5)
or (int)(x – 0.5)
for negative numbers.
Boolean expressions
- A boolean expression is any expression that results in a
boolean
value. The values used in the expression may be boolean
s or other kinds of values. For instance, x > 10
is a boolean
expression even though x
must be a number and a == b
always evaluates to a boolean
even though a
and b
could be any type of values.
- There are a number of kinds of operators that produce boolean values: logical operators that operate on booleans, equality operators that operate on all kinds of values, and relational operators that operate on numeric values.
Logical operators
- Logical operators operate on
boolean
values and produce a boolean
value. There are three logical operators in Java: !
(not), &&
(and), and ||
(or).
!
is the highest precedence, followed by &&
, followed by ||
.\note{One way to remember the relative precedence is to note that if you think of boolean
s as a kind of numbers with false
analogous to 0 and true
analogous to 1, then !
is equivalent to a single negation as in -x
, which flips the sign of its value, &&
is analogous to multiplication since true && x
is x
for all boolean
x
just like 1 * x
is x
for all numeric x
and ||
is like addition since false || x
is x
for all boolean x
, just like 0 + x
is x
for all numeric x
.)}
- When the result of a logical expression using
&&
or ||
can be determined by evaluating only the first operand, the second is not evaluated. This is known as short-circuited evaluation.\note{This can be useful when the second expression would not be safe to evaluate in some circumstances. For instance: s.length() >= 3 && s.substring(0, 3).equals(“abc”)
evaluates to false if the string is less than three characters long without trying to extract a substring which would throw an exception if the string is not that long.}
- De Morgan’s Laws allows us to transform some boolean expressions into equivalent expressions using two relaed identities:
!a && !b = !(a || b)
and !a || !b = !(a && b)
- Truth tables can be used to prove
boolean
identities, i.e. different expressions that are equivalent in the sense that for all possible combinations of values for the variables in the expressions they evaluate to the same value. A trivial example of a pair of equivalent expressions is: a && true
and a
. More complex identities include things like De Morgan’s Laws. For more details see [Boolean algebra summary]
Equality operators
- Equality operators operate on two values of the same type and determine whether the two values are “the same”.
- Both primitive and reference values can be compared for equality using the equality operators
==
and !=
.
- Reference values are only
==
when they both reference the same object or when they are both null
. This may not, however, be the notion of “the same” that you care about when you are comparing two objects.
- All classes have an
equals
method inherited from Object
and it is often overridden by classes to provide a way to determine if two instances of the class are equivalent in a more meaningful way simply being ==
. For example, two String
objects with the same character content are equals
even when they are not ==
.\note{The equals
method is not an operator; just a method that returns a boolean
.}
- The
==
operator is sometimes pronounced “equals equals” to distinguish it from the equals
method.
Relational operators
- Relational operators operate on numeric values and produce a
boolean
value.
- The relational operators are
<
, >
, <=
, and >=
which evaluate to true
if their left hand operand is less than, greater than, less than or equal to, or greater than or equal to the right hand operand. E.g. 10 < 20
evaluates to true
.
- You can’t chain relational operators in Java the way you can in math. So rather than writing
0 <= x < 10
you have to combine two relational expressions with the logical operator &&
, writing instead 0 <= x && x < 10
.