Java has call-site variance, which means the caller gets to decide which direction the subclass relationship goes in generic relationships.
Let's assume we've got a class Parent and a subclass called Child. Generally speaking, it's not safe to treat a List<Child> as a List<Parent> or vice versa. If we try to cast a List<Child> to a List<Parent> then someone could come along and .add something that isn't a Child to it, breaking our list. Conversely, if we try to cast a List<Parent> to a List<Child> and it contains some things that aren't Child instances, we're equally out of luck.
However, each cast still provides us with a guarantee. If I have a List<Child>, then I know that every element of that list is a Child and hence (by the 'is-a' relationship established by subclasses) every element of that list is a Parent. So if we only intend to read from the list and never to write to it, it's safe to take a List<Child> and treat it as a read-only version of List<Parent>. That's exactly what List<? extends Parent> is. It says "I've got a list, it contains some subclass of Parent and I don't know which one. It's safe to get elements from this list and cast them up to Parent since, no matter what class the ? represents, it's always safe to assume it's a Parent subclass. So an argument of type List<? extends Parent> can accept a List<Parent> or a List<Child> or a list of any subtype of Parent. But we can't add elements to a List<? extends Parent> because we don't know what type the ? is, so we can never safely supply an argument to List.add. This is called a covariant relationship, where it's safe to consider a list of a subclass to be a list of the superclass for these purposes.
The converse relationship is called contravariant. It's the exact same idea, but it's a little harder to understand sometimes. In Java, we would write it as List<? super Child>. A List<? super Child> is a list of some supertype of Child. That ? could be Parent or it could be Object or it could be some interface that Child happens to implement, but it has to be a supertype of Child. Now, we can never safely get elements from this list, since we have no idea what the type is. It's not Child, since the list could be a List<Parent> and could contain non-Child instances. However, we can add elements to the list. Whatever the ? is, it's a supertype of Child, so we can always safely add Child instances to List<? super Child>, since the argument to add can just be quietly upcast to the correct type.
Going back to your examples,
List<? extends Exception> lst = new ArrayList<Exception>();
The left-hand type is a list of some subtype of Exception. Notably, ArrayList<Exception> implements List<Exception> and, since Exception is (trivially) a subtype of itself, List<Exception> is a valid List<? extends Exception>.
List<NullPointerException> lst2 = new ArrayList<Exception>();
Here, ArrayList<Exception> is still a subtype of List<Exception>, but List<Exception> is incompatible with List<NullPointerException>, because in the absence of any variance annotations (extends or super), all generic arguments are assumed to be invariant (except arrays, but that's a whole other can of unsound worms). We could have written
List<? super NullPointerException> lst2 = new ArrayList<Exception>();
and gotten a write-only list of NullPointerException, or we could have written
List<? extends Exception> lst2 = new ArrayList<NullPointerException>();
and gotten a read-only list of Exception. But we have to specify which we want. Likewise,
public void f3(Collection<? extends S> c, List<S> l) {
    c = l;
}
List<S> implements Collection<S>, and S is (again, trivially) a subtype of S, so we have Collection<S> compatible with Collection<? extends S>, hence the assignment compiles.
More useful reading material on when you want extends vs. super: What is PECS (Producer Extends Consumer Super)?