An alternative way to create routine tasks for FacileThings in just 2 steps

This is the third (and last, for the moment) post in a series that aims at making up for the functions I hope to see implemented in FacileThings. In the previous posts, I’ve shown you How to Integrate FacileThings into Google Assistant and How to Set Up a Quick Collect Widget for FacileThings. This time the focus will be on the creation of an alternative way to create routine tasks.

The Routines function is one of the best implementations of recurring tasks I’ve encountered so far, but (there’s always a but”) I’d like to have more control on when the task is going to show up in my todo list.

Let me explain. I have an evening routine with a checklist of things that I need to handle the next day; it’s something I have to do daily, but in the evening, I know that and I don’t want it to show up during the day, when it’s not actionable or meaningful: I just want to see it in the evening.

In FacileThings you can choose the day(s) that the task will show up, but not the time. Again, the Routines function is great as is, this is just me being too demanding.

How could I implement a routine task that shows up at a certain time? As usual, using the FacileThings Capturing by email function (another great I-couldn’t-live-without function), Gmail and IFTTT.

STEP 1: Create an IFTTT account

Really? At this point, you still don’t have an IFTTT account? Just create the account, you’ll love it!

STEP 2: The Routine task with checklist for FacileThings”

Open the simple IFTTT applet I’ve developed. Now you’ll have to click on the Turn on” button, then IFTTT will ask for permission to access your Gmail account.

In the Every day of the week at” section, select the day and time for when you want your task to show up on your todo list.

