26 October 2020

Wrapper Classes

Look for your class's particulars in the folders on the left.

Uh oh.


jshell> ArrayList<int> al = new ArrayList<>();
|  Error:
|  unexpected type
|    required: reference
|    found:    int
|  ArrayList<int> al = new ArrayList<>();
|            ^-^

Only Object types can be used as a type parameter in a generic class. Ouch. What do we do? The answer lies in wrapper types.

Every primitive type has a wrapper type.

Java Wrapper Types
PrimitiveWrapper
byte Byte
short Short
int Integer
long Long
boolean Boolean
float Float
double Double
char Character

The wrapper types have these elements in common.

Let's see Integer in action. We can make an array list of Integers.


jshell> ArrayList<Integer> al = new ArrayList<>();
al ==> []

jshell> for(int k = 0; k < 20; k++){al.add(k*k*k);}

jshell> al
al ==> [0, 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 1331, 
    1728, 2197, 2744, 3375, 4096, 4913, 5832, 6859]

You will notice that the constructors in Integer are deprecated. Here is why. Notice when we use the String class we don't use the new keyword.


jshell> String s = "foo";
s ==> "foo"

Watch this. It's called autoboxing.


jshell> Integer i = 5;
i ==> 5

The primitive literal 5 is "boxed" automatically into an Integer object. This is how we usually make Integers.

When we added the integers into the array list in the example above, autoboxing also occurred.

Also notice this. The variable i knows it's pointing at an Integer.

