There are 10 types of people in the world: those who understand binary numbers and those who don't.
Data in computer programs are stored in variables.
A variable's name corresponds to some location in computer
memory where the value of that variable is stored.
Suppose you could “see” the binary value stored in some memory
location.
For example say the variable “foo
” corresponds
to the memory address 1280
, and when you “looked”
at that part of memory you saw the following:
0 1 0 0 0 1 1 0 1 1 0 1 1 1 1 0 ...
There is no way for you (or a computer) to know what it means. It could be an integer, a string of characters, a floating point number, or something else (part of a GIF graphic, for example). This is one reason why all Java variables have a declared type. The type of a variable tells the computer how to interpret the data.
Java provides many different built-in (or primitive) types you can use for your variables. As a programmer you must be able to pick an appropriate type for the kind of data you expect to store in any variable. In general prefer integral (“fixed point”) types to “floating point” types, and prefer smaller types to larger ones. You do need to ensure you chose a type that is large enough to hold the full range of values expected (which should be documented as part of the requirements), and will be accurate enough.
Primitive types are those directly supported by hardware and thus are very efficient. Some other languages only use object types, which must track the actual type and chose the appropriate hardware instructions on every access, taking up more memory and time. The developers of Java decided this efficiency gain was worth the confusion caused by have both primitive types and object types.
With advances in hardware and compiler optimizations making the efficiency gains much less, there is a push as of 2022 to unify primitive and object types in a future version of Java with two proposals from project Valhalla: JEP 401 and JEP 402.
Float and double are useful with scientific and engineering computation, and with statistics. Outside of these areas they should mostly be avoided. Float is preferred to double when memory is short, or when you need a very large number of values and can tolerate the lower precision. The performance advantage of floats to doubles is modest on modern hardware, and should not be a consideration.
For most applications you can chose int
, even when
a smaller integral type has an appropriate range.
As with floats, the smaller types are useful when you need a lot
of them and/or when memory use must be minimized.
Note most financial calculations can be calculated in fixed
point, that is using integers (calculate in pennies or
even thousandths of a cent).
Type | Size | Format | Range | Literals | Comments |
---|---|---|---|---|---|
boolean | ≤1 byte | — | — | false ,
true |
Use for on/off (checkbox) settings |
byte | 1 byte | signed integer | ±127 | −3, 0, 10, 124 | Use to store lots of small numbers (e.g., temperatures, years of service, test scores) |
short | 2 bytes | signed integer | ±32,767 | −130, −3, 0, 10, 124, 25000 | Use to store lots of small numbers too big for a byte |
char | 2 bytes | unsigned integer | 0 to +65,535 | 0, 124, 44000, 'A', '\u00A9' | Use for Unicode
character codes, including '\\' , '\n' ,
'\r' , '\t' , '\'' ,
and '\udddd' |
int | 4 bytes | signed integer | ±2,147,483,647 | −10, 0, 12, 120000, 1_200_000, 017 (octal), 0x2F (hex), 0b100 (binary) | Use to store or compute with integers; the most commonly used type |
long | 8 bytes | signed integer | ±9,223,372,036,854,775,807 | −10L, −3L, 0L, 10L, 250_000_000L | Use to store compute with integers too large for an int |
float | 4 bytes | floating point | ±1038 | −6F, 0.F, 0.0F, 3.14F, 6F, 6.02E23F, 1E2F, −1E2F, 1E−2F | Use to store or compute with rational numbers (numbers with decimal points or in scientific notation); has about 6 decimal digits of accuracy. |
double | 8 bytes | floating point | ±10308 | −10.0, 0.0, 0.0D, 3.14, 12., 120000D | Similar to float but with greater range and about 15 decimal
digits of accuracy. |
Most people consider using a signed value for byes a mis-feature in Java. The most common use for a byte is to hold non-ASCII data which is unsigned. So to process a GIF file read into an array of bytes requires a conversion:
int num = someByte < 0 ? someByte+256 : someByte;
byte
, short
,
and int
.
The only difference is the magnitude of the values, and what you are
doing with it.
For example:
byte b = 3; int i = 3;
Java doesn't have byte
or short
literals;
instead, int
literals are automatically narrowed or
widened as needed.
(Interestingly, char
literals such as 'a'
are first
converted to int
, which is then narrowed to short
or byte
as needed.
This means
“byte b = '\uXXXX';
”
might result in a negative value, if “XXXX
”
is large enough.)
0x
”
or “0X
”, and (since Java 7) binary literals
start with “0b
” or “0B
”.
So 17
is the decimal number for seventeen, 017
is the octal number for fifteen, 0x17
is the
hex number for twenty-three, and 0b101
is the binary number
for five.
Further information on binary, octal, decimal, and hex numbers can
be found by searching the Internet, for example
Bin Dec Hex Tutorial.
1_234_567
”
or “0x__0F
”.
Note such literals can't start or end with an underscore.
Integer.parseInt
, Long.parseLong
, etc.,
don't support using underscores this way; only Integer literals support this.
±num
" in the chart above really means
"−(num+1)
to +num
".)
Just for fun, here's what the 3–bit two's complement numbers look like:
Decimal | Binary | Decimal | Binary | ||
---|---|---|---|---|---|
+3 | 0 1 1 | −1 | 1 1 1 | ||
+2 | 0 1 0 | −2 | 1 1 0 | ||
+1 | 0 0 1 | −3 | 1 0 1 | ||
0 | 0 0 0 | −4 | 1 0 0 |
3 bit two's complement signed integers
sign | exponent | mantissa |
---|
The sign is a single bit, zero for positive and one for
negative.
The exponent is a signed integer (but not in two's complement).
The mantissa (or fraction) is an unsigned integer,
with a decimal point assumed to be present at the far left end.
The larger the exponent field, the larger the range of the number, and
the larger the mantissa, the greater the accuracy. Given a limited
number of bits in a float
or double
, there
is a trade-off of these values.
Floating point number are never accurate, there is always some floating point round-off error. This is not a problem for integers, which is the main reason to always pick an integer type if you possibly can. Note financial calculations can often be done using integers if you compute everything in pennies, and divide by 100 at the end to get dollars and cents. (The exact precision varies depending on what you do and the values you store. It could be several digits of error for some values.) Once you start doing computations, the result has even less precision.
As a simple example of floating point, pretend an 8–bit floating point
format (Java doesn't have any one byte floating point types) has 1 sign bit,
a 3–bit one's complement exponent, and a 4–bit mantissa.
Then the bit pattern of 00101101
can be interpreted as:
sign | exponent | mantissa |
---|---|---|
0 | 0 1 0 | 1 1 0 1 |
Here the sign is positive, the exponent is 2
,
and the mantissa is .1101
.
The result is binary +11.01
, which in decimal
would be +3.25
.
strictfp
modifier (and use the methods
in the StrictMath
class instead of the Math
class).
(Note strictfp
is obsolete as of Java 17, as all math is now
“strict”.)java.math
package,
BigInteger
and BigDecimal
.
These are object types (not primitives), and can be much slower than
using primitive types.
However there is no limit on the size of the values.
(See Big Numbers Demo for more information.)
String
literal is enclosed in double quotes:
"Howdy \"Wayne\"\n"
.
You can declare String
object references like this:
String msg = "Hello";
In Java strings are not a basic type but are objects of
class String
.
All identical String
literals in a program are collapsed
into a single object, so:
String s1 = "foo", s2 = "foo"; s1 == s2 true
but this can get tricky:
String s1 = "foo"; s2 = new String("foo"); s1 == s2 false
String
s can be concatenated using a plus symbol.
This allows one to break up String
literals too long
for a single line.
(Example: "ABC" + "DEF"
results in "ABCDEF"
.)
null
, which is a special value that means this variable
doesn't refer to any object.
For example: String name = null;
. static
methods).
For example: Integer.toString(int)
to convert an int
to a String
object, as can String.valueOf(int)
.
To convert from String
s to primitive types, use one of the
parseXXX()
methods (where XXX is the type).
Examples:
Integer.parseInt( "17" );
or
Float.parseFloat( "3.14F" );