I am currently learning about the functionalities of the Optional class, and I am trying to build a simplified version of the Optional class. I was able to code ifPresent(), filter(), of(), map() and so on. However, I am currently stuck with the implementing or().
I know that or() have the signature Optional<T> or(Supplier<? extends Optional<? extends T>> supplier). However, my implementation assumed that I can access the contents of the Optional. As show below:
class Optional<T> {
private final T item;
...
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
if (this.item == null) {
T item = supplier.get().item;
return Maybe.<T>of(item);
} else {
return this;
}
}
}
As you can see, T item = supplier.get().item would throw an error saying that .item is inaccessible due to it being private. How am I able to access the item without causing this error?
First, you need to recall that you can not access a private field through an instance of a subtype, even though assigning the subtype reference to a variable of the current type, which allows the access, is possible without cast.
So if you have
public class ClassWithPrivateField {
private String field;
static class Subclass extends ClassWithPrivateField {}
void someMethod(Subclass obj) {
String s = obj.field; // does not work, you can't access field through Subclass
}
}
you may write
public class ClassWithPrivateField {
private String field;
static class Subclass extends ClassWithPrivateField {}
void someMethod(Subclass obj) {
ClassWithPrivateField withBroaderType = obj; // always works
String s = withBroaderType.field; // now, no problem to access field
}
}
Now to your more complicated generic variant. If you have
public class Optional<T> {
private final T item;
private Optional(T t) {
item = t;
}
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
if(this.item == null) {
T item = supplier.get().item;
return Optional.of(item);
}
else return this;
}
private static <T> Optional<T> of(T item2) {
return new Optional<>(item2);
}
}
the access to item is rejected by the compiler because the type returned by the supplier is ? extends Optional<? extends T> which is a subtype of Optional<? extends T>, just the same way as Subclass is a subtype of ClassWithPrivateField.
You can fix the issue the same way, by introducing a variable:
public class Optional<T> {
private final T item;
private Optional(T t) {
item = t;
}
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
if(this.item == null) {
Optional<? extends T> optional = supplier.get(); // valid assignment
T item = optional.item; // valid access
return Optional.of(item);
}
else return this;
}
private static <T> Optional<T> of(T item2) {
return new Optional<>(item2);
}
}
Alternatively, you could insert a type cast to Optional<? extends T> like
T item = ((Optional<? extends T>)supplier.get()).item;
but I would prefer the variant with a variable as it immediately shows to the reader that the assignment (without a cast) is a valid type transition which can never fail. The type cast can not fail either and is a no-op at runtime, but its syntax is indistinguishable from type casts performing a runtime check that could fail.
You just need to replace
T item = supplier.get().item;
return Maybe.<T>of(item);
with
return (Optional<T>)supplier.get();
Related
What's the difference between
? extends Stream<? extends R>
and
Stream<? extends R>
Is <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) same as <R> Stream<R> flatMap(Function<? super T, Stream<? extends R>> mapper).
Could you give some examples?
Short answer: ? extends SomeType is very different than SomeType.
Longer answer:
The use of Stream<extends R> as SomeType confuses the example. To answer the question, consider a simpler comparison, for example:
? extends Integer
Integer
The first observation is that ? extends Integer as a type expression can be used only within generic declarations. On the other hand, Integer can be used in many more places.
Here are some code examples to help show the difference:
// The following do not compile:
//
// Syntax error on tokens, delete these tokens ('? extends').
//
// private Integer value;
// public ? extends Integer getValue() {
// return value;
// }
//
// Syntax error on tokens, delete these tokens ('? extends').
//
// private Integer value;
// public void setInteger(? extends Integer value) {
// this.value = value;
// }
//
// In both cases, the use of bounded quantification ('? extends') is
// not valid outside of a generic type declaration.
// Here is a very basic example of the use of generics:
//
// Generic 'Wrapped' is quantified on a single type, which
// is unrestricted:
public class Wrapped<T> {
Wrapped() { this.value = null; }
Wrapped(T value) { this.value = value; }
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
}
// The following is also valid:
//
// 'Wrapped_1' is quantified on a single type, which is restricted
// to be 'Integer' or a subtype of 'Integer'.
public class Wrapped_1<T extends Integer> {
// EMPTY
}
// This is not valid. In addition to being non-valid syntacticly,
// the declaration needs a specific type. Use of a wildcard does
// not provide a specific type.
//
// Syntax error on token "?", Identifier expected
//
// public class Wrapped_2<? extends Integer> {
// }
// The following does not compile:
//
// Cannot instantiate the type Wrapped<? extends Integer>.
// Type mismatch: cannot convert from Wrapped<? extends Integer> to Wrapped<Integer>.
//
// private Wrapped<Integer> Wrapped0 = new Wrapped<? extends Integer>();
// These show the difference in effect between the declarations
// 'Integer' and '? extends Integer'.
private Wrapped<Integer> wrapped_1 = new Wrapped<Integer>( new Integer(4) );
private Wrapped<? extends Integer> wrapped_2 = wrapped_1;
{
// This compiles:
wrapped_1.set( new Integer(5) );
// This does not compile:
//
// The method set(capture#1-of ? extends Integer)
// in the type Wrapped<capture#1-of ? extends Integer>
// is not applicable for the arguments (Integer)
//
// wrapped2.set( new Integer(6) );
}
let say R = Number
Stream<? extends R> can be Stream<Integer> Stream<Long>
But
? extends Stream<? extends R> says which implements Stream<Number> or Stream<Integer> and so on....
class XXXX implements Stream<Integer>{} ...
XXXX overrides all the Stream abstract methods
This question already has answers here:
Get generic type of class at runtime
(30 answers)
Closed 7 years ago.
I'd like to find a hack to infer the actual generic instance of another instance's var in runtime, without:
Changing my needed method signature (adding the helper parameter Class<T>, the obvious way)
Having to instanceof all possible subtypes in a hardcoded way
MyInterface<? extends Number> myInterface = whateverReturnsWildcardDoubleInterface();
Class<?> type = inferInstanceType(myInterface);
assert type == Double.class;
/** This is the method that represents the code I am looking for with the conrete signature**/
public <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
return T.class; //Concrete T (can or cannot be the very Number)
}
Ideally, it should return Double when T is particular subtype Integer,Double.. and Number when T is Number
I checked reflection, several "TypeResolver"/"GenericResolver" libs (as the one in Spring or others in Github), but I cannot fin a way to hack it.
EDIT: I reached the conclusion that he only feasible way to do that would be some kind of very complex reflection through the stack trace up to the acutal line that passes the type in the very instantiation
EDIT2: I know it's stupid... but I solved it by simply adding a T getT() method to my interface, so I could return myInterface.getT().getClass()
Disclaimer: This solution is provided as a hack tailored to my understanding of your setup, i.e. one generic interface with a single type parameter, multiple classes, which are not themselves generic, directly implementing this one interface alone, and implementing no other generic interfaces, directly or indirectly.
Assuming that all of the above is true, there is a relatively straightforward way of hacking a solution: calling getClass().getGenericInterfaces() returns a Type object that provides the actual type with which your generic interface has been instantiated.
interface MyInterface<T extends Number> {
T getVal();
}
class DoubleImpl implements MyInterface<Double> {
public Double getVal() {return 42.42; }
}
...
public static void main (String[] args) throws java.lang.Exception {
MyInterface<? extends Number> x = new DoubleImpl();
Type[] ifs = x.getClass().getGenericInterfaces();
System.out.println(ifs.length);
for (Type c : ifs) {
System.out.println(c);
Type[] tps = ((ParameterizedType)c).getActualTypeArguments();
for (Object tp : tps) {
System.out.println("===="+tp); // <<== This produces class java.lang.Double
}
}
}
Demo.
As assylias pointed out, Java's erasure will make that information unavailable at runtime - and thus a need for a hack.
On the assumption that myInterface has a getter for T, as in, MyInterface.getValue():T (or the hack would be to add it) you could do something like this (ignoring the possibility that getValue() could return null):
public <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
return myInterface.getValue().getClass()
}
Below is the full implementation
public class Q34271256 {
public static interface MyInterface<T> {
T getValue();
}
public static class MyDoubleClass implements MyInterface<Double> {
private final Double value;
public MyDoubleClass(Double value) {
this.value = value;
}
#Override
public Double getValue() {
return value;
}
}
public static class MyIntegerClass implements MyInterface<Integer> {
private final Integer value;
public MyIntegerClass(Integer value) {
this.value = value;
}
#Override
public Integer getValue() {
return value;
}
}
#SuppressWarnings("unchecked")
public static <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
Number value = myInterface.getValue();
if (value == null) return null;
return (Class<T>)value.getClass();
}
public static void main(String...args) {
List<MyInterface<? extends Number>> list = Arrays.asList(
new MyDoubleClass(1.1),
new MyIntegerClass(5)
);
for (MyInterface<? extends Number> myInterface : list) {
Class<?> type = inferInstanceType(myInterface);
System.out.printf("%s inferred type is %s\n",
myInterface.getClass().getName(),
type.getName());
}
}
}
And the output should look something like this:
MyDoubleClass inferred type is java.lang.Double
MyIntegerClass inferred type is java.lang.Integer
I'm trying to build a generics system that allows me to make subclasses that can call statics which exist on the abstract superclass that return the subclass' type. So far, this works:
public abstract class GenericsTest<T extends GenericsTest<T>> {
#SuppressWarnings("unchecked")
protected T createT() {
try {
Type supe = getClass().getGenericSuperclass();
Type t = ((ParameterizedType) supe).getActualTypeArguments()[0];
// This means that the type needs a default constructor.
// Sadly there is no real way to enforce this in java.
return (T) (Class.forName(t.toString()).newInstance());
} catch (Exception e) {
return null;
}
}
public static <T extends GenericsTest<T>> T fetch(int key) {
GenericsTest<T> obj = new GenericsTest<T>() {};
T ret = obj.createT();
// do stuff here to actually fetch/fill the object
return ret;
}
}
Now, by defining the implementing class as
public class GenericsTestImpl extends GenericsTest<GenericsTestImpl>
I can call GenericsTestImpl coolstuff = GenericsTestImpl.fetch(k);, which is pretty cool.
However... when I add a second generic type parameter, changing the final type definition to <T extends GenericsTest<T, E>, E> the whole system fails, for some bizarre reason. The original superclass has no problems, but the actual call to fetch() says that the types don't match:
// Bound mismatch: The generic method fetch(int) of type GenericsTest<T,E>
// is not applicable for the arguments (int). The inferred type
// GenericsTestImpl&GenericsTest<GenericsTestImpl&GenericsTest<T,E>,Object>
// is not a valid substitute for the bounded parameter <T extends GenericsTest<T,E>>
(added as commented code because the markup swallows <> stuff)
New code:
public abstract class GenericsTest<T extends GenericsTest<T, E>, E> {
#SuppressWarnings("unchecked")
protected T createT() {
try {
Type supe = getClass().getGenericSuperclass();
Type t = ((ParameterizedType) supe).getActualTypeArguments()[0];
// This means that the type needs a default constructor.
// Sadly there is no real way to enforce this in java.
return (T) (Class.forName(t.toString()).newInstance());
} catch (Exception e) {
return null;
}
}
public static <T extends GenericsTest<T, E>, E> T fetch(int key) {
GenericsTest<T, E> obj = new GenericsTest<T, E>() {};
T ret = obj.createT();
// do stuff here to actually fetch/fill the object
return ret;
}
}
And the implementation:
public class GenericsTestImpl extends GenericsTest<GenericsTestImpl, String>
Does anyone have any idea why the additional type messes it up? As far as I can see, that does match.
what i'm trying to do is as follows:
assume that getClassFromString() and getAllObjectsFromRepositoryByClass() already exist.
why can't i use Class<T extends Named & HasId>.
i tried generifying the class itself, but can't use stuff like T.class etc.
public interface Named { String getDisplayName(); }
public interface HasId { String getId(); }
public class Foo {
public List<PairItem> getPairItems(String typeId) {
Class<T extends Named & HasId> clazz = getClassFromString(typeId);
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
List<PairItem> items = new ArrayList<>();
for (clazz obj : allObjects) {
items.add(obj.getDisplayName(),ibj.getId());
}
return items;
}
You can change you Foo-class in this way:
public class Foo {
public <T extends Named & HasId> List<PairItem> getPairItems(String typeId) {
Class<?> classFromString = getClassFromString(typeId);
// Java 8 seems to be unable to chain asSubclass-calls. These are merely to verify our unchecked cast
classFromString.asSubclass(Named.class);
classFromString.asSubclass(HasId.class);
//noinspection unchecked
return getPairItems((Class<T>) classFromString);
}
public <T extends Named & HasId> List<PairItem> getPairItems(final Class<T> clazz) {
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
List<PairItem> items = new ArrayList<>();
for (T obj : allObjects) {
items.add(new PairItem(obj.getDisplayName(), obj.getId()));
}
return items;
}
}
This fixes your problems with multiple boundaries as they are only allowed for type-parameters per documentation.; also I guess that
If one of the bounds is a class, it must be specified first.
leads to the problem that the asSubclass()-calls can not be chained, otherwise we could remove our unchecked cast.
The second method can profit from the streaming-API like this:
public <T extends Named & HasId> List<PairItem> getPairItems(final Class<T> clazz) {
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
return allObjects.stream()
.map(obj -> new PairItem(obj.getDisplayName(), obj.getId()))
.collect(Collectors.toList());
}
Overall I assumed that you wanted to instantiate PairItem and split the method so there is a unchecked and a fully-checked part.
I'm trying to write a class that has a generic member variable but is not, itself, generic. Specifically, I want to say that I have an List of values of "some type that implements comparable to itself", so that I can call sort on that list... I hope that makes sense.
The end result of what I'm trying to do is to create a class such that I can create an instance of said class with an array of (any given type) and have it generate a string representation for that list. In the real code, I also pass in the class of the types I'm passing in:
String s = new MyClass(Integer.class, 1,2,3).asString();
assertEquals("1 or 2 or 3", s);
String s = new MyClass(String.class, "c", "b", "a").asString();
assertEquals("\"a\" or \"b\" or \"c\"", s);
Originally I didn't even want to pass in the class, I just wanted to pass in the values and have the code examine the resulting array to pick out the class of the values... but that was giving me troubles too.
The following is the code I have, but I can't come up with the right mojo to put for the variable type.
public class MyClass {
// This doesn't work as T isn't defined
final List<T extends Comparable<? super T>> values;
public <T extends Comparable<? super T>> MyClass (T... values) {
this.values = new ArrayList<T>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable<? super T>> List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}
error on variable declaration line:
Syntax error on token "extends", , expected
Any help would be very much appreciated.
Edit: updated code to use List instead of array, because I'm not sure it can be done with arrays.
#Mark: From everything I've read, I really want to say "T is a type that is comparable to itself", not just "T is a type that is comparable". That being said, the following code doesn't work either:
public class MyClass {
// This doesn't work
final List<? extends Comparable> values;
public <T extends Comparable> MyClass (T... values) {
this.values = new ArrayList<T>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable> List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}
error on add line:
The method add(capture#2-of ? extends Comparable) in the type List<capture#2-of ? extends Comparable> is not applicable for the arguments (T)
error on sort line:
Type mismatch: cannot convert from List<capture#4-of ? extends Comparable> to List<T>
Conclusion:
What it comes down to, it appears, is that Java can't quite handle what I want to do. The problem is because what I'm trying to say is:
I want a list of items that are
comparable against themselves, and I
create the whole list at once from the
data passed in at creation.
However, Java sees that I have that list and can't nail down that all the information for my situation is available at compile time, since I could try to add things to the list later and, due to type erasure, it can't guarantee that safety. It's not really possible to communicate to Java the conditions involved in my situation without applying the generic type to the class.
I think that the simple answer is that you cannot do that. If the type of one of a classes attributes depends on a type parameter, that parameter has to be declared at the class level. And I don't think that it "makes sense" any other way.
If T in your example is not a type parameter of the class, what is it? It cannot be the type parameter of the method, because that type is determined by how the method is called. (If the method is called in different static contexts with different inferred types for T, what is the notional type of T in the context of the attribute declaration?)
So to bring this back to what you are trying to do here, an instance of MyClass will hold elements of some type, and you want to be able to insert and remove elements in a statically typesafe fashion. But at the same time you don't want to be able to say what that type is. So how is the compiler supposed to statically distinguish between a MyClass instance that holds (say) Integer objects and one that holds String objects?
I don't even think you could implement this with explicit dynamic typechecks. (I think that type erasure means that the implementation of the getSortedList() method cannot find out what actual type is bound to its return type.)
No. The real solution is to make MyClass a generic class that declares the type parameter T; e.g.
public class MyClass <T extends Comparable<T>> {
and remove the declaration of the method-level type parameter T from the two methods.
There's plenty of unchecked warnings in this, but in principle it's not necessary to keep the List as anything but something containing things you know are Comparable. You enforce the rules you need to in the constructor, and everything else should be fine. How about something like this:
public class MyClass {
final private List<Comparable> values;
public <T extends Comparable<? super T>>MyClass(T... values){
this.values = new ArrayList<Comparable>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable<? super T>> List<T> getSortedLst() {
Collections.sort(this.values);
return (List<T>)this.values;
}
}
A quick test using the following shows that for classes that implement Comparable (like Integer and String) MyClass behaves as expected, but will throw a compilation error for classes that do not implement Comparable:
class Junk { }
public static void main(String[] args){
MyClass s = new MyClass(1,2,3);
System.out.println(s.getSortedLst());
MyClass a = new MyClass("c", "a", "b");
System.out.println(a.getSortedLst());
MyClass c = new MyClass(new Junk());
}
I believe the following will achieve what you want (stronger typing of Comparable). This will prevent people adding Comparable objects which are not from your interface to the list and allow multiple implementations.
public class test<T extends ComparableType> {
final List<T> values = new ArrayList<T>();
public test (T... values) {
for(T item : values) {
this.values.add(item);
}
}
public List<T> getSortedLst() {
Collections.sort(this.values);
return Collections.unmodifiableList(this.values);
}
}
public interface ComparableType extends Comparable<ComparableType> {}
public class ConcreteComparableA implements ComparableType {
#Override
public int compareTo(ComparableType o) {
return 0;
}
}
public class ConcreteComparableB implements ComparableType {
#Override
public int compareTo(ComparableType o) {
return 0;
}
}
edit:
I know this may be obvious; but if you do not wish the class to be Generic this solution will also work with:
public class test {
final List<ComparableType> values = new ArrayList<ComparableType>();
public test (ComparableType... values) {
for(ComparableType item : values) {
this.values.add(item);
}
}
public List<ComparableType> getSortedLst() {
Collections.sort(this.values);
return Collections.unmodifiableList(this.values);
}
}
Consider it like this (what I am about to say isn't reality. but it illustrates why you need to do what you need to do):
class Foo<T>
{
private T value;
T getValue() { return value; }
void setValue(T val) {value = val; }
}
// some code that uses the above class
Foo<Integer> iFoo = new Foo<Integer>();
Foo<String> sFoo = new Foo<String>();
iFoo.setValue(5);
sFoo.setValue("Hello");
When this happens the compiler (DOES NOT REALLY DO WHAT I AM ABOUT TO SAY!) generates the following code:
class IntegerFoo
{
private Integer value;
Integer getValue() { return value; }
void setValue(Integer val) {value = val; }
}
class StringFoo
{
private String value;
String getValue() { return value; }
void setValue(String val) {value = val; }
}
// some code that uses the above class
IntegerFoo iFoo = new IntegerFoo();
StringFoo< sFoo = new StringFoo();
iFoo.setValue(5);
sFoo.setValue("Hello");
If you were able to have the instance variables/methods parameterized without parameterizing the class the above thing (WHICH IS NOT REALITY!) wouldn't work.
What you are trying to do should be possible with static methods, but I don't think that is what you want.
Can you explain why you want to do the code you are trying to do? Perhaps we can figure out a better way to do what you want to do that works within the language.
I'd do it this way (I did it as a list or as an array), unless you really need the instance variable/methods:
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class MyClass
{
public static <T extends Comparable<T>> List<T> asSortedList(final T ... vals)
{
final List<T> temp;
temp = new ArrayList<T>(vals.length);
temp.addAll(Arrays.asList(vals));
Collections.sort(temp);
return (Collections.unmodifiableList(temp));
}
public static <T extends Comparable<T>> T[] asSortedArray(final Class<?> clazz,
final T ... vals)
{
final T[] temp;
temp = (T[])Array.newInstance(clazz,
vals.length);
System.arraycopy(vals,
0,
temp,
0,
vals.length);
Arrays.sort(temp);
return (temp);
}
public static void main(final String[] argv)
{
final List<String> list;
final String[] array;
list = MyClass2.asSortedList("c", "a", "b");
System.out.println(list);
array = MyClass2.asSortedArray(String.class, "z", "y", "x");
System.out.println(Arrays.deepToString(array));
}
}
the type constraint you want on the variable can't be expressed directly. you can introduce a new type to bridge the problem.
static class MyList<T extends Comparable<? super T>> extends ArrayList<T>{}
final MyList<?> values;
however, there is no point to be extremely type safe in a private piece of code. Generic is there to help you clarify your types, not to obfuscate them.
public class MyClass<T extends Comparable<? super T>> {
// This doesn't work as T isn't defined
final List<T> values;
public MyClass (T... values) {
this.values = new ArrayList<T>(Arrays.asList(values));
}
public List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}