`

jshell> x.getClass()
|  Error:
|  int cannot be dereferenced
|  x.getClass()
|  ^--------^

Contrast that to this.


jshell> int x = 42;
x ==> 42

jshell> x.getClass()
|  Error:
|  int cannot be dereferenced
|  x.getClass()
|  ^--------^

You cannot call methods on primitives. Now observe this.


jshell> x = i;
x ==> 5

The contents of i were autounboxed. So, we have autoboxing and autounboxing.

All wrapper classes have this feature.

Hammer Time Here is something not to do.


jshell> int out = 17;
out ==> 17

jshell> for(Integer i = 0; i < 5000; i++){out += i;}

jshell> out
out ==> 12497517

Here 5000 boxings and 5000 unboxings occurred. That will deliver a performance hit. Use primitives for loop variables. Autoboxing and autounboxing are useful tools, not universal solutions. Like all tools, they have their place.


jshell> String quack = "531";
quack ==> "531"

jshell> //can you figure out how to get 531 out of this?

Some clever person thought of this. All of the wrappers have a feature just like this.


jshell> Integer.parseInt(quack)
$13 ==> 531

What happens if we try something dumb like using this on "duck egg."


jshell> Integer.parseInt("duck egg")
|  Exception java.lang.NumberFormatException: For input string: "duck egg"
|        at NumberFormatException.forInputString (NumberFormatException.java:68)
|        at Integer.parseInt (Integer.java:652)
|        at Integer.parseInt (Integer.java:770)
|        at (#14:1)

An exception is a .45 calibre bullet heading straight for the beating heart of your program. Consider this code.


public class Exceptional
{
    private static ArrayList al;
    public static void main(String[] args)
   {
       System.out.println("I am now alive and on");
       System.out.println("the correct side of the weeds");
       int x = Integer.parseInt("445");
       System.out.println(x);
       int y = Integer.parseInt("duck egg");
       System.out.println("I am dead now");
    }
}

This code compiles without remark. If you run this code, it will keep running until the line where y is defined as you see here. Then immediate program death ensues.

unix> java Exceptional
I am now alive and on
the correct side of the weeds
445
Exception in thread "main" java.lang.NumberFormatException: For input string: "duck egg"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at Exceptional.main(Exceptional.java:11)

Now modify this program as follows.


import java.util.ArrayList;
public class Exceptional
{
    private static ArrayList<String> al;
    public static void main(String[] args)
   {
       System.out.println("I am now alive and on");
       System.out.println("the correct side of the weeds");
       int x = Integer.parseInt("445");
       System.out.println(x);
       int y = Integer.parseInt("duck egg");
       //al.add("foo");
       System.out.println("I am dead now");
    }
}
unix> java Exceptional
I am now alive and on
the correct side of the weeds
445
Exception in thread "main" java.lang.NullPointerException
    at Exceptional.main(Exceptional.java:12)

Since you never used new on the array list, it pointed at null. Calling a method on null triggers a NullPointerException.

Treasure Hunt What is 1000 in base 8? Some clever wag found this.


jshell> Integer.toOctalString(1000)
$1 ==> "1750"

There's this too.


jshell> Integer.toHexString(1000)
$2 ==> "3e8"

What is 1000 in base 3?

Integer.parseInt goes in the wrong direction.


jshell> Integer.parseInt("1010111", 2)
$3 ==> 87

Look for the word "radix" on the page. We found this.


jshell> Integer.toString(1000, 3)
$4 ==> "1101001"

jshell> Integer.toString(1001, 3)
$5 ==> "1101002"

Check this out.


jshell> String s = "true"
s ==> "true"

Nope.


jshell> Boolean.parseBool(s)
|  Error:
|  cannot find symbol
|    symbol:   method parseBool(java.lang.String)
|  Boolean.parseBool(s)
|  ^---------------^

This works.


jshell> Boolean.parseBoolean(s)
$7 ==> true

jshell> Boolean.toString(true)
$8 ==> "true"

This works too.


jshell> "" + true
$9 ==> "true"

Let's be doubly sure.


jshell> String guac = "6.02e23"
guac ==> "6.02e23"

jshell> double avocado = Double.parseDouble(guac)
avocado ==> 6.02E23

Character os loade with useful stuff. Here are some items


jshell> Character.isDigit('7')
$12 ==> true

jshell> Character.isDigit('q')
$13 ==> false

Characters are two bytes wide. It's unicode. All wrappers have a BYTES constant.


jshell> Character.BYTES
$14 ==> 2

jshell> Integer.BYTES
$15 ==> 4

jshell> Long.BYTES
$16 ==> 8

Inbox me for a cast!


jshell> Character c = 'q'
c ==> 'q'

jshell> (int) c
$18 ==> 113

More useful stuff:


jshell> Character.isAlphabetic('5')
$19 ==> false

jshell> Character.isAlphabetic('a')
$20 ==> true

jshell> Character.isAlphabetic('A')
$21 ==> true

jshell> Character.isUpper('A')
|  Error:
|  cannot find symbol
|    symbol:   method isUpper(char)
|  Character.isUpper('A')
|  ^---------------^

jshell> Character.isUpperCase('A')
$22 ==> true

jshell> Character.isSpace(' ')
$24 ==> true

jshell> Character.isSpace('\n')
$25 ==> true

jshell> Character.isSpace('\t')
$26 ==> true

Here is what isLetter does.


jshell> for(char c = 'A'; c <= 'z'; c++)
           {
               System.out.printf("%s:  isLetter: %s\n", c, Character.isLetter(c));
           }
A:  isLetter: true
B:  isLetter: true
C:  isLetter: true
D:  isLetter: true
E:  isLetter: true
F:  isLetter: true
G:  isLetter: true
H:  isLetter: true
I:  isLetter: true
J:  isLetter: true
K:  isLetter: true
L:  isLetter: true
M:  isLetter: true
N:  isLetter: true
O:  isLetter: true
P:  isLetter: true
Q:  isLetter: true
R:  isLetter: true
S:  isLetter: true
T:  isLetter: true
U:  isLetter: true
V:  isLetter: true
W:  isLetter: true
X:  isLetter: true
Y:  isLetter: true
Z:  isLetter: true
[:  isLetter: false
\:  isLetter: false
]:  isLetter: false
^:  isLetter: false
_:  isLetter: false
`:  isLetter: false
a:  isLetter: true
b:  isLetter: true
c:  isLetter: true
d:  isLetter: true
e:  isLetter: true
f:  isLetter: true
g:  isLetter: true
h:  isLetter: true
i:  isLetter: true
j:  isLetter: true
k:  isLetter: true
l:  isLetter: true
m:  isLetter: true
n:  isLetter: true
o:  isLetter: true
p:  isLetter: true
q:  isLetter: true
r:  isLetter: true
s:  isLetter: true
t:  isLetter: true
u:  isLetter: true
v:  isLetter: true
w:  isLetter: true
x:  isLetter: true
y:  isLetter: true
z:  isLetter: true

Grinch Dog Time


jshell> Integer.MAX_VALUE
$27 ==> 2147483647

jshell> Integer.MIN_VALUE
$28 ==> -2147483648

jshell> Double.MAX_VALUE
$29 ==> 1.7976931348623157E308

Here are a few features of Double.


jshell> Double.isFinite(5)
$30 ==> true

jshell> Double.isFinite(1.0/0)
$31 ==> false

jshell> Double.isNaN(1.0/0)
$32 ==> false

jshell> 1.0/0
$33 ==> Infinity

jshell> Double.SIZE
$34 ==> 64

jshell> Double.BYTES
$35 ==> 8