I have abstract class OptionalComparator<T extends Comparable<T>> implements Comparator<Optional<T>>
So far, so good.
Following the model used by Optional itself, I figured it would be best to have a single instance of this class, and cast it when necessary (for example, to OptionalComparator<Integer>).
So I made private static final OptionalComparator<? extends Comparable<?>> ABSENT_FIRST.
The trouble came when I tried to assign a value. What should the type be?
new OptionalComparator<Comparable<Object>>() {...} doesn't work.
new OptionalComparator<Comparable<Comparable<Object>>>() {...} doesn't work.
new OptionalComparator<Integer>() {...} does work, for example, but I want the least-specific type possible.
What am I doing wrong? How can I make a base-case instance of this class?
You can have multiple implementations of OptionalComparator like this:
private static final OptionalComparator<? extends Comparable<?>> ABSENT_FIRST = new AbsentFirst<>();
private static final OptionalComparator<? extends Comparable<?>> ABSENT_LAST = new AbsentLast<>();
private interface OptionalComparator<T extends Comparable<T>> extends Comparator<Optional<T>> { }
private static class AbsentFirst<T extends Comparable<T>> implements OptionalComparator<T> {
#Override
public int compare(Optional<T> obj1, Optional<T> obj2) {
if (obj1.isPresent() && obj2.isPresent()) {
return obj1.get().compareTo(obj2.get());
} else if (obj1.isPresent()) {
return -1;
} else if (obj2.isPresent()) {
return 1;
} else {
return 0;
}
}
}
private static class AbsentLast<T extends Comparable<T>> implements OptionalComparator<T> {
#Override
public int compare(Optional<T> obj1, Optional<T> obj2) {
if (obj1.isPresent() && obj2.isPresent()) {
return obj1.get().compareTo(obj2.get());
} else if (obj1.isPresent()) {
return 1;
} else if (obj2.isPresent()) {
return -1;
} else {
return 0;
}
}
}
static <T extends Comparable<T>> OptionalComparator<T> absentFirstComparator() {
#SuppressWarnings("unchecked")
OptionalComparator<T> comp = (OptionalComparator<T>) ABSENT_FIRST;
return comp;
}
static <T extends Comparable<T>> OptionalComparator<T> absentLastComparator() {
#SuppressWarnings("unchecked")
OptionalComparator<T> comp = (OptionalComparator<T>) ABSENT_LAST;
return comp;
}
public static void main(String... args) {
OptionalComparator<Integer> absentFirstInt = absentFirstComparator();
System.out.println(absentFirstInt.compare(Optional.of(1), Optional.empty()));
OptionalComparator<Integer> absentLastInt = absentLastComparator();
System.out.println(absentLastInt.compare(Optional.of(1), Optional.empty()));
OptionalComparator<Double> absentFirstDouble = absentFirstComparator();
System.out.println(absentFirstDouble.compare(Optional.of(1.0), Optional.empty()));
OptionalComparator<Double> absentLastDouble = absentLastComparator();
System.out.println(absentLastDouble.compare(Optional.of(1.0), Optional.empty()));
}
Output:
-1
1
-1
1
Guava now provides (since 21.0, and no more #Beta since 27.1) Comparators.emptiesLast(Comparator) and emptiesFirst(Comparator).
Example: Comparator<Optional<Instant>> compareOptInst = Comparators.emptiesLast(Comparator.naturalOrder());
You may just have to do an unsafe cast. Consider how ImmutableList handles the empty-list case:
private static final ImmutableList<Object> EMPTY =
new RegularImmutableList<Object>(ObjectArrays.EMPTY_ARRAY);
/**
* Returns the empty immutable list. This set behaves and performs comparably
* to {#link Collections#emptyList}, and is preferable mainly for consistency
* and maintainability of your code.
*/
// Casting to any type is safe because the list will never hold any elements.
#SuppressWarnings("unchecked")
public static <E> ImmutableList<E> of() {
return (ImmutableList<E>) EMPTY;
}
In this case, it might similarly be easiest to use a raw type instance. As long as you gate all calls that return ABSENT_FIRST with generic casts, this will be fine, and calling code shouldn't have any warnings.
Related
Let's say I will have multiple constructors, other can use T, but one constructor has to use Comparable
I tried to use
public <T extends Comparable<T>>TestT() // does not help
the code
import java.util.ArrayList;
public class TestT<T> {
private ArrayList<T> arr;
public TestT() {
arr = new ArrayList<>();
}
void push(T e){
arr.add(e);
}
}
How to make it so TestT constructor will allow only Comparable? Assuming I have other constructors which do not require Comparable
Your question doesn't make much sense since all constructor have the same name. Try using static methods instead:
public class TestT<T> {
private ArrayList<T> arr;
public static <X extends Comparable<X>> TestT<X> comparable() {
return new TestT<>();
}
private TestT() {
arr = new ArrayList<>();
}
void push(T e){
arr.add(e);
}
}
Please see if the below code answers to your requirements:
class TestT<T> {
private List<T> arr;
// Constructor that receives Comparable
protected <X extends Comparable<? super X>> TestT(X comparableIn1, X comparableIn2) {
/* Locate here your logic that transforms the input Comparable to List<T> */
// some foolish example implementation
if (comparableIn1.compareTo(comparableIn2) > 0) {
arr = new ArrayList<>();
}
else {
arr = new LinkedList<>();
}
}
// Another Constructor that receives a Collection of Comparable
protected <X extends Comparable<? super X>> TestT(Collection<X> comparableCollection) {
/* Locate here your logic that transforms the input Comparable Set to List<T> */
}
// Another Constructor that receives something else
protected TestT(List<T> listOfАrbitraries) {
arr = listOfАrbitraries;
}
void push(T e){
arr.add(e);
}
}
// Create different instances by the above Constructor receiving Comparable
TestT<Integer> arrayListOfIntegers = new TestT<>("1","0");
TestT<Object> linkedListOfObjects = new TestT<>("1","2");
Frankly, the notation <X extends Comparable<? super X>> can be simplified to just <X extends Comparable<X>>. In this case your Constructor argument's type will need to implement compareTo(X o) method, while in a manner I wrote above, the Comparable Interface can be also implemented by a method compareTo(<? super X> o) and the method's definition can be also in one of X's super types.
I have an interface:
public interface ITransformer<S,T>{
public void transform(S source,T target);
default String getTransformerName(){
Class<S> s;
Class<T> t;
return s.getName() + t.getName(); //*********
}
}
the error message the starred line:
The local variable s may not have been initialized
The local variable t may not have been initialized
I would like to use this method to return a string with [S.classname][T.classname] . Please let me know how to achieve this or is this impossible to do at interface ?
Update: Jan 12
My purpose of doing this is due to the fact that this class will be in framework and I want to reduce the human error as much as possible.. I am changing the code as follows:
public interface ITransformer<S,T>{
public void transform(S source,T target);
public FieldEntry<S, T> getTransformerName();
}
public class FieldEntry<S,T> implements Comparable<FieldEntry> {
private Class<S> s;
private Class<T> t;
public FieldEntry(Class<S> s,Class<T> t){
this.s = s;
this.t = t;
}
public String getEntryName(){
return s.getName() + t.getName();
}
#Override
public int compareTo(FieldEntry entry) {
if(entry == null) throw new IllegalArgumentException("The argument to compare cannot be null!");
return entry.getEntryName().compareTo(this.getEntryName());
}
}
In order to demonstrate why this can’t work, you may change your class to
public interface ITransformer<S,T>{
public void transform(S source,T target);
static <In,Out> ITransformer<In,Out> noOp() {
return (source,target) -> {};
}
static void main(String... arg) {
ITransformer<String,Integer> t1 = noOp();
ITransformer<Long,Thread> t2 = noOp();
System.out.println(t1 == (Object)t2);
}
}
Running this will print true. In other words, both functions are represented by the same instances, so there can’t be and property allowing to recognize their different type.
Generally, when two functions (lambda expressions or method references) exhibit the same behavior, a JVM may represent them by the same implementation type or even the same instance.
Even for non-interface classes, this doesn’t work due to Type Erasure. It only works when you have a reifiable (i.e. non-generic) type extending or implementing a generic type.
It's a little bit dangerous and I wouldn't used this in production (because you should cover in your code all possible use cases of your interface), but you can use reflection for it:
public interface ITransformer<S, T> {
public void transform(S source, T target);
default String getTransformerName() {
Type[] genericInterfaces = this.getClass().getGenericInterfaces();
ParameterizedType parameterizedType = null;
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType paramInterface = (ParameterizedType) genericInterface;
if (paramInterface.getRawType().equals(ITransformer.class)) {
parameterizedType = paramInterface;
break;
}
}
}
if (parameterizedType == null) {
throw new IllegalStateException("!");
}
return parameterizedType.getActualTypeArguments()[0].getTypeName() + parameterizedType.getActualTypeArguments()[1].getTypeName();
}
}
public class StringToIntegerTransfomer implements ITransformer<String, Integer> {
#Override
public void transform(String source, Integer target) {
}
}
public interface StringToNumberTransfomer<T extends Number> extends ITransformer<String, T> {
}
public class StringToLongTransfomer implements StringToNumberTransfomer<Long>, ITransformer<String, Long> {
#Override
public void transform(String source, Long target) {
}
}
#Test
public void test() {
ITransformer<String, Integer> intTransformer = new StringToIntegerTransfomer();
ITransformer<String, Long> longTransformer = new StringToLongTransfomer();
ITransformer<String, String> stringTransformer = new ITransformer<String, String>() {
#Override
public void transform(String source, String target) {
}
};
ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>() {
#Override
public void transform(String source, Double target) {
}
};
System.out.println(String.format("intTransformer: %s", intTransformer.getTransformerName()));
System.out.println(String.format("longTransformer: %s", longTransformer.getTransformerName()));
System.out.println(String.format("stringTransformer: %s", stringTransformer.getTransformerName()));
System.out.println(String.format("doubleTransformer: %s", doubleTransformer.getTransformerName()));
}
Output for this snippet:
intTransformer: java.lang.Stringjava.lang.Integer
longTransformer: java.lang.Stringjava.lang.Long
stringTransformer: java.lang.Stringjava.lang.String
java.lang.IllegalStateException: !
This code has one restriction, you should say implements ITransformer<S, T> for all implementations of ITransformer. That why I have got IllegalStateException for this line ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>(). But you can improve this code.
Better option is to use some base implementation of interface and pass source and target classes into constructor:
public interface ITransformer<S, T> {
void transform(S source, T target);
String getTransformerName();
}
public abstract class BaseITransformer<S, T> implements ITransformer<S, T> {
private final Class<S> sourceClass;
private final Class<T> targetClass;
public BaseITransformer(Class<S> sourceClass, Class<T> targetClass) {
this.sourceClass = sourceClass;
this.targetClass = targetClass;
}
public String getTransformerName() {
return sourceClass.getName() + targetClass.getName();
}
}
In Java it is impossible to get a Class<S>, unless you already know which class S is, or something else that knows which class S is gives you one.
I have a PlayerCharacter class.
PlayerCharacter can be extended (for example, VampirePlayerCharacter vs WerewolfPlayerCharacter)
I have a Trait class. Trait can be extended (for example, Generation or Gnosis).
PlayerCharacter has a method, #withTrait(Trait), which adds the Trait to a collection.
PlayerCharacter has a method, #applyAllTraits() which loops through the collection and applies each of them to the character.
A VampirePlayerCharacter should be able to be given any Trait that could apply to a PlayerCharacter, as well as any Trait that could only apply to a VampirePlayerCharacter.
So I added a generic type, making Trait<PC extends PlayerCharacter>
Thus, there can be BasicTrait<PlayerCharacter> and Generation<VampirePlayerCharacter>
My conundrum:
If PlayerCharacter's collection of traits is Collection<Trait<PlayerCharacter>>, then VampirePlayerCharacter can't add a Trait<VampirePlayerCharacter> to the collection.
If PlayerCharacter's collection of traits is Collection<Trait<? extends PlayerCharacter>>, then VampirePlayerCharacter can add a Trait<VampirePlayerCharacter> to the collection. However, PlayerCharacter can no longer loop through the traits, because their type is indeterminate (it could be Trait<PlayerCharacter> or a Trait<VampirePlayerCharacter> or a Trait<WerewolfPlayerCharacter> or...)
If PlayerCharacter's collection of traits is Collection<Trait<? super PlayerCharacter>>, then VampirePlayerCharacter can't add a Trait<VampirePlayerCharacter>, because VampirePlayerCharacter isn't a supertype of PlayerCharacter
I'm about a hair's-breadth from saying that more specialized traits just have to use a cast in their apply method and if you set things up inappropriately, they'll explode- but I'm certain that this is not a novel problem, and I just can't wrap my head around the solution.
class PlayerCharacter {
private int str;
List<Trait<?>> traits = new ArrayList<>();
PlayerCharacter withStrength(int str) {
this.str = str;
return this;
}
PlayerCharacter withTrait(Trait trait) {
this.traits.add(trait);
return this;
}
void applyTraits() {
traits.forEach((Trait<?> t) -> t.apply(this));
}
}
class VampirePlayerCharacter extends PlayerCharacter {
private int fangLength;
VampirePlayerCharacter withFangLength(int fangLength) {
this.fangLength = fangLength;
return this;
}
}
abstract class Trait<PC extends PlayerChracter> {
void apply(PC pc);
}
class StrengthTrait extends Trait<PlayerCharacter> {
private int str;
StrengthTrait(int str) {
this.str = str;
}
void apply(PlayerCharacter pc) {
pc.withStrength(str);
}
}
class FangLengthTrait extends Trait<VampirePlayerCharacter> {
private int fangLength;
FangLengthTrait(int fangLength) {
this.fangLength = fangLength;
}
void apply(VampirePlayerCharacter pc) {
pc.withFangLength(fangLength);
}
}
Well the problem is that you need to retain your inheritance as generic type information.
Basically you would have to do something like:
class PlayerCharacter<P extends PlayerCharacter<P>> {
List<Trait<? super P>> myTraits;
}
class VampirePlayer extends PlayerCharacter<VampirePlayer> {...}
abstract class Trait<P extends PlayerCharacter<P>> {
abstract void apply(P player);
}
class FangLengthTrait extends Trait<VampirePlayer> {...}
It begins to get very clunky, though. You can somewhat improve the situation by approaching from composition:
class Attributes {}
class Base extends Attributes {
int strength;
}
class Vampire extends Base {
int fangLength;
}
class Player<A extends Attributes> {
final A attributes;
final List<Trait<? super A>> traits = new ArrayList<>();
Player(A attributes) {
this.attributes = attributes;
}
void applyTraits() {
for(Trait<? super A> t : traits)
t.apply(this);
}
}
interface Trait<A extends Attributes> {
void apply(Player<? extends A> player);
}
class StrengthTrait implements Trait<Base> {
#Override
public void apply(Player<? extends Base> player) {
player.attributes.strength = 1000;
}
}
class FangLengthTrait implements Trait<Vampire> {
#Override
public void apply(Player<? extends Vampire> player) {
player.attributes.fangLength = 100;
}
}
final class Factory {
private Factory() {}
public static Player<Base> newPlayer() {
return new Player<Base>(new Base());
}
public static Player<Vampire> newVampire() {
return new Player<Vampire>(new Vampire());
}
}
I still find it clunky, personally. If you are mainly just using these Traits to construct objects you might think about using a builder or factory so you don't need to use generics.
What should be the signature of a method that takes a generic object and returns another generic object, one that either is the same or a sub class of the original class? That is, if the method takes some generic class A, the returned object is guaranteed to be either A or B such that B extends A (directly or indirectly)?
The code below exemplifies what I'm trying to do, in the function getList():
package com.company;
import java.util.ArrayList;
public class Main {
private Main(){
List<String> stringList = new GenericMessageListCreator.getList(StringGenericMessage.class);
}
private class GenericMessageListCreator() {
public List<GenericMessage<T1>> getList(Class<T1 extends GenericMessage> clazz) {
return new ArrayList<T1>();
}
}
private class GenericMessage<T> {
public GenericMessage(){};
private T internalValue;
public void setValue(T value) {
this.internalValue = value;
}
public void echoValue() {
System.out.println("I contain " + internalValue);
}
}
private class StringMessage extends GenericMessage<String>{}
private class IntegerMessage extends GenericMessage<Integer>{}
}
Example aside, in actuality I'm writing a registry of classes that are used for Commands in a command pattern. When I get an object by its class I want to fetch the appropriate Command and pass the object to it.
I think you are looking for this signature:
public <T1 extends GenericMessage> List<GenericMessage<T1>> getList(Class<T1> clazz) {
return new ArrayList<T1>();
}
You'll find more info about generic methods here.
EDIT
Based on what I understand from your sample code, I would go for something like (I corrected some syntax errors in your code):
private class GenericMessageListCreator {
public <U, V extends GenericMessage<U>> List<U> getList(Class<V> clazz){
return new ArrayList<U>();
}
}
private class GenericMessage<T> {
public GenericMessage(){};
private T internalValue;
public void setValue(T value)
{
this.internalValue = value;
}
public void echoValue() {
System.out.println("I contain " + internalValue);
}
}
private class StringMessage extends GenericMessage<String>{}
private class IntegerMessage extends GenericMessage<Integer>{}
Thus, you'll be able to create a List<String from `StringMessage like this:
List<String> stringList = new GenericMessageListCreator().getList(StringMessage.class);
I'm not even sure which method you want to have this behavious on, but I've assuming it's getList():
private class GenericMessageListCreator() {
public <T extends GenericMessage<?>> List<T> getList(Class<T> clazz) {
return new ArrayList<T>();
}
}
I have the following code:
public interface IDoWork<K extends AbstractKey,V extends AbstractClass> {
V obtain(K key, V value);
}
public class AbstractKey {
String id;
}
public class AbstractClass {
String name;
}
public class ConcreteA extends AbstractClass {
String attributeA;
}
public class DoWorkA implements IDoWork<KeyA, ConcreteA> {
private static final DoWorkA INSTANCE = new DoWorkA();
public static DoWorkA getInstance() {
return INSTANCE;
}
#Override
public ConcreteA obtain(KeyA k, ConcreteA v) {
//do something in real life
return null;
}
}
public class Main {
public static void main(String[] args){
KeyA a = new KeyA();
ConcreteA c = new ConcreteA();
IDoWork<? extends AbstractKey, ? extends AbstractClass> instance =
WorkFactory.getInstance().obtainInstance(a);
instance.obtain(a, c);
}
}
public class WorkFactory {
private static final WorkFactory INSTANCE = new WorkFactory();
public static WorkFactory getInstance() {
return INSTANCE;
}
public IDoWork<? extends AbstractKey, ? extends AbstractClass> obtainInstance(AbstractKey key){
if(key instanceof KeyA){
return DoWorkA.getInstance();
}
throw new IllegalArgumentException("Case not handled");
}
}
In the following code:
KeyA a = new KeyA();
ConcreteA c = new ConcreteA();
IDoWork<? extends AbstractKey, ? extends AbstractClass> instance = WorkFactory.getInstance().obtainInstance(a);
instance.obtain(a, c);
This line doesn't compile:
instance.obtain(a, c);
due to the nature of Java generics. I get the following error:
The method obtain(capture#3-of ? extends AbstractKey, capture#4-of ? extends AbstractClass) in the type IDoWork is not applicable for the arguments (KeyA, ConcreteA)
Is there another way to do it? If omit the type parameters in
IDoWork<? extends AbstractKey, ? extends AbstractClass> instance =...
If I remove the type parameters from IDoWork... it works but I get a warning. Is there a way to fix that.? I know that I can remove the type parameters from the interface and that will solve the problem but I find it handy to have the generics in order not to have to do casting + it brings clarity to the code since it's clear to see what each class uses. Depencendy injection is out of question because it's not available in the codebase I'm in.
I have something that works, but is not very optimal:
If you define your WorkFactory this way:
public class WorkFactory {
private static final WorkFactory INSTANCE = new WorkFactory();
public static WorkFactory getInstance() {
return INSTANCE;
}
#SuppressWarnings("unchecked")
public <K extends AbstractKey, V extends AbstractClass> IDoWork<K, V> obtainInstance(K key, V val) {
if (key instanceof KeyA) {
return (IDoWork<K, V>) DoWorkA.getInstance();
}
throw new IllegalArgumentException("Case not handled");
}
}
then your main method should work cleanly:
public static void main(String[] args){
KeyA a = new KeyA();
ConcreteA c = new ConcreteA();
IDoWork<KeyA, ConcreteA> instance = WorkFactory.getInstance().obtainInstance(a, c);
instance.obtain(a, c);
}
I have changed obtainInstance to take the key and the val, to infer the types properly.