I have implemented compareTo to allow me to compare my class' based on some criteria and it is working fine.
However, at some point I want to compare the class' on one thing and at another point in the code I want to compare the class based on another thing.
Is it possible to have two different implementations of compareTo and using one at some point and one at another?
In general the mechanism to do this is to implement one or more Comparators and use the appropriate one as needed.
Since your Class is "Comparable" you can use the compareTo, you can't - however - create more then one implementation of that function to be used at different points in the same Class (you have one function to override, and you can't do that twice).
You can, however, take a look at the Comparator Interface; and implementation of that interface can allow you to implement and use a different compareTo for your object.
We achieved something similar by writing a utility comparator for our class - something like this:
public class FooComparator implements Comparator<Foo> {
public static String COMPARE_FIELD1 = "COMPARE_FIELD1";
public static String COMPARE_FIELD2 = "COMPARE_FIELD2";
public static String COMPARE_FIELD3 = "COMPARE_FIELD3";
private String compareBy = COMPARE_FIELD1;
private boolean reverse = true;
public FooComparator(){}
public FooComparator(String sort){
compareBy = sort;
}
public void reverse() {
if(reverse) {reverse = false;
} else {reverse = true;}
}
public void field1Sort() {compareBy = COMPARE_FIELD1;}
public void field2Sort() {compareBy = COMPARE_FIELD2;}
public void field3Sort() {compareBy = COMPARE_FIELD3;}
public int compare(Foo foo1, Foo foo2) {
if(compareBy.equals(COMPARE_FIELD2)) {
return compareByField2(foo1, foo2);
} else if(compareBy.equals(COMPARE_FIELD3)) {
return compareByField3(foo1, foo2);
}
return compareByField1(foo1, foo2);
}
private int compareByField1(Foo foo1, Foo foo2) {
if(reverse) {return foo1.getField1().compareTo(foo2.getField1());}
return foo1.getField1().compareTo(foo2.getField1());
}
private int compareByField2(Foo foo1, Foo foo2) {
if(reverse) {return foo1.getField2().compareTo(foo2.getField2());}
return foo1.getField2().compareTo(foo2.getField2());
}
private int compareByField3(Foo foo1, Foo foo2) {
if(reverse) {return foo1.getField3().compareTo(foo2.getField3());}
return foo1.getField3().compareTo(foo2.getField3());
}
}
We then can use it like this:
List<Foo> foos = new ArrayList<Foo>();
FooComparator comparator = new FooComparator(FooComparator.COMPARE_FIELD1);
Collections.sort(foos, comparator);
Related
I am trying to sort my list of objects like this:
List<UsersDataFoundTo> mergedUsers = mergeUsersFound(ldapUsers, foundUsers);
return mergedUsers.sort((UsersDataFoundTo h1, UsersDataFoundTo h2) -> h1.getLastName().compareTo(h2.getLastName()));
and on the return statement I get an error:
Incompatible types.
Required: java.util.List<UsersDataFoundTo>
Found:void
What do I do wrong then?
Much easier would be to write is as:
mergedUsers.sort(Comparator.comparing(UsersDataFoundTo::getLastName))
And sort has a void return type, so basically do a :
return mergedUsers;
For reusable, I think the class UsersDataFoundTo should implements Comparable and override compareTo function.
class UsersDataFoundTo implements Comparable<UsersDataFoundTo> {
private String lastNam;
public String getLastNam() {
return lastNam;
}
public void setLastNam(String lastNam) {
this.lastNam = lastNam;
}
#Override
public int compareTo(UsersDataFoundTo other) {
return getLastNam().compareTo(other.getLastNam());
}
}
Then you can use a collection utility to sort it like this:
List<UsersDataFoundTo> mergedUsers = //...
java.util.Collections.sort(mergedUsers);
I hope this help.
In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}
I'm sorry if this question has been asked before, but I don't really know what to search for.
Anyway, I'm making a math package, and many of the classes extend Function:
package CustomMath;
#SuppressWarnings("rawtypes")
public abstract class Function <T extends Function> {
public abstract Function getDerivative();
public abstract String toString();
public abstract Function simplify();
public abstract boolean equals(T comparison);
}
I want to compare functions to see if they're equal. If they're from the same class, I want to use its specific compare method, but if they're of different classes, I want to return false. Here is one of the classes I have currently:
package CustomMath;
public class Product extends Function <Product> {
public Function multiplicand1;
public Function multiplicand2;
public Product(Function multiplicand1, Function multiplicand2)
{
this.multiplicand1 = multiplicand1;
this.multiplicand2 = multiplicand2;
}
public Function getDerivative() {
return new Sum(new Product(multiplicand1, multiplicand2.getDerivative()), new Product(multiplicand2, multiplicand1.getDerivative()));
}
public String toString() {
if(multiplicand1.equals(new RationalLong(-1, 1)))
return String.format("-(%s)", multiplicand2.toString());
return String.format("(%s)*(%s)", multiplicand1.toString(), multiplicand2.toString());
}
public Function simplify() {
multiplicand1 = multiplicand1.simplify();
multiplicand2 = multiplicand2.simplify();
if(multiplicand1.equals(new One()))
return multiplicand2;
if(multiplicand2.equals(new One()))
return multiplicand1;
if(multiplicand1.equals(new Zero()) || multiplicand2.equals(new Zero()))
return new Zero();
if(multiplicand2.equals(new RationalLong(-1, 1))) //if one of the multiplicands is -1, make it first, so that we can print "-" instead of "-1"
{
if(!multiplicand1.equals(new RationalLong(-1, 1))) // if they're both -1, don't bother switching
{
Function temp = multiplicand1;
multiplicand1 = multiplicand2;
multiplicand2 = temp;
}
}
return this;
}
public boolean equals(Product comparison) {
if((multiplicand1.equals(comparison.multiplicand1) && multiplicand2.equals(comparison.multiplicand2)) ||
(multiplicand1.equals(comparison.multiplicand2) && multiplicand2.equals(comparison.multiplicand1)))
return true;
return false;
}
}
How can I do this?
With generic you have the guarantee that the equals method is only apply with the type 'T', in this case 'Product'. You can't passe another class type.
Another possibility would be in classe Function define:
public abstract boolean equals(Function comparison);
And in classe Product the object comparison whith a comparison instanceof Product
Override Object.equals(Object) method. You don't need to use generics here. Its body will look something like this
if (other instanceof Product) {
Product product = (Product) other;
// Do your magic here
}
return false;
I have a string (which is a message) that I get as input and I need to do one of 4 possible things depending on the string
I know that there is eunm.valueOf() option, but I have 4 different enums, each with few possible messages.
looks something like:
public enum first{ONE,TWO,THREE};
public enum second{FOUR,FIVE,SIX};
public enum third{SEVEN,EIGHT,NINE};
public void work(String message){
//Here I want to compare message string to one of the 3 enums
}
is it possible to do this in one method of the enum?
or should I just try to create one, and if I get an exception try the other and so on?
As others have commented, it may be better to think through whether you really need 4 distinct enums.
But if you do, you could have them implement a common interface. Then you can map the input strings to the appropriate enum member, and call its method to accomplish what you want. Something like
public interface SomeInterface {
void doSomething();
};
public enum First implements SomeInterface {
ONE,TWO,THREE;
#Override
public void doSomething() { ... }
};
...
Map<String, SomeInterface> myMap = new HashMap<String, SomeInterface>();
for (First item : First.values()) {
myMap.put(item.toString(), item);
}
...
public void work(String message){
SomeInterface obj = myMap.get(message);
if (obj != null) {
obj.doSomething();
}
}
This assumes that the 4 possible things you want to do correspond to the 4 enums. If not, you can override the method separately for each and any enum member too, e.g.
public enum First implements SomeInterface {
ONE,
TWO {
#Override
public void doSomething() { // do something specific to TWO }
},
THREE;
#Override
public void doSomething() { // general solution for all values of First }
};
Enumerations in Java are full blown classes. Individual values can even override the behavior to meet their needs. It's pretty cool. You can use this to your advantage:
public enum Value implements Worker
{
ONE,
TWO,
THREE
{
#Override
public void doWork(String message)
{
// overrides behavior of base enum
}
},
FOUR,
/* ... */,
NINE;
private final String message;
Value() { this(""); }
Value(String message) { this.message = message; }
public void doWork(String message)
{
if (this.message.equals(message))
{
/* ... */
}
}
}
public interface Worker
{
void doWork(String message);
}
You can create a Map of them all
static final Map<String, Enum> enumMap = new LinkedHashMap<String, Enum>(){{
for(First e: First.values()) put(e.name(), e);
for(Second e: Second.values()) put(e.name(), e);
for(Third e: Third.values()) put(e.name(), e);
}};
Enum e = enumMap.get(name);
What you're really looking for is a aggregation of the other enums. The easiest way to get that is to make a new enum that puts all of those choices in a new enum. Something to this effect:
public enum Combination {
NEWONE(first.ONE), NEWTWO(first.TWO), NEWTHREE(first.THREE),
NEWFOUR(second.FOUR), NEWFIVE(second.FIVE), NEWSIX(second.SIX),
NEWSEVEN(third.SEVEN), NEWEIGHT(third.EIGHT), NEWNINE(third.NINE);
private String contents;
public Combination(first f) {
contents = f.toString();
}
public Combination(second s) {
contents = s.toString();
}
public Combination(third t) {
contents = t.toString();
}
public String toString() {
return contents;
}
}
This will more correctly aggregate the previous enums into a single data structure.
Even given your odd/even example in the comments, I don't feel multiple enums are the way to go here. I would use something like (warning, untested):
public enum Numbers {
ONE("first"), TWO("first"), THREE("first"), FOUR("second"), FIVE("second"), SIX("second"), SEVEN("third"), EIGHT("third"), NINE("third")
private String type;
Numbers(String t) { this.type = t; }
String getType { return this.type; }
}
Then you can use valueOf() to look up the enum element, and getType() to find out which of your three categories it belongs to.
It isn't entirely clear what you are asking, but perhaps you want to define a mapping between strings and constants, like this:
enum Type { FIRST, SECOND, THIRD };
Map<String, Type> mapping = new HashSet<String, Type>(){{
put("ONE", Type.FIRST);
put("TWO", Type.FIRST);
//...
put("NINE", Type.THIRD);
}};
public Type getTypeFromString(String s) {
return mapping.get(s);
}
I'm trying to define a class (or set of classes which implement the same interface) that will behave as a loosely typed object (like JavaScript). They can hold any sort of data and operations on them depend on the underlying type.
I have it working in three different ways but none seem ideal. These test versions only allow strings and integers and the only operation is add. Adding integers results in the sum of the integer values, adding strings concatenates the strings and adding an integer to a string converts the integer to a string and concatenates it with the string. The final version will have more types (Doubles, Arrays, JavaScript-like objects where new properties can be added dynamically) and more operations.
Way 1:
public interface DynObject1 {
#Override public String toString();
public DynObject1 add(DynObject1 d);
public DynObject1 addTo(DynInteger1 d);
public DynObject1 addTo(DynString1 d);
}
public class DynInteger1 implements DynObject1 {
private int value;
public DynInteger1(int v) {
value = v;
}
#Override
public String toString() {
return Integer.toString(value);
}
public DynObject1 add(DynObject1 d) {
return d.addTo(this);
}
public DynObject1 addTo(DynInteger1 d) {
return new DynInteger1(d.value + value);
}
public DynObject1 addTo(DynString1 d)
{
return new DynString1(d.toString()+Integer.toString(value));
}
}
...and similar for DynString1
Way 2:
public interface DynObject2 {
#Override public String toString();
public DynObject2 add(DynObject2 d);
}
public class DynInteger2 implements DynObject2 {
private int value;
public DynInteger2(int v) {
value = v;
}
#Override
public String toString() {
return Integer.toString(value);
}
public DynObject2 add(DynObject2 d) {
Class c = d.getClass();
if(c==DynInteger2.class)
{
return new DynInteger2(value + ((DynInteger2)d).value);
}
else
{
return new DynString2(toString() + d.toString());
}
}
}
...and similar for DynString2
Way 3:
public class DynObject3 {
private enum ObjectType {
Integer,
String
};
Object value;
ObjectType type;
public DynObject3(Integer v) {
value = v;
type = ObjectType.Integer;
}
public DynObject3(String v) {
value = v;
type = ObjectType.String;
}
#Override
public String toString() {
return value.toString();
}
public DynObject3 add(DynObject3 d)
{
if(type==ObjectType.Integer && d.type==ObjectType.Integer)
{
return new DynObject3(Integer.valueOf(((Integer)value).intValue()+((Integer)value).intValue()));
}
else
{
return new DynObject3(value.toString()+d.value.toString());
}
}
}
With the if-else logic I could use value.getClass()==Integer.class instead of storing the type but with more types I'd change this to use a switch statement and Java doesn't allow switch to use Classes.
Anyway... My question is what is the best way to go about something thike this?
What you are trying to do is called double dispatch. You want the method called to depend both on the runtime type of the object it's called on, and on the runtime type of its argument.
Java and other C derivatives support single dispatch only, which is why you need a kludge like the visitor pattern you used in option 1. This is the common way of implementing it. I would prefer this method because it uses no reflection. Furthermore, it allows you to keep each case in its own method, without needing a big "switchboard" method to do the dispatching.
I'd choose the second option, with the third, I'd better be using generics so you don't rely on that Enum. And with the first option you could be implementing methods for the rest of your life. Anyways you could use "instanceof" operator for Class matching.