Arrays & Collections
Arrays
Fixed length, zero-based:
int [] numbers = new int [ 5 ] ;
String [] colors = { "red" , "green" , "blue" };
colors . length // 3 — a field, not a method
colors [ 1 ] // "green"
colors [ 3 ] // ArrayIndexOutOfBoundsException
Arrays . sort ( numbers );
Arrays . toString ( numbers );
Arrays are rigid. In practice you use a List.
List
Ordered, resizable, duplicates allowed:
var names = new ArrayList < String > ();
names . add ( "Ann" );
names . add ( "Ben" );
names . get ( 0 ) // "Ann"
names . size () // 2
names . contains ( "Ben" ) // true
names . indexOf ( "Ben" ) // 1
names . remove ( "Ben" );
names . set ( 0 , "Anne" );
names . isEmpty ()
List<String> means “list of strings” — the compiler keeps everything else out. On the right
side the diamond <> is enough: List<String> names = new ArrayList<>();
var days = List . of ( "Mon" , "Tue" , "Wed" ); // immutable
days . add ( "Thu" ); // UnsupportedOperationException
var copy = new ArrayList <> ( days ); // mutable copy
Tip
Default to List.of(...). Immutable is the common case and prevents accidental changes.
for ( var name : names ) IO . println ( name );
for ( var i = 0 ; i < names . size (); i ++ ) IO . println ( i + ": " + names . get ( i ));
names . forEach ( IO :: println );
Set
No duplicates. HashSet (unordered), LinkedHashSet (insertion order), TreeSet (sorted).
var tags = new HashSet < String > ();
tags . add ( "java" );
tags . add ( "java" ); // no effect
tags . size () // 1
var a = Set . of ( 1 , 2 , 3 , 4 );
var b = Set . of ( 3 , 4 , 5 );
var intersection = new HashSet <> ( a ); intersection . retainAll ( b ); // [3, 4]
var union = new HashSet <> ( a ); union . addAll ( b ); // [1..5]
var difference = new HashSet <> ( a ); difference . removeAll ( b ); // [ 1 , 2 ]
Map
Keys → values, keys are unique.
var ages = new HashMap < String , Integer > ();
ages . put ( "Ann" , 30 );
ages . put ( "Ann" , 31 ); // overwrites
ages . get ( "Ann" ) // 31
ages . get ( "Zoe" ) // null
ages . getOrDefault ( "Zoe" , 0 ) // 0
ages . containsKey ( "Ann" )
ages . remove ( "Ann" );
Useful patterns:
counts . merge ( "java" , 1 , Integer :: sum ); // count things
counts . putIfAbsent ( "course" , 1 );
groups . computeIfAbsent ( "a" , k -> new ArrayList <> ()). add ( "Ann" );
for ( var e : ages . entrySet ()) IO . println ( e . getKey () + " " + e . getValue ());
ages . forEach (( name , age ) -> IO . println ( name + ": " + age ));
var capitals = Map . of ( "Germany" , "Berlin" , "France" , "Paris" ); // immutable
Which one?
Need
Type
ordered, duplicates ok
ArrayList
no duplicates, fast lookup
HashSet
no duplicates, sorted
TreeSet
key → value
HashMap
key → value, sorted
TreeMap
queue / stack
ArrayDeque
Records: bundling data
When values belong together, use a type — not a map:
record Person ( String name , int age ) {}
var ann = new Person ( "Ann" , 30 );
ann . name () // "Ann"
IO . println ( ann ) // Person [ name = Ann , age = 30 ]
You get the constructor, accessors, equals, hashCode and toString for free — which also
makes records good map keys:
record Coordinate ( int x , int y ) {}
var map = new HashMap < Coordinate , String > ();
map . put ( new Coordinate ( 1 , 2 ), "treasure" );
map . get ( new Coordinate ( 1 , 2 )); // "treasure" — different object , equal content
More on records in chapter 11 .
★ Exercises
Sum, average, min and max of ten numbers, using a loop.
Remove duplicates from a list — once with a Set, once by hand.
Count letter frequency of a sentence in a Map<Character, Integer>.
Build a phone book Map<String, String> with add, lookup and delete methods.
Define record Item(String name, double price, int qty) and total a cart of five items.
Turn a List<String> into a Map<Integer, List<String>> grouped by word length.