KotlinCS 124 LogoJava
PrevIndexNext
Kotlin
Java
  • Implementing a Map : 04/26/2024

  • Streams : 04/25/2024

  • Generics : 04/24/2024

  • Hashing : 04/23/2024

  • Binary Search : 04/22/2024

  • MP3: Course Ratings : 04/19/2024

  • Quicksort : 04/18/2024

  • Merge Sort : 04/17/2024

  • Sorting Algorithms : 04/16/2024

  • MP Debugging Part 1 : 04/15/2024

  • MP2: Course Activity : 04/12/2024

  • Practice with Recursion : 04/11/2024

  • MP Debugging Part 0 : 04/10/2024

  • MP2: API Client : 04/09/2024

  • MP2: API Server : 04/08/2024

  • Trees and Recursion : 04/05/2024

  • Trees : 04/04/2024

  • Recursion : 04/03/2024

  • MP1: Filtering and Search : 04/02/2024

  • MP1: Loading and Sorting : 04/01/2024

  • Lists Review and Performance : 03/29/2024

  • Linked Lists : 03/28/2024

  • Algorithms and Lists : 03/27/2024

  • Continuing MP0 : 03/26/2024

  • Getting Started with MP0 : 03/25/2024

  • Lambda Expressions : 03/22/2024

  • Anonymous Classes : 03/21/2024

  • Practice with Interfaces : 03/20/2024

  • Implementing Interfaces : 03/19/2024

  • Using Interfaces : 03/18/2024

  • Working with Exceptions : 03/08/2024

  • Throwing Exceptions : 03/07/2024

  • Catching Exceptions : 03/06/2024

  • References and Polymorphism : 03/05/2024

  • References : 03/04/2024

  • Data Modeling 2 : 03/01/2024

  • Equality and Object Copying : 02/29/2024

  • Polymorphism : 02/28/2024

  • Inheritance : 02/27/2024

  • Data Modeling 1 : 02/26/2024

  • Static : 02/23/2024

  • Encapsulation : 02/22/2024

  • Constructors : 02/21/2024

  • Objects, Continued : 02/20/2024

  • Introduction to Objects : 02/19/2024

  • Compilation and Type Inference : 02/16/2024

  • Practice with Collections : 02/15/2024

  • Maps and Sets : 02/14/2024

  • Lists and Type Parameters : 02/13/2024

  • Imports and Libraries : 02/12/2024

  • Multidimensional Arrays : 02/09/2024

  • Practice with Strings : 02/08/2024

  • null : 02/07/2024

  • Algorithms and Strings : 02/06/2024

  • Strings : 02/05/2024

  • Functions and Algorithms : 02/02/2024

  • Practice with Functions : 02/01/2024

  • More About Functions : 01/31/2024

  • Errors and Debugging : 01/30/2024

  • Functions : 01/29/2024

  • Practice with Loops and Algorithms : 01/26/2024

  • Algorithms : 01/25/2024

  • Loops : 01/24/2024

  • Arrays : 01/23/2024

  • Compound Conditionals : 01/22/2024

  • Conditional Expressions and Statements : 01/19/2024

  • Operations on Variables : 01/18/2024

  • Variables and Types : 01/17/2024

  • Welcome to CS 124 : 01/16/2024

Lists and Type Parameters

import java.util.List;
import java.util.ArrayList;
List<String> strings = new ArrayList<>();
strings.add("test");
System.out.println(strings);
strings.add("me");
System.out.println(strings);

Next we’ll examine how to use Java’s lists. We’ve stored sequential data before in an array, but lists are more flexible and more suited to certain tasks.

Debugging Challenge
Debugging Challenge

But let’s start with some debugging practice!

Lists
Lists

Like arrays, lists are an ordered data structure. However, unlike arrays, the size of a list can change as the program runs. This makes them much more appropriate for solving certain problems.

Java has built-in lists. Let’s see how they work! (Feel free to open up the documentation as you follow along…)

import java.util.List;
import java.util.ArrayList;
// Java Lists

List Creation and Initialization
List Creation and Initialization

Like arrays, Java Lists store sequential data. However, the syntax for using them is a bit different. Let’s review the array operations we’re familiar with and show how they map onto Listss.

First, let’s show how we create an array and List, and check their size:

