2

I am having trouble with using Java capture groups correctly.

Suppose I have these classes:

class Foo{}
class Bar{}

interface InterfaceXYZ<T>{ 
  void doSomething(T t);
}

class FooImplementation implements InterfaceXYZ<Foo>{
  @Override void doSomething(Foo){}
}

Finally,

class Delegator<T>{
  Delegator(InterfaceXYZ<T> delegate){this.delegate = delegate;}

  void doSomething(T t) {
    delegate.doSomething(t);
  }

  private InterfaceXYZ<T> delegate;
}

The problem is this works fine -

FooImplementation fi = new FooImplementation();
Delegator d = new Delegator(fi);
d.doSomething(new Foo());

This does not work fine (as expected) - causes a runtime exception

FooImplementation fi = new FooImplementation();
Delegator d = new Delegator(fi);
d.doSomething(new Bar());

Why doesn't it throw a compile time error? If I have to make it throw a compile time error, what changes do I need to make?

Akshaya Shanbhogue
  • 1,438
  • 1
  • 13
  • 25

1 Answers1

0

For the most part it's right, but you need to specify the <...> part during instantiation (or it will default to raw type, which is similar to <Object>. See this answer for details on difference between raw, <?>, and <Object>). And Foo and Bar are both objects so the compiler sees this and thinks it's ok.

Here is what the instantiation looks like using <...>. Here, InterfaceXYZ<Foo> and FooImplementation are interchangeable (as the compiler knows FooImplementation is a InterfaceXYZ<Foo>)

For Foo

InterfaceXYZ<Foo> fi = new FooImplementation();
Delegator<Foo> d = new Delegator<Foo>(fi);
d.doSomething(new Foo());

And for Bar (getting compile time error instead of runtime)

InterfaceXYZ<Bar> fi = new FooImplementation();
Delegator<Bar> d = new Delegator<Bar>(fi);
d.doSomething(new Bar());

Additional note:

InterfaceXYZ<?> fi = new FooImplementation(); won't throw a compile time error because you might say add fi to a List<InterfaceXYZ<?>>, where InterfaceXYZ<bar> is also valid and usable. The compiler can't and won't check for every possible way an object can be used in the call stack, so only trust compile time errors to appear under just the context of the current class being compiled.

Community
  • 1
  • 1
Tezra
  • 8,463
  • 3
  • 31
  • 68
  • The compiler should also generate a warning about the raw type usage. It is good to not ignore these. – Jens May 10 '17 at 20:51
  • @Jens, It should generate a warning, but it depends on your IDE and its configuration. But yes, All warnings are bad unless you know EXACTLY why it is being thrown, and you have a VERY GOOD SPECIFIC REASON to ignore it. – Tezra May 10 '17 at 20:53
  • Yes, I tried it earlier and that works. The main question I had is - why? Doesn't the compiler have enough information to show that the two are incompatible? – Akshaya Shanbhogue May 10 '17 at 20:56
  • 2
    Wait, so what are you saying...InterfaceXYZ = new FooImplementation(); would work? – Manish Kumar Sharma May 10 '17 at 20:58
  • 1
    @Akshay Sadly, the compiler is very shallow and as far as it knows, > is valid (if you want to add FooImplementation and BarImplementation to a list for example) – Tezra May 10 '17 at 20:59
  • @pulp_fiction, no, I'm saying if you add , that you will get the expected incompatible error messages from the compiler. – Tezra May 10 '17 at 20:59
  • "or it will default to `>`, which is basically ``" It does *not* "default to `>`, and `>` is *not* basically ``. – newacct May 18 '17 at 02:44
  • @newacct 99.9% of the time there is no functional difference between raw, ? and Object. Never the less, corrected the statement that default is raw, and added a link for more info on that for those who care. – Tezra May 18 '17 at 12:41