In the Send an email” section, change the Subject replacing the placeholder [task_name_and_context] with the appropriate task name and context  (for example: Ask John for advice #calls). Optionally you can write your checklist items in the body: be sure to add the HTML tag <p> before each of them.

HAPPY ENDING

Now your routine is set up and good to go. Your task will show up according to the schedule of your choice.

Did you encounter difficulties of some sort? Do you have suggestions to improve this solution? Please, let me know in the comment section.

tutorial how to facilethings ifttt

3 little steps to make your Huawei phone awesome

Last January I decided to leave the iPhone for an Android phone. I needed a dual SIM phone with a good camera, Huawei Mate 10 Pro seemed a perfect choice.

It’s really a wonderful device, but the EMUI is really ugly.

EMUI (Emotion UI) is the Huawei personalization of Android. Its look & feel is quite dated and the overall experience is really poor.

I knew at first glance that I had to do something to fix this. Let’s see how I’ve done it.


STEP 1: Install a theme that mimics Android AOSP

EMUI theme chooser screenEMUI theme chooser screen

Fortunately, EMUI has some merits, one of them is that it supports themes. I love Androids look & feel, so I looked for some themes that could mimic it.

Again, I had to do some research, but in the end, I found some wonderful themes in the Google Play Store. Hamzio7s and App_Labs are the better ones. Currently, I’m using App_Labs G-Pix [Android P] EMUI 8/5 THEME with the icons from Hamzio7 Pure AOSP EMUI 5.X/8.0 Theme.


STEP 2: Install Nova Launcher

The themes are really good to improve the system UI, but they can’t do much for the stock launcher, so the better option is to install a third party one and Nova Launcher from TeslaCoil Software, in my opinion, is still the better option.

Once installed, I tweaked some options to my taste.

Reshape Legacy Icons options screenReshape Legacy Icons options screen

First of all, I activated the Reshape Legacy Icons option, so that the launcher will reshape or add a background to all the icons that don’t match my shape of choice (I chose to have rounded icons like in the Pixel phones). That gives a beautiful sense of consistency. You can find this option in Nova Settings -> Look & Fill -> Adaptive Icon Style.

Search Bar Style options screenSearch Bar Style options screen

Then I added Google Search Pill on the desktop, you could also place the search bar under the dock, like in the Pixel phone, but I like the Pill better. You can play with these options in Nova Settings -> Desktop -> Search Bar Style.

I also tweaked many other parameters (icons size and labels, drawer background, etc.) to make the launcher appearance exactly like I wanted. Nova Launcher is very customizable so I encourage you to play with it. Make sure to backup your settings, so you can restore the previous configuration if you don’t like what you have done while experimenting.


STEP 3: Install Nova Google Companion

The EMUI stock launcher supports the integrated Google Now page, Nova Launcher doesn’t. To have this feature you have to install Nova Google Companion. This app isn’t in the Play Store, but you have to download it from TeslaCoil Softwares website.

Integrations options screenIntegrations options screen

Once you have installed it, you can tweak its settings in Nova Settings -> Integrations.

Now your Huawei phone is really awesome!

tutorial how to android emui huawei nova launcher theme

How to setup a Quick Collect widget for FacileThings

This is the second post in a series that aims at making up for the functions I hope to see implemented in FacileThings mobile app. In the previous post I’ve shown you how to integrate FacileThings into Google Assistant, this time the focus will be on the creation of a Quick Collect widget.

If you want to collect some ideas in your inbox using a mobile phone, you have to tap on the FacileThings icon, wait for the app to startup and synchronize, then you have to tap on the Collect” button and only now you can write down what’s on your mind. I’d like to have a faster option… and I can have it, thanks to the FacileThings Capturing by email function, Gmail and IFTTT.


STEP 1: Create an IFTTT account

You don’t have a IFTTT account yet? Just create an account, it’s super useful!


STEP 2: Install the IFTTT app

Now you have to install the IFTTT app for Android or install the IFTTT app for iOS. Which one should you choose? It depends on what phone you’re using, obviously!


STEP 3: The Quick Collect widget for FacileThings”

Open the simple IFTTT widget applet I’ve developed. Now you’ll have to click on the Turn on” button, then IFTTT will ask for permission to access your Gmail.


STEP 4: Add the widget to your phone

Activate the widget on your phone. You don’t know how to do it? Follow the guide How do I manage or add new Applet widgets on my mobile device? in the IFTTT Help Center.


HAPPY ENDING

Now you’re good to go: tap on your new widget, write down whatever you like, tap on the Send” button and it’s done!

Please be aware that this widget only works while your phone is online!

Did you encounter difficulties of some sort? Do you have suggestions to improve this solution? Please, let me know in the comment section.

tutorial how to facilethings ifttt widget

How to collect stuff to your FacileThings inbox using Google Assistant

FacileThings is one of the best GTD applications out there. Unfortunately, its mobile app lacks some useful features like a widget or integration with Google Assistant. Fortunately, I’ve got good news: we can use third-party tools and a little creativity to implement some workarounds and get a better experience with FacileThings.

In this first post, I’ll show you how to integrate FacileThings with Google Assistant. We’ll use: FacileThings Capturing by email function, Gmail and IFTTT (If This, Then That), to get it done. IFTTT is a well known web-based service that lets you connect different apps together using applets (or recipes).

Now let’s start!


STEP 1: Create an IFTTT account

Go to IFTTT and create an account. You can quickly join using your Google or Facebook account… or you can manually enter your data in a good old-fashioned way. Obviously, if you already have an account, just go to…


STEP 2: The Add a task to your FacileThings inbox using Google Assistant” applet

This is quite simple: just open the simple applet I’ve developed. Now you’ll have to click on the Turn on” button, thenIFTTT will prompt you to grant it permission to access your Google Assistant and Gmail.


STEP 3: Customize the applet

Now IFTTT will show you the applet configuration form and let you customize it. By default this applet will be triggered by the following three variations of the phrase:

  1. collect $

  2. add $ to my task list

  3. add $ to FacileThings

where $ is the placeholder for the text that will be added to your inbox. Feel free to change them with any phrase you like, but be sure to add the $ and avoid anything that might overlap with already existing Google Assistant commands.


HAPPY ENDING

Now you’re good to go, just say: OK Google, collect…” followed by the stuff you want in your inbox.

Did you find difficulties of some sort? Do you have suggestions to improve this solution? Please, let me know in the comment section.

howto tutorial gtd productivity facilethings google assistant ifttt

How I’ve configured Todoist for GTD

In the last month, I’ve been looking for a GTD software. Getting Things Done, The Art of Stress-free Productivity, is a time-management method developed by productivity consultant David Allen; you can read more about it on the Getting Things Done website.

I’ve tried several different applications and Todoist, is without any doubt the best all-round task manager among them, but I ended up using FacileThings because it’s built around the GTD methodology, while Todoist needs some configuration effort and some workaround to be used this way. I’ll write about FacileThings on some other occasion, but now I’m going to explain how I’ve set up Todoist according to GTD methodology.


AREAS OF RESPONSIBILITY AND PROJECTS

I’ve used Todoists Projects to implement two different GTD concepts: Projects (every task that needs multiple steps to be accomplished) and Areas of Responsibility (the different aspects of your life). I’ve created the first layer of projects, representing the Areas of Responsibility:

Projects in Todoist used as Areas of ResposibilityProjects in Todoist used as Areas of Resposibility

As you can see, I wrote them in uppercase in order to differentiate them from the real projects.

For each Area of Responsibility, I’ve created the real GTD projects related to that area:

Projects in TodoistProjects in Todoist

Every project has the same color as its Area of Responsibility. To have a clearer vision, you can add a comment to each Area and Project to clearly describe its nature or desired outcome.


CONTEXTS

GTD defines as Contexts the physical place, tool or situation needed to perform that task. The Todoists Labels are basically tags and can be used to implement the Contexts.

Labels in Todoist used as ContextsLabels in Todoist used as Contexts

I’ve chosen the same color for every Context because I intend to create other Labels for different purposes (in the next paragraph).

NOTE: The Labels feature is only available in Todoist Premium.

TASKS

In Todoist, every task is displayed in the Inbox until it’s associated to a Project, so I assign the single action tasks that do not fit in any Project directly to the appropriate Area of Responsibility.

Tasks in TodoistTasks in Todoist

According to GTD methodology, it’s possible to assign additional information to a task, like the expected duration or energy required, in order to ease the choice of the task to be performed in a specific moment. I’ve created some other Labels to implement this data.

Labels in TodoistLabels in Todoist

A Routine (or repetitive task) can easily be created by setting up the schedule field using natural language — GREAT feature!

Recurring tasks in TodoistRecurring tasks in Todoist

This way, you focus on the tasks of a specific Area of Responsibility by selecting it, or on the task of my current Context by selecting its Label. You can also set up complex Filters using natural language.


TICKLER FILE

The Tickler File allows you to put a piece of information aside and display it again at a specific date that’s more convenient for you. I’ve implemented it using Google Calendar and IFTTT.

In Google Calendar, I’ve created a new calendar named Tickler. I usually keep it hidden; when I need to add something to my Tickler File, I enable it and create an event for the date in which I want to see that information.

In IFTTT I’ve created an applet, connected to the Tickler calendar, which creates a new task in the Todoist inbox when an event starts.

Easy peasy.


CONCLUSION

As you can see, in this implementation there’s everything you need to practice GTD, and Todoist has a lot of great features and great apps (web, Android, iOS, Windows); unfortunately, in the end, I’ve found this solution too high-maintenance, at least for me. FacileThings offers a less satisfying UX, but it’s built for GTD and it forces you to operate according to the methodology; I think that’s a great help for someone (like me) that has just started with GTD and is struggling to put it into practice.

howto tutorial gtd productivity facilethings todoist

Advanced Generics

Overview

I’m sure that as a Java developer, you’re familiar with using generics. For example, when you work with a collection such as an array list, you use generics to specify the type of the elements in the array list. If you want to become an advanced Java developer, then you will need to understand generics in more depth than just how to use them for collections. In this module, we will first take a look at how to define your own generic types. You’ll learn how to specify type parameters, how generic types are instantiated into parameterized types, and how you use type arguments. Besides generic types, you can also define generic methods. You will learn how to define and use generic static and generic instance methods. Next, we’ll look at specifying bounds on type parameters and for what situations this is useful. After that, we will briefly talk about raw types. It’s important to understand how generics work with inheritance. You will learn that generic types are invariant and you’ll see why this makes sense and what consequences this has. Another big topic with regard to generics, and which in my experience not many Java developers understand really well, is wildcards. One of the most frequently asked questions with regard to wildcards is why you cannot add elements to a list with the unbounded wildcard denoted by the question mark. After this module, you will be able to answer this question. Wildcards can have upper bounds, as well as lower bounds. You’ll learn what that means exactly and what it is useful for. To become really proficient at using generics, you’ll need to understand how the compiler deals with them, which is through the process of type erasure. In order to understand and explain certain limitations of generics, you’ll need to understand how this works. Finally, you’ll learn why generics and arrays don’t work very well together and what issues can occur when using generics with variable arguments. Let’s start with defining your own generic types.

Explanation: Defining Generic Types

Let’s go over the example again and explain it in detail so that you understand exactly what we did and what the relevant terms mean. First, the interface TreeNode and the classes InnerNode and LeafNode that we defined are generic types. A generic type is a type that has type parameters. The capital letter T between angle brackets that we used in the definition of the interface and the classes is a type parameter. A type parameter is really a placeholder for an actual concrete type. Inside the generic type, you use the type parameter as if it’s an actual type. For example, in interface TreeNode, we used T as the return type of the getValue method, and in class LeafNode, we used it as the type of the value field. When you start using generic types as we did in the example class, then you fill in the type parameters with type arguments. In the example, we created a binary tree with integer values, so we used Integer as a type argument here to fill in the type parameter T. When you use a generic type with specific type arguments, then what you are doing is called instantiating the generic type. When you instantiate a generic type, what you get is a parameterized type. For example, in the main method of the example class, we created a LeafNode. What we did here is instantiate the generic type LeafNode with the type Integer as a type argument. The result of that instantiation is the type LeafNode, which is a parameterized type. Note that you have to be very careful here with understanding what I mean with the word instantiate when I talk about instantiating a generic type. When I mentione the word instantiate, you most likely think that it means creating a new object. In the line of code in the example here where we instantiate the generic type LeafNode into the parameterized type LeafNode, we are at the same time creating a new object of this parameterized type, but there are really two different things going on here that are both called instantiating. First, there’s instantiating at the type level. This is where we create the parameterized type LeafNode out of the generic type LeafNode. Second, there is creating an instance at the value level. This is where we create a new object of the type LeafNode. As you can see, with generic types there’s really a parallel world at the type level of concepts that you already know at the value level. At the value level, you can define methods and constructors with value parameters. When you call these methods and constructors, you supply arguments, which are actual values that fill in the parameters. The term instantiating at the level of values means creating a new object. At the type level, you can define generic types with type parameters. You can instantiate a generic type, which means that you create an actual type out of it, which is a parameterized type. When you do that, you fill in the type parameters with specific type arguments. Now I want to make a note about the terms parameters and arguments. People often confuse these terms and use one while they really mean the other, but they actually mean slightly different things. A parameter is a placeholder for a value or type that is fulfilled with an argument later on. When you define a method or a constructor or a generic type, then you specify parameters. When you call the method or constructor or instantiate the generic type, then you specify arguments for the parameters, which are the actual values or types that will be used for that specific goal or instantiation. This first example was simple, but we took some time to carefully discuss how it works and defined the terminology because it’s important for you to have a strong foundation for what’s coming later in this module. This sentence sums it up. A generic type is a type with type parameters, which is instantiated into a parameterized type by supplying type arguments to fill in its type parameters. There are a few more points to mention about defining generic types, and then we’ll discuss some practical use cases. First, we used a single capital letter T for the name of the type parameter in our generic types. Using single capital letter names for type parameters is a convention in Java. When you look at the generic types in the standard library, you will see that they often use T, which stands for type. Another example is a type map, which has two type parameters named K and V, which stand for key and value. Because it’s such a widely used convention, some people think that it’s required to use single capital letters for the names of type parameters, or conversely that when something has a single capital letter as a name, it must be a type parameter, but that’s not the case. Single capital letter names for type parameters are just a convention. Second, for type arguments, you can only use reference types and not primitive types. For example, it’s not possible to create a list of the primitive type int. You will need to use the corresponding wrapper type for the primitive type, so it would have to be a list of the wrapper type integer. Third is that most kinds of types can have type parameters, but there are some exceptions. In the example, we created a generic interface and two generic classes. Also, records and nested types, including static nested classes, inner classes, and local types, can have type parameters. There are three exceptions, which are anonymous inner classes, enums, and exception types, which are all types that directly or indirectly extend class Throwable. Finally, let’s talk about practical use cases for generic types. One major use case for generic types is generic data structures, which is exactly what it’s used for in the standard collections interfaces and classes and also what we’ve used it for in our first example. Another use case is for code reuse, for example in an abstract superclass. One example that I remember from my own experience is when I was working on an application that had two similar screens in which the user had to answer a question by selecting one answer out of a set by using radio buttons. One screen was for one particular kind of contract with a particular set of possible answers to the question, while another screen was for a different kind of contract with different answers to the same question. Because the screens were so similar, I created an abstract superclass and two subclasses, one each for the two screens for the different kinds of contracts. For the answers to the question, there were two different enums. The abstract superclass had a type parameter and the two subclasses extended the superclass with the appropriate enum as the type argument. That way, the abstract superclass could present the values of the appropriate enum as possible answers on the screen. The abstract superclass allowed me to reuse most of the code for the two screens, so I didn’t have to copy and paste my code.

Defining Generic Methods

Besides generic types, there are also generic methods. In other words, not only types can have type parameters, methods can also have type parameters. Let’s take a look at some examples of generic methods. Let’s start this example by defining a generic record named Pair with two type parameters, T and U. The record will have two components named first and second of types T and U. This record represents a pair of two values of arbitrary types. Now, let’s add a static factory method with type parameters to this record. The way we define it is as follows. First we write the access specifier public and then static. Now before we write the return type of the method, we specify the type parameters between angle brackets. For this method, we need two type parameters, which we will call V and W. Then, as usual, we specify the return type, which is Pair<V, W> followed by the name of the method, the parameter list, and finally the body between curly braces. When you compare it to the definition of a non‑generic method, what’s new here is the list of type parameters which comes immediately before the return type of the method. Let’s now switch to an example class with a main method and see how we can call this generic method. The syntax for calling the of method looks like this. Since this is a static method, we are going to call it on the type Pair, so we first write Pair, then there’s a dot followed by the type arguments between angle brackets and then the name of the method and the value arguments between parentheses. This is the full syntax for calling a generic method where we explicitly specify the type arguments. Most of the time, however, you don’t need to specify the type arguments because of type inference, which means that the compiler automatically determines the type arguments. Let’s create another pair by calling the of method, but without specifying the type parameters. The compiler automatically understands that we want to create a pair of integer and string here, which it uses from the types of the value arguments. Note that we don’t even have to use the diamond operator here, which we had to do when we created a new object from a parameterized type. Let’s take a look at the definition of the of method again. You might wonder why it needs its own type parameters V and W when it’s defined inside the record that already has type parameters T and U. That’s because it’s a static method, and static methods don’t have access to the type parameters of their enclosing type. There’s, of course, a good reason for this. To understand this, remember what I said about the parallel worlds that exist between the type level and the value level. You know that at the value level, static methods belong to the class itself and are not associated with a particular instance of the class. That’s why a static method cannot access the instance members of the class. Now, think about how this works at the type level. Just like at the value level, static methods belong to the generic type itself and not to a particular instantiation of the generic type. Note that when I talk about the type level with the word instantiation, I don’t mean an object, but a particular parameterized type, which is an instantiation of a generic type. I use the word instantiation instead of instance here to indicate a difference between them. Exactly like a static method cannot access non‑static members of its enclosing type, it cannot access the type parameters of its enclosing type. You can see the type parameters of the enclosing type as being non‑static at the type level. Now, let’s add two wither methods to the record pair named withFirst and withSecond. These are both regular non‑generic methods. Note that these methods can access the type parameters of the enclosing record. That’s because they will always be called on a particular object that’s an instance of a particular parameterized type, which is an instantiation of the generic type Pair. Finally, let’s add a generic instance method to the record pair. We’ll create a method named map that has two type parameters, V and W, and that returns a pair of V and W. It will take one value argument, which is a BiFunction. A BiFunction represents an arbitrary function with two parameters and that returns a value. In this case, we want a function that takes two values of the types T and U and it returns a pair of V and W. The body of this method is very simple, we just apply the function to the two components of the Pair and return whatever the function returns. Note that the map method has its own type parameters, V and W, but it can also use the type parameters T and U of the generic type Pair because it’s an instance method. Let’s finish with an example of how you call the map method. Because it’s a regular instance method, we can call it on any Pair object. Let’s call it and pass a lambda expression that returns a new Pair with the two components of the pair reversed. Note that in this line we are again relying on type inference. If you wanted to write out this line fully, it would look like this. What we’re doing here is that we start with a Pair of Integer and String and then we swap the components so we end up with a pair of String and Integer. So if we would have to specify the type arguments of the parameters V and W, they would have to be String and Integer. Next we should specify the types of the parameters of the lambda expression explicitly, which should be Integer left and String right. And finally, inside the lambda expression we are calling the generic static of method. We should specify String and Integer as the type arguments for that method as well. As you can see, fortunately we have type inference, which allows us to omit the type arguments most of the time, and that makes this code easier to write and read.

Bounded Type Parameters

In the examples we’ve worked with so far, we define genetic types and methods with unbounded type parameters. This means that there are no restrictions on the types that can be used as type arguments for those type parameters. Sometimes it’s useful to be able to put restrictions on the types that can be used as type arguments. Let’s look at examples of how this works and what it is useful for. We’ll start with the generic interface TreeNode from the first example of this module. Suppose that for the type parameter T, we only want to allow types that implement interface Comparable. Let’s first see how to do this and then we’ll get to why in a moment. How we do this is by adding an extends clause to the type parameter, so we write T extends Comparable. Note that interface Comparable is itself a generic type, so we have to pass it a type argument, which in this case consists of our own type parameter T. Now, let’s look at the classes that implement interface TreeNode because we need to make some changes there too. First, class LeafNode. At the moment when we try to compile this, we get an error from the compiler that says type argument T is not within bounds of type‑variable T. This happens because interface TreeNode now requires its type argument to be a type that implements interface Comparable, but class LeafNode has no restrictions on its type parameter. One thing to be aware of here is that the type parameter T of class LeafNode and the type parameter T of interface TreeNode are not the same parameter. They are different type parameters defined on the two different types, LeafNode and TreeNode. They just happen to have the same name, T. In the definition of class LeafNode, we are using the type parameter T of this class as the type argument that we pass to interface TreeNode. Interface TreeNode requires its type parameter T to extend Comparable, which the type parameter of class LeafNode doesn’t do. Solving this error is easy, we just have to put the same bound on the type parameter of class LeafNode. Now let’s take a look at class MaxValueInnerNode. Recall that in the earlier example, we had a class InnerNode with a getValue method that returned null. In this example, I’ve renamed the class and we are going to implement the getValue method differently. What I want the getValue method to do in this example is look at the values of its left and right child nodes and then return the largest of the two values. Here is why we wanted to put the bound on the type parameter T. To be able to determine which value is largest, we need the type T to implement interface Comparable. This enables us to call the compareTo method. To finish this example, let’s create a tree with some MaxValueInnerNodes and some LeafNodes. Let’s get the value from the tree and print it. When I run it, it will print 5, which is indeed the largest value of any of the Leafnodes.

Multiple Type Parameter Bounds

Let’s look at one more example. In this example, we’ll define a generic method with type parameter bounds, and not only that, we’ll also learn how to apply multiple bounds to a type parameter. We start with a Product record, exactly like we had earlier. Suppose that we want to write a method that takes a list of products, sorts the products by ID, and then returns a list containing the names of the sorted products. Let’s start by writing a regular non‑generic method to do this. We’ll call it sortByIdAndExtractNames. In the main method, let’s create a list of products and then call this method and print a result. As you can see when I run it, it does what it’s supposed to do. Now this method is written to work only with products. Suppose that we want to make it more generally useful so that it can be used with any type that has an ID and a name instead of just Product. First, to be able to express the ideas any type that has an ID and any type that has a name, let’s define two simple interfaces. I’ll define an interface named HasId that has a method named Id and an interface named HasName that has a method named name. Next, I’ll make the Product record implement these interfaces. Since Product has components named id and name, we don’t have to do anything else here. The automatically generated accessor methods for these components match with the names of the method in the interfaces, so the accessor methods will serve as the implementation of the methods defined in the interfaces. Now let’s get back to the method sortByIdAndExtractNames. I want to make this a generic method that can be used with any type that implements both interfaces, HasId and HasName. The way we can do that is as follows. First, I’ll add a type parameter to the method. Then, I’ll add an extends clause to the type parameter. To specify multiple bounds, I write HasId, followed by an ampersand, and then HasName. This means that the type T must now be a type that implements interface HasId and implements interface HasName. Next, we change the type of the value parameter of this method from List to List. We also have to make some changes to the implementation. Instead of method references to the methods of type Product, I have to use method references to the methods of the interfaces HasId and HasName now. Now we’ve reached the goal. The method sortByIdAndExtractNames can now be called on any list of objects of a type that implements both interface HasId and interface HasName. There are a few remarks to make to complete this topic. In the example, we used two interfaces, which we used as bounds on the type parameter. It’s also possible to use a class as the bound and potentially multiple interfaces. If you use a class and one or more interfaces of bounds, then you must list the class first and then the interfaces, separated by ampersands in the extends clause. Another point is that you can only specify an intersection of types and bounds and nothing else. The ampersand, which you can read as meaning and, maybe makes you wonder whether you can also use a pipe symbol to represent or. In other words, that would mean that the type T should be a type that implements one interface or another interface. Such a type would be a union type instead of an intersection type. That is not possible, however, Java does not support union types.

Raw Types

Let’s briefly discuss raw types. A raw type is a generic type that is used without type arguments. For example, it’s possible to declare a variable of the generic type List without specifying type arguments and initialize it by creating a new instance of the generic type ArrayList without specifying type arguments. The ArrayList that you create this way provides almost no type safety. You can put any type of object in this list and nothing in the code tells you what the type of the elements is supposed to be. When you get an object out of the list and you want to work with it, you’ll need to cast it to the expected type. If at runtime the object is not of the type that you think it is, you will get a ClassCastException. Raw types seem useless, and you’re right, they are useless. You should always avoid using raw types in your Java code. The only reason why raw types exist at all in Java is because of backward compatibility. Generics have not existed in Java since the beginning. They were added to Java a long time ago with the release of Java SE 5 in September 2004. The companies that have owned and maintained Java over the years have always taken backward compatibility very seriously, so when generics were added, raw types were allowed to prevent code written for older versions of Java from breaking. The time when Java didn’t have generics is far behind us. It’s unlikely that you’ll ever work with code that is so old that you are required to deal with raw types. So now you know what raw types are, and the only important thing that you need to know is never use raw types.

Generics and Inheritance

The next subject we’ll discuss is how generics behave with regard to inheritance. You will learn that generics are invariant. In object‑oriented programming, when one type is a subtype of another type, then it normally means that there is an is a relationship between the subtype and its super type. In this example, I’ve created an interface Animal and two records, Dog and Cat, that implement the interface. Obviously dogs and cats are both animals, and this is reflected in a code by the fact that the records implement the interface. So the types Dog and Cat are both subtypes of the type Animal. Now we can make a list of dogs and put some dogs into this list. Next, think about the following question. When a dog is an animal, does that also mean that a list of dogs is also a list of animals? At first sight, it seems like the answer to that question is yes. When a dog is an animal, then obviously a list of dogs is also a list of animals. Translated into code, that means that we should be able to declare a new variable of type List and initialize it by assigning the list of dogs to it. This should work just like we can assign a dog to a variable of type animal because a dog is an animal. But surprisingly, we get an error when we try this. The error message says incompatible types: list of dog cannot be converted to list of animal. So it looks like Java does not agree that a list of dogs is a list of animals. The reason for this is that generics are invariant. To define this exactly, this means that if two types, S and T, have an inheritance relationship where S is a subtype of T, then if you use S and T to instantiate a generic type X, the resulting parameterized types, X of S and X of T, do not have an inheritance relationship. Invariance is just one of three types of variance that are possible. The other two are covariance and contravariance. I won’t explain these in detail right now, but I will say that what we initially might have expected, which is if a dog is an animal, then a list of dogs is also a list of animals, is covariance. The question for now is why generics are invariant and not covariant. Intuitively, it seems to be wrong that a list of dogs is not a list of animals, but there’s actually a very good reason for it. The thing is that if generics were covariant, then the compiler would let us do things that should not be possible. Let’s continue with the example to see what I mean. Suppose the generics would be covariant, then this assignment would be possible. And since a cat is also an animal, we could add a cat to the list as well. But note that although the type of the variable is List, the type of the actual list that it refers to is List. In other words, if this would be allowed, then we would be able to add a cat to a list of dogs, and that would be very strange. So now you understand that generics are invariant, which means that an inheritance relationship between type arguments does not carry over into parameterized types. The example clearly explained why generics are invariant even though it seemed counterintuitive at first.

Wildcards

The next subject to discuss is wildcards. As I mentioned in the overview of this module, I think that this is a feature of generics that not many Java developers understand really well. To make sure that you learn this properly, let’s be very careful with sorting out what wildcards are and how you use them. First, we will look at the definition of terms that have to do with wildcards, and then we’ll take a look at what wildcards are useful for and how they are used in practice. Let’s start with the question, what is a wildcard? A wildcard is a way to refer to a family of types. By a family of types, I mean a set of types that are related to each other in some way. There are three kinds of wildcards. There is the unbounded wildcard, which you write as a question mark. It refers to the family of all types. There’s the upper bounded wildcard, which you write as ? extends SomeType. This refers to the family of types that are subtypes of the specified type, including the type itself. And finally, there’s the lower bounded wildcard, which you write as ? super SomeType. This refers to the family of types that are super types of the specified type, again including the type itself. Wildcards are used to declare wildcard parameterized types. Now the next question is, what is a wildcard parameterized type? Remember that a parameterized type is a type that you create from a generic type by applying type arguments to the generic type. For example, the type List is a parameterized type created from the generic type List by applying String as a type argument to it. Besides concrete types such as string, you can use wildcards as type arguments. When you use wildcards for one or more of the type arguments when you instantiate a generic type, then what you get is a wildcard parameterized type. So, now we can conclude that there are two kinds of parameterized types. The first kind are concrete parameterized types, which are parameterized types in which the type arguments are all specific types. A concrete parameterized type is a single specific type that is fully defined. The second kind are wildcard parameterized types. In contrast to concrete parameterized types, a wildcard parameterized type is not fully defined. It’s not a particular single type, but it’s a type that matches a family of parameterized types. A wildcard matches a family of types, and therefore a wildcard parameterized type matches a family of parameterized types. The kind of wildcard that’s used determines what parameterized types match with a wildcard parameterized type. For example, the wildcard parameterized type List matches all parameterized types, List of some arbitrary type. The wildcard parameterized type List matches all parameterized types, List of some type that extends Animal or List itself.

Wildcard Capture

You know that Java supports subtyping, which means that if you have a variable of type T, and S is a subtype of T, then you can assign an object of type S to the variable. For example, when you create a variable of type Animal, you can assign an object of type Dog to that variable because Dog is a subtype of Animal. This works in a similar way with wildcard parameterized types. If you have a variable of a wildcard parameterized type, then you can assign any object to it that is of a type that matches the wildcard parameterized type. For example, if I have a variable of type List, and we tried to assign a list of dogs to it. You discovered that that didn’t work because generics are invariant, which means that a list of dogs is not a list of animals. Now take a look at what happens when we use a wildcard parameterized type. Let’s declare a variable of type List. Pay attention here because with this example, we are coming across what I think is a big misconception that many developers have about wildcards. First, the type List can contain both Dog and Cat objects. Now, the type List of extends Animal is something different. It is a list of objects of a particular but unknown type that extends the type Animal. This list can only contain objects of that particular type. In this example, we assigned a list of dogs to the variable, so we know that the unknown type is, in fact, the type Dog. The wildcard that we declared the variable with hides this fact. By just looking at the type of the variable, you cannot tell what the exact type of the objects in the list is. Let’s now see what happens when we try to add a Cat to this list. We get an error message that says incompatible types: Cat cannot be converted to capture#1 of ?extends Animal. That looks a bit cryptic. What does capture1# of ? extends Animal mean? That name is the name of the capture of the wildcard. The capture is the particular unknown type that a wildcard stands for. So what this error message is telling us is that for the argument of the add method, the compiler expects us to supply a value and it expects the type of that value to be the capture of the wildcard. The compiler complains that instead of such a value, we gave it a value of type Cat, which is the wrong type. Note that although we know that this variable really refers to a list of dog objects, we still cannot add a Dog to this list. When we try, we get exactly the same error message as when we tried to add a Cat. The reason for the error is, of course, also exactly the same. The compiler expects us to supply a value that is of the capture type of the wildcard. The capture type is, however, some unknown type which extends Animal. Because it’s unknown, it’s not the same as the type Dog. Let’s conclude by summarizing what you’ve just learned. It’s really important to get this because, as I mentioned, this should clear up the biggest misconception that I see Java developers have about wildcards. The most important point to remember is that a wildcard stands for a particular but unknown type. This means that, for example, a List

Using Wildcards in Practice

You’ve learned exactly what wildcards mean and how they work. But what is, of course, very interesting to know is how and for what purposes you apply them in practice. One of the things that wildcards are useful for is when you’re defining methods that take parameters of parameterized types. Sometimes, if you use concrete parameterized types, you unnecessarily restrict the types of values that you can pass to such methods. Using wildcards can help you remove those unnecessary restrictions. In the standard library, you can find many examples of methods that use wildcard parameterized types for this purpose. Let’s take a look at some of those to make clear how this works and to get some practice in interpreting method signatures with wildcards. Let’s start with a copy method from class JavaUtilCollections, which copies a list into another list. The method signature of this method looks as follows. It has a type parameter, , so it is a generic method. It has two parameters, which are the destination list of type List and the source list of type List. Now, let’s figure out why it has exactly this method signature with a lower‑bounded wildcard for the first parameter and an upper‑bounded wildcard for the second parameter. To understand this, let’s start by supposing that the method would not have been declared with bounded wildcards. Suppose that the method signature would have looked like this, so both parameters would be of type List. With this method signature, the method now requires that the types of the elements of both lists are of the same type, . But this is more restrictive than necessary. For example, it should be perfectly okay to copy elements from a source list into a destination list of which the elements are a super type of those in the source list. To make it concrete, suppose that my source list is a list of dogs, and my destination list is a list of animals. You can store dogs in the list of animals as well, so it should be possible to call the copy method with these source and destination lists. Right now that’s not possible because the method signature requires that if the source list is a list of dogs, the destination list must be a list of dogs too. What we can do to fix this problem is use wildcards on the parameter types. For the destination list, it’s okay if the list is any kind of list of which the elements are of a super type of T, and for the source list, it’s okay if the elements are of a subtype of T. In fact, this method signature would have worked just as well if only one of the two parameters would have been declared with the wildcard and the other one would just have been List. But the designers of this method decided to add the wildcard to both parameters, which makes it even more flexible. This example illustrates a principle about when to use upper bounded and when to use lower‑bounded wildcards. Which type of boundary is appropriate depends on the role that the parameter plays in the method. Upper‑bounded wildcards are useful for in parameters. An in parameter is a parameter that serves as input for the method. The method is going to read data from the object that the parameter refers to. Lower‑bounded wildcards are useful for out parameters. An out parameter is a parameter that’s used by the method as an output. The method is going to modify the state of the object that the parameter refers to. The example with the copy method shows this exactly. The source list is an in parameter because that’s where the method reads data from. The destination list is an out parameter because the method is going to modify the destination list. Because the source list is an in parameter, it has an upper‑bounded wildcard, and because the destination list is an out parameter, it has a lower‑bounded wildcard. In some situations, a parameter plays both roles, so it’s an in, as well as an out parameter. If that’s the case, then use the type parameter without a wildcard, so just write T instead of ? extends T or ? super T. Finally, there are also situations where a method needs to accept the parameterized type, but the method doesn’t need to do anything with the type parameter of that parameterized type. In that case, you can use the unbounded wildcard. Imagine a method, for example, that determines the size of a list. That method works on lists with elements of any type, and the method doesn’t need to do anything with the elements of the list other than count how many there are. In particular, it doesn’t need to know what the type of the element is, and therefore, the unbounded wildcard is an appropriate choice for this method.

Understanding Wildcards in Method Signatures

Let’s look at one more slightly more complicated example of a method in the standard library, which is the flatMap method in interface java.util.stream.Stream. This method has one parameter with a complicated‑looking type that contains three wildcards. First, it helps to understand what the flatMap method does. It takes a function as an argument, the mapper, which it calls on each element of the stream. The function is supposed to return a new stream for each element. The flatMap method will then return a stream that exists of a concatenation of all the streams that the function returned for each of the elements. In other words, flatMap does a one‑to‑many transformation of the elements of a stream. The elements of the output stream may be of a different type than the elements of the input stream. The type of the parameter is the generic type Function, which has two type parameters. The type Function represents a function with one parameter and that returns a value. The first type parameter is the type of the argument that the function takes, and the second one is the type of the value that it returns. Here you can see that flatMap expects a function that takes an argument of type ? super T, and that returns a value of type ? extends Stream. Let’s see if we can explain what this means. First we have to understand where the type parameters T and R come from and what they mean. The T is the type parameter of interface Stream itself, in which the flatMap method is defined. It’s the type of the elements in the stream on which we call the flatMap method. The R is the type parameter of the flatMap method. As you can see, flatMap is a generic method that’s defined inside the generic type Stream. To understand what R means, look at the return type of the method. It returns a Stream, which tells us that R is the type of the elements of the stream that flatMap returns. Now, let’s take a look at the type parameters of the function. The first type parameter tells us that the function takes an argument of some type that is a super type of T. Remember what I said about in and out parameters. You use upper bounded wildcards, so that’s ? extends something, for in parameters and lower bounded wild cards, ? super something, for out parameters. If you look at this method signature, then at first glance it looks like it’s exactly the other way around here. The first type parameter of interface Function is the type of the input of the function, yet it has a lower bounded wildcard here which you are supposed to use for out parameters. Also, the second type parameter of interface Function is the type of the output of the function, but it has an upper bounded wildcard. Why is it like this? It’s because you have to look at this from the perspective of the flatMap method, and not from the perspective of the mapper function. For the flatMap method, the parameter that is passed to the mapper function is an out value and the value that the function returns is an in value. Seen from the perspective of the flatMap method. The correct lower and upper bounds are used for the wildcards. Now let’s unpack the return type of the function, which is ? extends Stream. What this means is that flatMap wants the function to return something that is a subtype of Stream and that the elements in that stream are of some type that is a subtype of R. This makes sense, because the function is expected to return a stream, which is, of course, an instance of some type that implements interface Stream. The elements in that stream should be of type R, or possibly of a subtype of type R. Finally, the flatMap method itself then returns a Stream that contains elements of type R. Note that there are no wildcards in the return type of the flatMap method. That is deliberate. When you define methods, it’s better to avoid wildcards in the return type because it can make life unnecessarily complicated for callers of the method. Remember that a wildcard parameterized type contains only partial type information. Each wildcard in a wildcard parameterized type stands for some unknown type. By returning a wildcard parameterized type, you are withholding type information from the caller that can make the return value hard to work with. Have a look yourself at other methods in the standard library and see if you can understand and explain their method signatures. Here are some suggestions for examples that you could look at, class java.util.Collections, interface java.util.Comparator, interface java.util.stream.Stream, and class java.util.stream.Collectors.

Type Erasure

If you have been using generics while writing code in Java, you’ll most likely have noticed that there are some things that you cannot do. There are certain limitations on what you can do with generics in Java because of type erasure. Type erasure is the process by which the compiler deals with generics. But we are not looking at type erasure in this course just out of curiosity of how the Java compiler works. If you understand type erasure, then you can explain why these limitations exist, and that will help you to work more effectively with generics. An important point to understand is that in Java, generics are a compile‑time only feature. Type parameters and type arguments are used by the compiler for type checking, but no information about them is retained in the byte code. At runtime, there are no generic and parameterized types and no type parameters and type arguments. Let’s take a look at what exactly type erasure does with generic types and generic methods and what happens with type arguments at the places where you use generic types and methods. Type parameters in a generic type or method are discarded and replaced with the type java.lang.Object or the leftmost bound of the type parameter if it has bounds. Type arguments are simply discarded by the compiler, which means that parameterized types are replaced by their corresponding raw types. Where necessary, the compiler automatically adds type casts. To illustrate this, take a look at the next example. This is the same as the very first example of this module with interface TreeNode and classes InnerNode and LeafNode to represent a binary tree. But here, I’ve modified them to show what type erasure does. Remember that interface TreeNode was a generic type with an unbounded type parameter, T. Type erasure removes the type parameter and replaces it with a type object, so the getValue method now has Object as its return type instead of T. The return type of the getLeft and getRight methods was a parameterized type, TreeNode of T. This has been replaced by the raw type, TreeNode. Exactly the same thing has happened in classes InnerNode and LeafNode. The type parameters have been removed, and in the places where they were used, they have been replaced by the type, Object, and parameterized types have been replaced by raw types. Also, in the main method where we create and print a binary tree, the parameterized types have been replaced by raw types. It’s as if the code has been translated into how you would write it without generics. If a generic type has a type parameter with bounds, then type erasure will replace occurrences of the type parameter with the leftmost bound instead of the type, Object. Remember that when we talked about bounds on type parameters, we worked with a modified version of the example where TreeNode had a type parameter, T, with a bound, which was Comparable. With this version of the example, type erasure will replace T by Comparable instead of Object. So the getValue method, in this case, would now have Comparable as its return type. Note that Comparable is itself a generic type to which, of course, the same rules are applied. So the type erased version of getValue will have the raw type, Comparable, as its return type.

Limitations Caused by Type Erasure

The reason why it’s interesting to know about type erasure is because it explains why there are certain limitations when you work with generics. Let’s look at these limitations. First, you cannot use primitive types as type arguments. This is because type erasure replaces uses of type parameters by the type Object, and primitive types are not objects. The compiler compiles generic types into bytecode as if the generics aren’t there and generates code that works with any type of object, but not with specific types of primitive values. Next, it’s not possible to create a new instance of a type parameter, so new T() does not work. Type erasure removes type parameters, so at runtime there’s no information about the type T. The Java virtual machine doesn’t have the information to know what type of object to create. A well‑known way to get around this is by creating an object via reflection. To do this, you will need to have a Class object which describes the type of object you want to create. You can get the appropriate constructor from the Class object and use it to create a new instance. In this case, the Class object is the thing that contains the type information that’s missing because of type erasure when you try to do new T(). The next limitation is that instanceof doesn’t work with so‑called non‑reifiable types. A non‑reifiable type is a type for which information is lost during type erasure, or in other words, a type for which there is no complete type information at runtime. Non‑reifiable types are parameterized types with at least one concrete type argument or with at least one bounded wildcard as a type argument. For example, you can’t check if an object is an instanceof List because List is a parameterized type with a concrete type argument, String. The type List is a non‑reifiable type because type erasure throws away the type argument, so the information about the type String is lost. Note that some parameterized types are reifiable. For example, the wildcard parameterized type List is a reifiable type. The wildcard stands for an arbitrary unknown type, so it doesn’t really contain information about a specific type that would be discarded by type erasure. Another limitation caused by type erasure is that there are no class literals for parameterized types. For example, List.class is not allowed. Because of type erasure, there is simply no way to have a Class object that represents a specific parameterized type. Type erasure also explains why you get unchecked warnings. There are situations where neither the compiler nor the runtime environment can guarantee that an operation is type‑safe. In that case, you get an unchecked warning. We’ll see examples of this in the following clips. Finally, type erasure causes limitations on overloading methods. You cannot have overloaded methods of which the method signature looks the same after type erasure. For example, you cannot define two methods with the same name in the same class that take a List and a List. When type erasure has been applied to these two methods, they have the same method signature, so it looks like you have defined the same method twice. At runtime, the JVM has no way to distinguish these two methods. You now understand that type erasure causes many of the restrictions on generics that you might have encountered already when programming in Java.

Heap Pollution

Despite all the type checking that a compiler does, there are certain situations where it’s possible that the variable of a parameterized type refers to an object that is of the wrong type. This is called heap pollution. The ultimate causes for heap pollution are the fact that Java allows the use of raw types and type erasure. One way that heap pollution can occur is when you mix raw types and parameterized types. When you use raw types, the compiler relaxes many of its type checking rules, so it lets you do things that would normally not be possible. Take a look at this example where we create an ArrayList of Dogs and assign it to a variable of the raw type List. This assignment by itself is not a problem, but now look at what we’ll do next. We’ll declare a variable of the parameterized type List of Cat and initialize it by assigning the List of Dogs to it. This is allowed because the variable dogs is a raw list. When you compile this, you’ll get an unchecked warning, which should be a hint that you’re doing something that’s potentially wrong. For the rest it seems to work okay. You can, for example, print this List. When I run this, you’ll see that it works, although it’s a bit strange that this List of Cats really contains Dog objects. But when I try to get a Cat out of the List, it will, of course, go wrong. When I run this, I get a ClassCastException because the first object in the List is obviously not a Cat. You can, of course, avoid this type of heap pollution by not mixing raw types and parameterized types. You shouldn’t be using raw types at all anyway. Another way in which heap pollution can occur is when you perform unchecked casts. Because of type erasure, it’s not always possible to perform a complete type check at runtime when you do a cast. When the target type of a cast is a non‑reifiable type, then there will not be enough type information at runtime to check if the value you are casting is indeed of the target type. The compiler will, in that case, allow you to perform the cast, but it will give you an unchecked warning. Heap pollution occurs when the type of the object you are casting is not actually of the target type. Here’s another example that shows this. We start with a List of Dogs again. We can assign this to a variable of the wildcard parameterized type List<? extends Animal, so the type of the variable animals tells us that it’s a List of objects of some unknown type that extends Animal. Now we know that the unknown type is really the type Dog, so we can cast this variable back to the type List of Dog. When we compile this, we get an unchecked warning because the target type of the cast List of Dog is a non‑reifiable type. Type erasure throws away the type arguments when the code is compiled, so at runtime, it will not be possible to check that the variable animals really refers to a List of Dogs. In this case, no heap pollution occurs because the variable animals does indeed refer to a List of Dogs. But in exactly the same way, we can cast animals to a List of Cats. Of course, you will get an unchecked warning again, and this time heap pollution does occur because animals is not really a List of Cats. When we try to get a Cat out of this List, a ClassCastException will occur. A third way in which heap pollution can occur is the following situation, which I’ll sketch, but not demonstrate in detail. Suppose that you have two separate source files in which you use parameterized types. In one source file, for example, you have a method that returns a List of Dogs, and in another source file, you call this method and store the return value in a variable. Now, one possible scenario is that you modify the second source file and change the variable in which you store the return value to List of Cat. If you now only recompile the second source file, then you have heap pollution. When you compile the second source file, but not the first one, the Java compiler will look at the previously compiled bytecode for the first source file. Of course, because of type erasure, the bytecode does not contain exact type information for the return type of the method, so the compiler can’t check if the method returns a List of Cats. This is, of course, not a common scenario, but this type of heap pollution is actually even worse than the other two types that we discussed because when you do this, you will not even get an unchecked warning from the compiler. It will look like everything is okay, but at some point, you will get an unexpected ClassCastException when you run your code.

Generics and Arrays

Generics and arrays are not a good combination in Java. When you try to use both of these language features together, you will quickly run into problems and limitations. Let’s take a look to understand where these problems and limitations come from. Have you ever tried to create an array of a parameterized type? You will have noticed that this isn’t possible. For example, let’s try to create an array of pairs of Integer and String. We can declare a variable of that type with no problem. But let’s now try to create a new array and assign it to this variable. When you try this, you will get an error from the compiler that’s not very informative. It says generic array creation, but doesn’t give you any information about why that’s not allowed. The same happens when you try to create an array of a type parameter. For example, let’s create a method named createArray with a type parameter, T, that returns an array of T. So far, there’s no problem. It’s allowed to declare the return type as array of T. But let’s now try to implement this method by simply creating and returning an array of T of the requested size. When I compile this, I get the same error again, generic array creation. To understand this, we have to go back to invariants and covariants. Remember that in the clip about generics and inheritance, you learned that when a dog is an animal, that doesn’t mean that a list of dogs is also a list of animals because generic types are invariant. You’ve learned that there’s a good reason why generic types are invariant. If they would’ve been covariant, then Java would let us add a cat to a list of dogs, which would obviously be a problem. Now, here’s a fact about arrays that may surprise you. Arrays are covariant. Apparently, in the early days of Java, the language designers thought it was a good idea to make arrays covariant. This means that the type array of dog is, in fact, a subtype of the type array of animal, and we can assign an array of dogs to a variable of type array of animal without getting an incompatible types error. So doesn’t this open up the door to doing bad things like putting a cat in an array of dogs? Well, yes, it does. Surprisingly, we can put a cat into this array, and the compiler doesn’t give us an error and not even a warning. Even worse, we can also get the cat out of the array and assign it to a variable of type dog. What’s wrong here? Does Java really let us do this? Let’s see what happens when we run this program. As you see, in the line where we try to store a cat into the array, we get an ArrayStoreException. So Java doesn’t really let us silently turn a cat into a dog. What we can conclude from this is that when arrays were added to Java, the design philosophy was different. Arrays were made covariant, which unfortunately created a hole in the type system, which lets us write code like this. This hole was plugged with a runtime check. When you store an object in an array, then this runtime check verifies that the object you are storing in the array is of the right type, and if it isn’t, then an ArrayStoreException is thrown. Now combine this with what you know about type erasure, and you’ll understand why creating arrays of parameterized types or type parameters is not allowed. In order to perform the array store check, an array needs information at runtime about the exact element type of the array. At runtime, every array has information stored somewhere about the exact element type of that array. You know that for non‑reifiable types, type erasure has thrown away part of the type information. At runtime, parameterized types look like they’re corresponding raw types. Because part of the type information is missing at runtime for non‑reifiable types, the erased store check would not be able to do its work, and therefore, it’s not safe to allow arrays of non‑reifiable types. So, the reason why generics and arrays don’t work well together is because the way in which arrays work with a check that requires type information at runtime is at odds with how generics work with type erasure. If you are an experienced Java developer, then you already know that arrays in Java are not as useful as junior Java programmers sometimes seem to think. In most cases, you’re better off using collection classes instead of arrays.

Generics and Variable Arguments

The last subject we’ll discuss about generics is the combination of generics with varargs, or variable arguments. You can define methods that take a variable number of arguments. Let’s take a quick look at an example. We will create a method here named printLines that takes a variable number of arguments. We indicate that by putting three dots after the type name of the parameter. Inside the method, the parameter variable looks like an array. in this example, an array of strings, of course. We can loop over the array and print each of the strings. When we call this method, we can supply any number of arguments. Varargs are really just syntactic sugar for arrays. What’s happening in this line where we call the method is that an array is automatically created with the argument values. The array is what’s actually passed to the method. Now maybe you already have a suspicion why we are talking about this subject in this module about generics. In the previous clip, you’ve learned that arrays and generics don’t work very well together in Java. Since variable arguments are really just syntactic sugar for arrays, there are also some issues when you use generics with variable arguments. In particular, there’s a problem when you use values of a non‑reifiable type as variable arguments. Let’s continue with the example to understand what this problem is exactly. For the next part of the example, we are going to work with the record Pair again, which is a very simple record with two components of arbitrary types. Now here’s an idea for a useful method. Let’s create a method that takes a map and a number of pairs and that puts the pairs into the map using the first component of each pair as the key and the second component as a value. To make it work with any kind of map and pair, we’ll make this a generic method. We’ll add two type parameters, T and U. The first parameter of this method should be a map of T and U, but remember what you’ve learned about bounded wildcards. The map is an out parameter of the method, so we can put lower‑bounded wildcards on the type arguments here. So the type will be Map<? super T, ? super U. The second parameter of the method should be a pair of T and U. Since this is an in parameter, we can use upper‑bounded wildcards here. So the type will be Pair<? extends T, ? extends U>. Now to make the method more convenient, we want to be able to not just pass one pair to the method, but an arbitrary number of pairs. Let’s make the second parameter a varargs parameter by adding three dots after the type name of the parameter. The implementation of this method is simple. We just loop over the array of pairs and add an entry to the map for each pair, using the first component as the key and the second component as the value. Let’s try to use this method in the main method. We’ll first create a HashMap with integer keys and string values, and then we can call putIntoMap with this map and some pairs of integers and strings. It looks like this is all completely fine, but let’s compile the source file and see what the compiler says. To show you what happens, I’ll open a terminal window and compile the source file manually with the following command. The compiler gives me an unchecked warning. To find out why, let’s compile this again with the flag ‑Xlint:unchecked as the compiler suggests. Now we get some more information. There are actually two warnings. The first one happens in the declaration line of the method. It says Possible heap pollution from parameterized vararg type Pair<? extends T, ? extends U>. The second one happens in the main method in the line where we call the method, and it says unchecked generic array creation for varargs parameter of type Pair<? extends Integer, ? extends String> array. Let’s find out why we are getting these warnings. It has to do with the fact that varargs are really arrays. First, we look at the declaration line of the method. The varargs parameter is really an array just written with a different syntax. The type Pair<?extends T, ? extends U> is a non‑reifiable type. So what we really have here is an array of a non‑reifiable type. This explains the first unchecked warning. Arrays of non‑reifiable types are dangerous because when you put an object into such an array, the array store check will be unable to check if the object is actually of the right type, which can lead to heap pollution. In principle, we could do something bad in this method. For example, we could declare a variable named array of type Object[] array and initialize it by assigning the parameter variable pairs to it. This is allowed because arrays are covariant, so the type of the array pairs is a subtype of the type Object[] array. But in an Object[] array, we can store any kind of object. For example, we can set the first element of this array to a new pair of long values. The compiler allows this, and even at runtime, the array store check won’t notice that this is wrong because it will be unable to check if this pair of long values is actually the correct element type for this array. The conclusion of this first point is that varargs parameters of non‑reifiable types are allowed, but can lead to heap pollution, and therefore, you get an unchecked warning. Now let’s look at the second unchecked warning, which happens at a point where we call the method. Something really strange is going on here. The warning message already gives you a hint. Remember that when you call a varargs method, the compiler automatically creates an array from the variable arguments, which is passed to the method. In this example, the variable arguments are pairs of Integer and String. Note that the type pair of Integer and String is a concrete parameterized type, which is a non‑reifiable type. Now put this together with what you’ve learned in the previous clip. Creating an array of elements of a non‑reifiable type is forbidden by the compiler. When you try that, you will get an error that says generic array creation. What’s actually happening in this line is that the compiler creates an array of the non‑reifiable type pair of Integer and String anyway, despite the fact that it forbids you, the programmer, from creating such an array yourself. Of course, because this can lead to heap pollution, it gives you an unchecked warning. Now here’s your final point. There’s a special annotation that you can put on the method, the @SafeVarargs annotation. When you put this annotation on the method, the unchecked warnings disappear. When you use the @SafeVarargs annotation, you’re promising the compiler that the method doesn’t do anything bad with the varargs array inside the method. You should be very careful when you use this annotation and understand that it means that you’re asking the compiler to trust you and disable some of its type checks.

Module Summary

We are at the end of this module about generics. Generics is a big and complicated topic, and it’s about much more than using type arguments for collections. We started with how you can define your own generic types and methods. The most important topic from that part of the module is the terminology. You need to have a solid understanding of the terms generic type, type parameter, parameterized type, and type argument. These terms are easier to understand when you see the parallels between the world of values and the world of types. Just like you can define parameters for passing values to methods, you can define type parameters for generic types. When you call a method, you supply arguments, which are the actual values that you pass to the method. Likewise, when you instantiate a generic type into a parameterized type, you supply type arguments, which are the actual types that you want to use. The word instantiating has a different meaning in the value world versus the type world. When we talk about values, what we mean by instantiating is creating a new object. When we talk about generic types, then instantiating means creating a particular parameterized type from a generic type using specific type arguments. Next, we looked at bounded type parameters. Sometimes you don’t want to allow any type to be used as a type argument, but only types that extend a particular class or implement one or more particular interfaces. Then you learned what raw types are. Raw types only exist for backward compatibility with old versions of Java. You should not use raw types except for when you have a very good reason to do so. We discussed how generics work with inheritance. You’ve learned that generics are invariant, which means that if you have a type Dog, which is a subtype of Animal, that doesn’t automatically mean that a list of dogs is also a list of animals. This is necessary for compile‑time type safety. We discussed wildcards in detail. With wildcards, you can declare wildcard parameterized types. In contrast to a concrete parameterized type, a wildcard parameterized type is not one particular fully defined type, but a way to refer to a family of related parameterized types. One very important point to remember about wildcards is that a wildcard stands for a specific but unknown type. This means that, for example, a list which has the unbounded wildcard as a type argument is not a list that can contain arbitrary objects of different types. Instead, it is a list that contains objects of a single type, but the wildcard doesn’t tell you what that type is. You cannot add elements to such a list because there is not enough information for the compiler to check if an object that you try to add to the list is of the right type. Wildcards can be unbounded or have an upper or a lower bound. We looked at examples of methods in Java standard library that use bounded wildcards. You learned that upper bounded wild cards are useful for in parameters and lower bounded wildcards are useful for out parameters. The next topic we looked at was type erasure. Generics are a compile‑time only feature in Java. After the compiler has done its type checking, it discards type parameters and type arguments. In the byte code that the compiler produces, and at runtime, there is no information about generics. Understanding type erasure helps you to understand why there are certain limitations when you work with generics. Java’s type system is not perfect. There are situations where it can happen that a variable of a parameterized type refers to an object that is actually of a different type. That problem is called heap pollution. When the compiler gives you an unchecked warning, then that’s a sign that heap pollution might be happening in your program, and you should be careful. In the last part of the module, you’ve discovered that generics and arrays unfortunately don’t play nice together in Java. The main reasons for this are that generics are invariant, while arrays are covariant, and that arrays require runtime type information for the array store check, while type erasure makes that information unavailable. In particular, the compiler doesn’t allow you to create arrays with elements of a non‑reifiable type because this is just not typesafe. Variable arguments are really just syntactic sugar for arrays, and because generics and arrays don’t work well together, there are also problems when using generics with variable arguments. I know this was a lot of information to learn. Don’t worry if you don’t remember all of the details you’ve learned about in this module. You now have at least a good foundational knowledge of generics, which will help you to understand them when you use them in practice. In the next module, you will learn how lambda expressions and method references really work. Please continue whenever you’re ready.