import java.util.List;
import java.util.ArrayList;
String[] array = new String[8]; // size cannot change
System.out.println(array.length); // .length property for arrays
List<String> list = new ArrayList<>(); // starts empty but can grow and shrink
System.out.println(list.size()); // .size() method for lists

Note that with the List, unlike the array we do not need to specify a size when we create the List. This is because the size of a List can change!

Next up, how do we initialize a list with a set of values and print its contents? This turns out to be a bit harder than you would like with Java Lists, and requires a separate import statement:

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
String[] array = {"1", "2", "4"}; // easy with arrays
System.out.println(array); // but doesn't print nicely
List<String> list = new ArrayList<>(Arrays.asList("1", "2", "4")); // ugly with lists
System.out.println(list); // but at least they print nicely!

List Get and Set
List Get and Set

Now that we have a List with a few values, how do we access them and modify them? With arrays we used bracket notation, but Lists work differently:

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
// bracket notation
String[] array = {"1", "2", "4"};
System.out.println(array[0]);
array[0] = "0";
System.out.println(array[0]);
// .get and .set operations
List<String> list = new ArrayList<>(Arrays.asList("1", "2", "4"));
System.out.println(list.get(0));
list.set(0, "0"); // .set(index, newValue)
System.out.println(list.get(0));

List Add and Remove
List Add and Remove

Now we get to something that arrays can’t do—modify their length! Java Lists provide both an add and a remove method. Let’s explore how they work:

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
List<String> list = new ArrayList<>(Arrays.asList("1", "2", "4"));
System.out.println(list);

Boxing and Boxing Classes
Boxing and Boxing Classes

Before we go on, a somewhat dull but important digression.

In the examples above we’ve seen how to create List of Strings:

import java.util.List;
import java.util.ArrayList;
List<String> values = new ArrayList<>();

But how would we create a list of int values? This doesn’t seem to work:

import java.util.List;
import java.util.ArrayList;
List<int> values = new ArrayList<>(); // fails

The problem here is that Java lists have to store objects, and if you remember from early in the course, int (and long and boolean, etc.) are primitive types. So we can’t store them in Lists. Uh-oh.

Happily, there’s a simple solution. For each primitive type Java provides a boxing class that is a object but can store an instance of a primitive type. The boxing classes have capitalized names that are usually the same as the primitive type, with two exceptions:

Thrilling, I know. But, happily, this now works:

import java.util.List;
import java.util.ArrayList;
List<Integer> values = new ArrayList<>();
values.add(1);
values.add(2);
values.add(4);
System.out.println(values);

Autoboxing
Autoboxing

Under certain conditions Java will automatically box (primitive to object) and unbox (object to primitive) values for you:

int i = 5;
Integer j = i * 2; // boxing int to Integer
int k = j + 1; // unboxing Integer to int
System.out.println(i);
System.out.println(j);
System.out.println(k);

But not always. In particular, arrays are not automatically boxed:

void printIt(Integer[] values) {
for (int i = 0; i < values.length; i++) {
System.out.println(values[i]);
}
}
printIt(new int[] {1, 2, 5});

Unlike their primitive types, boxing types can also be null:

Integer example = null;
System.out.println(example);
example = 0;
System.out.println(example);

Practice: Small Word Filter With Array

Created By: Geoffrey Challen
/ Version: 2021.9.0

Write a method called smallWordFilter that, given a non-null String containing words separated by single spaces (" "), returns all the words in the original String that are 3 characters or shorter in the same order in which they appeared in the original String, as a String[].

For example, given the input "Xyz is the very best cat" you would return the String[] {"Xyz", "is", "the", "cat"}. We have skipped both "very" and "best" because they are longer than 3 characters.

This is a problem that would be much easier to solve using a list, since you don't know exactly how many part of the input String are 3 characters or smaller! But this can be done with an array, if somewhat awkwardly. Here's a solution sketch to help you get started:

  1. Split the array based on the single space " "
  2. Next, count the number of parts of the String that are 3 characters or smaller
  3. Now create your String[] of the appropriate size
  4. And then loop again through the array of String parts filling your output array as you go

We've provided some starter code to help you get going on this problem.

String[] smallWordFilter(String words) {
String[] parts = words.split(" ");
int count = 0;
// count words that meet the criteria
String[] toReturn = new String[count];
// now populate the toReturn array
return toReturn;
}

Type Parameters
Type Parameters

