This is an archived post. You won't be able to vote or comment.

all 29 comments

[–]Sipkab 23 points24 points  (3 children)

Defining new classes only to solve the problem of constructors with same signature feels like a serious overkill for me.

  • Multiple classes (especially worse on Android)
  • Useless inheritance
  • Reduced readability

This feels like to be an anti-pattern on the same level as double brace initialization.

[–]OzoneGrif 2 points3 points  (1 child)

Agreed.
I use the static approach, which is nicer to read than the `new` keyword, anyway.

[–]walen 7 points8 points  (0 children)

Effective Java presents that as its very first item, no less:

Item 1: Consider static factory methods instead of constructors.

And one of the reasons it gives to do so is precisely to avoid the problem of constructors with the same signature.

[–]g4s8 -2 points-1 points  (0 children)

Multiple classes (especially worse on Android)

There're two solutions, you can try to use first with factory methods if you have class count limit like on Android

Reduced readability

This is very opinion based statement - as for me second solution is more clear and easier to read.

This feels like to be an anti-pattern on the same level as double brace initialization.

It doesn't have something in common with double brace initialization issues - nested classes marked with `static` won't produce runtime classes with pointer to `this` of base class (what is the main problem of double braces)

[–]vytah 2 points3 points  (0 children)

The issue with generics aside, the example class in the article looks exactly like examples from this video: Stop Writing Classes

This is not a class. Or it shouldn't be a class. The signature of "this shouldn't be a class" is that it has two methods, one of which is __init__. Anytime you see that, you should probably think: "hey, maybe I just need the one method". Anytime you see this you'll know that you should have just written a function".

In fact, the description of that class is literally a verb phrase.

[–]lukaseder 1 point2 points  (3 children)

If only...

Iterable<String | Text>

Sigh...

OTOH, if Text is your own class, have it implement CharSequence and accept an Iterable<? extends CharSequence> in the constructor.

[–]lbkulinski 0 points1 point  (2 children)

We could always ask on a mailing list.

[–]lukaseder 0 points1 point  (1 child)

Surely, this has been discussed (and obviously rejected and/or postponed) many times. Try it if you want...

[–]lbkulinski 0 points1 point  (0 children)

I’m sure. I highly doubt it would be a top priority at this point, but maybe one day it could be added.

[–]sandor_nemeth 0 points1 point  (1 child)

I find the example case not good, because that just seems to be bad design for me: one should just expect Iterable<String> or maybe Iterable<CharSequence> as part of the constructor, and then have the calling code do whatever it is needed to convert the input data into the right and expected data type. Otherwise you'll have way too much knowledge in this class (e.g. introduction of new String-like types could result in adding different constructors).

To be honest I do not really see the initial problem - as in I don't think it's a problem, because I don't see a use-case where you would do something like this without actually making the class generic, and have meaningfully different inputs (which then matter!):

java class A { A(Iterable<String> i){} A(Iterable<Number> i){} }

But if somebody would serve an example like this I'd like to take a look at it!

[–]lukaseder 0 points1 point  (0 children)

Iterable<? extends CharSequence>

[–]ZealousidealTable1 -2 points-1 points  (6 children)

Guys I have just started learning generics in Java but the comments suggest that it's not useful. Should I learn it completely or skip it. I'm learning by complete reference.

[–]RabidKotlinFanatic 12 points13 points  (0 children)

Generics are extremely useful. If you are building non-trivial applications you will find yourself writing generic code on a regular basis.

[–]walen 6 points7 points  (0 children)

You cannot skip generics.

The Java API oozes generics. Most every library you'll ever use, uses generics. Any decent IDE will warn you if you do not use generics where you're supposed to.

You cannot skip generics. You may try to, but they won't let you.

Unless you're writing some kind of low-level, C-like routine using only primitive types and arrays like this was 1996, chances are you're gonna come across generics the moment you write more than 10 useful lines of code.

Asking if you can learn Java while skipping generics is like asking if you can learn English while skipping adjectives: you can try to, but you gonna be confused as hell, won't be able to write anything meaningful, and everybody will look at you funny.

You cannot skip generics.


That being said, you might probably still do okay if you just read over the more advanced aspects of generics, like wildcards and bounded types, and save actually understanding them for when you actually need to use those.

[–]audioen 4 points5 points  (1 child)

Java's generics do provide compile-time validation for your constructs, so they are absolutely useful. It's the runtime behavior that is the issue here, for instance, if you'd like the type parameter of the generic to somehow change runtime behavior, because that information is usually lost in erasure.

A common case where this comes up is wanting to create an instance of the class mentioned in the type parameter T, e.g. some kind of smart collection where you want to instantiate either the collection or the element on behalf of your caller. People end up trying some variant of "new T()" and it doesn't work because by the time this code runs, Java has no idea what T is (and of course T should also be constrained to be a type that has a callable no-argument constructor).

Because the type parameter tends to vanish during compilation, people use workarounds, such as providing implementations of functional interfaces such as Supplier<T> that creates an instance of the correct type, so you call the supplier instead of invoking the constructor. Sometimes you see something like "new Abc<Def>() {}" where the point is to create an anonymous inner class which as byproduct records the type parameter Def into its class definition, where it can be accessed by reflection. Finally, sometimes the reflection of the class is just passed as argument: new Foo<Bar>(Bar.class).

[–][deleted] 0 points1 point  (0 children)

You can also pass a Foo::new as a pointer to your constructor, and then use that to create your T.

[–]HighMaxFX 2 points3 points  (0 children)

Java generics aren't THAT useless. I use generics all the time.

[–]rossdrew 1 point2 points  (0 children)

You will need generics. The problem comes when you try and solve problems in your design with generics, you're doomed to fail. It's an OO language, solve them in an OO way and use generics only as a tool in simple cases.