> For the complete documentation index, see [llms.txt](https://cs61b-2.gitbook.io/cs61b-textbook-2025/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cs61b-2.gitbook.io/cs61b-textbook-2025/10.-inheritance-ii-extends-casting-higher-order-functions/10.3-casting.md).

# 10.3 Writing a Max Function

We've seen that Java provides a nice `Collections.max` function for us. `Collections` also includes other handy functions like `min`, `sort`, and `reverse`.

In this chapter we'll see how we can write such functions ourselves.

## Generic Functions (Warumup)

As a warmup suppose we want a function which picks a random item from an array. Some code is shown below:

```java
public class RandomPicker {
    public static <T> T randomItem(T[] items) {
        Random random = new Random();
        int randomIndex = random.nextInt(x.length);
        return x[randomIndex];
    }
}
```

And a sample program that uses this function is given below:

```java
public class RandomPickerDemo {
   public static void main(String[] args) {
       String[] x = {"hi", "little", "cat"};
       System.out.println(RandomPicker.pickRandom(x));
   }
}
```

Next, we'll try to make it so that the `pickRandom` function can work on any type of array.

### Approach One: Generics

We can try to use Generics, as shown in the code below:

```java
public class RandomPicker<T> {
   public static T pickRandom(T[] x) {
       Random random = new Random();
       int randomIndex = random.nextInt(x.length);
       return x[randomIndex];
   }
}
```

However, this code doesn't really make sense as written. The `pickRandom` function is static, but we have to instantiate a `RandomPicker` object to specify the generic type. That is, we'd need to do something like:

```java
String[] x = {"hi", "little", "cat"};
RandomPicker<String> stringPicker = new RandomPicker<>();
System.out.println(stringPicker.pickRandom(x));
```

but we can't call static methods using an instance.

A fix for this is to make the `pickRandom` function non-static, as shown below:

```java
public class RandomPicker<T> {
   public T pickRandom(T[] x) {
       Random random = new Random();
       int randomIndex = random.nextInt(x.length);
       return x[randomIndex];
   }
}
```

If we do this our code will work fine, but it's still very awkward to have to instantate a picker object.

### Approach Two: Generic Static Methods

The correct and better approach is to make our static method generic. This is shown below:

```java
public class RandomPicker {
   public static <T> T pickRandom(T[] x) {
       Random random = new Random();
       int randomIndex = random.nextInt(x.length);
       return x[randomIndex];
   }
}
```

This syntax is confusing (and it'll get worse later!). The way you can read `public static <T> T pickRandom(T[] x)` is: "I am declaring a public static function that works on objects of type , it returns a T, it is called pickRandom, and it takes an array of Ts as its input.

After noting to Java that our static method is generic, we can call it without instantiating a `RandomPicker` object as shown below:

```java
public class RandomPickerDemo {
   public static void main(String[] args) {
       String[] x = {"hi", "little", "cat"};
       System.out.println(RandomPicker.pickRandom(x));
   }
}
```

Note that unlike generic classes, we don't need to specify the generic type when calling a generic static method (i.e. there's no `<String>` after `pickRandom`). The type is automatically inferred.

One minor annoyance is that our pickRnadom function will not work with arrays of primitive types, i.e. we can use `int[]`, `double[]`, `float[]`.

```java
public class RandomPickerDemo {
   public static void main(String[] args) {
       int[] x = {1, 2, 3, 4, 5, 6, 7, 8};
       System.out.println(RandomPicker.pickRandom(x));
   }
}
```

There's no way around this, and in fact real Java libraries often have multiple functions, one for each primitive type. For example, there exists `Arrays.sort(int[])`, `Arrays.sort(double[])`, `Arrays.sort(float[])`, etc. One day maybe Project Valhalla will fix this.

## Writing our Max Function, Type Bounds

Using the idea of a generic static function, we can write our max function as follows:

```java
public class Maximizer {
   public static <T> T max(T[] items) {
       T maxItem = items[0];
       for (int i = 0; i < items.length; i += 1) {
           int cmp = items[i].compareTo(maxItem);
           if (cmp > 0) {
               maxItem = items[i];
           }
       }
       return maxItem;
   }
}
```

There's one last problem, Java doesn't know that `T` has a `compareTo` method. We can fix this by adding a **type bound** to our generic type, as shown below:

```java
public class Maximizer {
   public static <T extends Comparable<T>> T max(T[] items) {
       T maxItem = items[0];
       for (int i = 0; i < items.length; i += 1) {
           int cmp = items[i].compareTo(maxItem);
           if (cmp > 0) {
               maxItem = items[i];
           }
       }
       return maxItem;
   }
}
```

This tells Java that `T`, whatever it is, has to implement `Comparable<T>`. If you try to pass an arary of objects into max that does not implement `Comparable<T>`, you'll get a compile-time error.

The way to read `public static <T extends Comparable<T>> T max(T[] items)` is: "I am declaring a public static function that works on objects of type , it returns a T, it is called max, and it takes an array of Ts as its input. Additionally, T has to implement Comparable."

### Bonus: An Even Better Type Bound

In real industrial strength Java code, the correct way to specify our method is:

```java
public class Maximizer {
   public static <T extends Comparable<? super T>> T max(T[] items) {
		...
   }
}
```