The syntax that we introduce above is our first example of a Java type parameter:

import java.util.List;
import java.util.ArrayList;
List<String> strings = new ArrayList<String>();

The <String> on the left tells Java that this List variable will store Strings. And the <String> on the right tells Java to create a new ArrayList that will store Strings. If we wanted to store ints, we’d use <Integer> instead, for reasons that we explain below.

Usually these two types are the same, and so we can use the diamond operator for convenience:

import java.util.List;
import java.util.ArrayList;
// <String> on the left, but <> on the right
List<String> strings = new ArrayList<>();

It allows us to omit the String on the right side of this common expression, and saves us a few keystrokes.

Why do lists require a type parameter? It’s so that we can tell Java what we are going to put in them! Once we do, Java will help us avoid common mistakes:

import java.util.List;
import java.util.ArrayList;
List<String> strings = new ArrayList<>();
strings.add(1); // Can't add an `int` to a `List<String>`!

These mistakes are also caught before you program is run, at a step called compilation that we’ll explore later.

Type Parameters in Documentation
Type Parameters in Documentation

It’s important to understand how to identify type parameters when examining Java documentation. Let’s do that together next.

List v. ArrayList
List v. ArrayList

In the examples above we’ve used two imports: List and ArrayList:

import java.util.List;
import java.util.ArrayList;
List<String> values = new ArrayList<>();

This may seem a bit mysterious at the moment. And we won’t be able to fully explain this until a bit later. But there is a difference between the two, and a good reason that we use both and not just ArrayList, which some of you may have seen in previous courses. We’ll return to this topic later this semester.

Practice: Small Word Filter With List

Created By: Geoffrey Challen
/ Version: 2021.9.0

Write a method called smallWordFilter that, given a non-null String containing words separated a single space (" "), returns all the words in the original String that are 3 characters or shorter in the same order in which they appeared in the original String, as a List<String>.

For example, given the input "Xyz is the very best cat" you would return the List<String> containing {"Xyz", "is", "the", "cat"}. We have skipped both "very" and "best" because they are longer than 3 characters.

Note that you should not add any import statements, since both java.util.List and java.util.ArrayList are already available.

Untyped Lists
Untyped Lists

We will almost always be using type parameters with our lists! This help make them safer, since we are telling Java what we will put in and take out of the List.

However, Java will let you create an untyped List, and this is what will happen if you omit the <String> or <Integer> type parameter. Let’s discuss some of the problems that this can cause:

import java.util.List;
import java.util.ArrayList;

Overall we will avoid using bare or untyped lists and always provide type parameters when we use a List in our code.

Homework: Stop Shouting List Filter

Created By: Geoffrey Challen
/ Version: 2022.9.0

Text-based communication over the internet is great! But let's avoid shouting at each other—meaning communicating using all caps, LIKE THIS!

Complete a method named removeShouting that accepts a List<String> and returns a new List<String> where any shouty words have been de-shouted—meaning any words that appear in all caps have been converted to lowercase. For example, given the input {"Please", "stop", "SHOUTING"}, you would return the list {"Please", "stop", "shouting"}. Note that only words that appear in all caps should be converted to lowercase—so "SHOUTING" in the example above but not "Please". You'll want to investigate various String methods to help you out with this problem. You can assume that the passed List is not null.

As a side note for Java. Whenever we compare Strings in Java we should always get in the habit of using .equals, since this is the only approach guaranteed to be correct. However, in this problem you'll notice a place where you can use == in place of .equals and have your submission still work. If you're curious about why this is the case, ask on the forum. We were surprised to observe this behavior ourselves, but it makes at least a certain amount of sense.

CS People: Reshma Saujani
CS People: Reshma Saujani

Having a technical background isn’t a requirement for helping drive positive change in technology. Illini Reshma Saujani earned undergraduate degrees in Political Science and Speech Communication here at the University of Illinois, and graduate degrees from Harvard’s Kennedy School and Yale Law School. While a practicing lawyer and political aspirant, Saujani noticed the gender disparity in high school computer science classrooms, which caused her to found Girls Who Code in 2012 to encourage women to pursue technical careers.

She’s also spoken and written about female empowerment in the workplace. Her latest book, “Pay Up” was informed by her experience during the pandemic, and identifies structural forces in the American workplace that are harming women:

More Practice

Need more practice? Head over to the practice page.