Loop through a subset of an enum values - java

I have an enum with 4 values, and I have a method signature that accepts an enum value. I would like to be able to do something with all enum values not passed as the argument to doSomething().
public void doSomething(EnumThing thing){
EnumThing[] thingValues = EnumThing.values();
List<EnumThing> valuesNotPassedAsArg = new ArrayList<EnumThing>();
for(EnumThing th : thingValues){
valuesNotPassedAsArg.add(th);
}
valuesNotPassAsArg.remove(thing);
//here I would loop through all valuesNotPassAsArg and do something with them
}
public enum EnumThing{
SOMETHING, SOMETHINGELSE, ANOTHERTHING;
}
Is there a cleaner way to do this? I feel as if the loop to get the items from the thingValues array is superfluous.

Look into EnumSet. Specifically,
import java.util.EnumSet;
import static java.util.EnumSet.complementOf;
for (EnumThing t : complementOf(EnumSet.of(thing))) {
... do the work ...
}

#Marko's answer is better than this, but it might be helpful to know of this alternative way.
public static void main(String[] args) {
EnumThing thing = EnumThing.ANOTHERTHING;
List<EnumThing> list = new ArrayList<EnumThing>(Arrays.asList(EnumThing.values()));
list.remove(thing);
System.out.println(list);
}
public enum EnumThing{
SOMETHING, SOMETHINGELSE, ANOTHERTHING;
}
This prints out
[SOMETHING, SOMETHINGELSE]

Looking at your title, to iterate a range you do
for (int i = YourEnum.___RANGE___START___.ordinal() +1; i != YourEnum.__RANGE___END___.ordinal() ; i++) {
YourEnumvalue = YourEnum.values()[i];
//use value
}
or this
for (YourEnum value: EnumSet.range(YourEnum.___RANGE___START___, YourEnum.__RANGE___END___)) {
// use value
}
I you just want to skip a single element, then Skip Head's solution might outperform the complementOf, which seems to be an overkill in case of single iteration.

Another way is to use Stream.of method. For example:
public class EnumTest {
public static enum MyEnum {
VALUE1, VALUE2, VALUE3
}
public static void main(String[] args) {
Stream.of(MyEnum.values()).filter(v -> v != MyEnum.VALUE2).forEach(System.out::println);
}
}
Which prints:
VALUE1
VALUE3

public void doSomething(EnumThing thing){
EnumThing[] thingValues = EnumThing.values();
for(EnumThing th : thingValues){
if (th != thing) {
doSomethingElse(th);
}
}
}

Something like this is a little bit better I'd say
public void doSomething(EnumThing thing){
EnumThing[] thingValues = EnumThing.values();
List<EnumThing> valuesNotPassedAsArg = Arrays.asList(thingValues);
valuesNotPassAsArg.remove(thing);
//here I would loop through all valuesNotPassAsArg and do something with them
}
public enum EnumThing{
SOMETHING, SOMETHINGELSE, ANOTHERTHING;
}

Related

How to call a method whose name is the value of a string variable in java?

This is the code of the method that I want to simplify. The method name I call of SerializedExpFamMixture class is exactly the value of "model", my question is how to assign the value of "model" directly as the name of the method instead of using "if" to determine which method I should call. Since by using "if", I need to list all the possible values of "model" and judge which method I should use.
Thank you very much for help. I am new to java.
public static SerializedExpFamMixture RateMtxModel(String model)
{
SerializedExpFamMixture result=new SerializedExpFamMixture();
if(model=="kimura1980()")
result=SerializedExpFamMixture.kimura1980();
if(model=="accordance()")
result=SerializedExpFamMixture.accordance();
if(model=="pair()")
result=SerializedExpFamMixture.pair();
return result;
}
One way you can approach this is to use Reflection:
Method method = myClass.getClass().getMethod("doSomething", null);
method.invoke(myClass, null);
Since you are new to Java, it's time for some general pointers:
In Java, we usually name our methods with camelCase, so the first letter is lower case.
Also, in Java we usually leave the opening curly-bracket on the same line as the code (no newline).
Always use final on your variables. At least your parameters. That way you won't overwrite it, and thus won't have to try to figure out which value it actually has at runtime.
Use curly-brackets! Please!
The result variable is not actually needed.
Use the equals-method to compare Strings.
If you only want one result, use else-if
Fixing these things, your method looks like this:
public static SerializedExpFamMixture rateMtxModel(String model) {
if (model.equals("kimura1980()")) {
return SerializedExpFamMixture.kimura1980();
} else if (model.equals("accordance()")) {
return SerializedExpFamMixture.accordance();
} else if(model.equals("pair()")) {
return SerializedExpFamMixture.pair();
}
return new SerializedExpFamMixture();
}
Next, let's look at what you are actually trying to do here. You want to pass some Strings around, and use them as a basis for creating objects. And now, with the advice given here, you will do this using reflection. This does not sound like a very good idea to me. Say you were to go through with this, and this happened:
rateMtxModel("kinura1980");
Small typo, hard to spot, will give unexpected results. If you were actually calling a method the compiler would let you know that you messed up, now you will get no warning (btw did you see both errors in that method call?). The same if someone were to delete the accordance()-method, the compiler would not alert them that this will break the program.
If it was up to be I would just use the static factory-methods in SerializedExpFamMixture directly, but if you have to do it like this (if the task at hand is using a String input to create an object) I would do something like this:
public enum Something {
KIMURA1980("kimura1980()"),
ACCORDANCE("accordance()"),
PAIR("pair()");
private final String stringValue;
private Something(final String stringValue) {
this.stringValue = stringValue;
}
public static Something fromString(final String string) {
for (final Something something : values()) {
if (something.stringValue.equals(string)) {
return something;
}
}
return null;
}
}
public static SerializedExpFamMixture rateMtxModel(final String model) {
if (model == null) {
throw new IllegalArgumentException("model is null!");
}
final Something something = Something.fromString(model);
if (something == null) {
return new SerializedExpFamMixture();
}
switch(something) {
case KIMURA1980:
return SerializedExpFamMixture.kimura1980();
case ACCORDANCE:
return SerializedExpFamMixture.accordance();
case PAIR:
return SerializedExpFamMixture.pair();
default:
return new SerializedExpFamMixture();
}
}
This way, the one place where you will use the Strings is in the enum, the rest of the code will use the enum constants and thus have the safety of the compiler to rely on.
One could also leave the linking between operation and String to the enum, like this:
interface Operation<T> {
public T run();
}
public enum Something {
KIMURA1980("kimura1980()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.kimura1980();
}
}) ,
ACCORDANCE("accordance()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.accordance();
}
}),
PAIR("pair()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.pair();
}
}),
DEFAULT(null, new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return new SerializedExpFamMixture();
}
});
private final String stringValue;
private final Operation<SerializedExpFamMixture> operation;
private Something(final String stringValue, final Operation<SerializedExpFamMixture> operation) {
this.stringValue = stringValue;
this.operation = operation;
}
public static Something fromString(final String string) {
if (string != null) {
for (final Something something : values()) {
if (string.equals(something.stringValue)) {
return something;
}
}
}
return DEFAULT;
}
public SerializedExpFamMixture getCorrespondingSerializedExpFamMixture() {
return operation.run();
}
}
With this setup in the enum (I think the Operation-part can be trimmed out with Java8), the method will be as simple as:
public static SerializedExpFamMixture rateMtxModel(String model) {
return Something.fromString(model).getCorrespondingSerializedExpFamMixture();
}
Use reflection, but you need to consider a few things:
Bug alert! Comparing Strings using == doesn't work as expected in java - use .equals() instead. However, the solution below bypasses that problem
For the general case, which includes methods not visible to the invoker, you need to consider accessibility, both in finding the method and invoking it
You don't need the result variable, and even if using your code, don't need to initialize it
Try this:
String methodName = model.replace("(", "").replace(")", "");
try {
// getMethod() returns only public methods, getDeclaredMethod() returns any visibility
Method method = SerializedExpFamMixture.class.getDeclaredMethod(methodName);
// if the method is not guaranteed to be visible (eg public) you need this:
method.setAccessible(true);
return (SerializedExpFamMixture) method.invoke(null); // how to invoke on the class object
} catch (Exception forBrevity) {
return new SerializedExpFamMixture();
}

Java String array comparing with enum

given the following code...
private enum EventTypes {
WORK, BREAK, WAIT, CLOSE, COMPLETE
}
public static void main(String[] args) {
System.out.println("BREAK : " + EventTypes.BREAK);
System.out.println(Arrays.asList(EventTypes.values()).contains("WORK"));
System.out.println(Arrays.asList(EventTypes.values()).contains("WOR"));
}
This produces the output...
BREAK : BREAK
false
false
Now, from the output I can see "BREAK" exists as a String - so why does it believe "WORK" does not exist in the above enum?
Enum values aren't strings. Do this :
Arrays.asList(EventTypes.values()).contains(EventTypes.WORK));
If you want to know if your string is the name of an enum value, do
boolean exist = false;
try {
EventTypes.valueOf("WORK");
exist = true;
} catch (IllegalArgumentException e) {}
You can remove the quotes but if you cannot you can parse the String.
Arrays.asList(EventTypes.values()).contains(EventTypes.valueOf("WORK"))
A brittle, but simple approach is to compare the strings
Arrays.toString(EventTypes.values()).contains("WORK")
The later may be ok for unit tests but not suitable for production code.
You can add custom implementation of contains
private enum EventTypes {
WORK, BREAK, WAIT, CLOSE, COMPLETE;
public static boolean contains(String str) {
for (EventTypes enumtype : values()) {
if (enumtype.name().contains(str))
return true;
}
return false;
}
}
Then you can use it like below.
System.out.println(EventTypes.contains("WORK"));
System.out.println(EventTypes.contains("WOR"));
Remember enums are constants and I don't know what you will achieve doing this.
You can read more about enums on Enum Types
Correct usage is
EventTypes enumType =EventTypes.valueOf("WORK");
Try it this way.....
enum EventTypes {
WORK, BREAK, WAIT, CLOSE, COMPLETE
};
public class T {
public static void main(String[] args) {
for(EventTypes e : EventTypes.values()){
if(e.name().equals("WORK")){
System.out.println("True");
}else{
System.out.println("False");
}
}
}
}

How to use enum with values in Java

When I try to use enum to store: "=", ">", "<", etc, I have:
public static enum DataValueModifier {
EQUAL("="),
GREATER_THAN(">"),
GREATER_EUQAL(">="),
LESS_THAN("<"),
LESS_EQUAL("<="),
APPRROXIMATE("~"),
NOT_DETERMINED("ND");
private String value;
private DataValueModifier(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
How do I use it when I try to compare a string to see if it contains a "=" sign, should I do:
if (dataValue.contains(DataValueModifier.EQUAL.getValue())) {
...
}
I understand using enum is the better practice here, but this just looks silly...
Thanks,
David
If you defined a method boolean containedIn(String str) in your enum and imported your enum values of interest (in this case EQUAL), usage would look like:
if (EQUAL.containedIn(dataValue)) {
...
}
First of all, I'd move the "contains" method (or the equivalent of it) to the enum itself by defining an isModifier method.
public static enum DataValueModifier {
...
public boolean isModifier( String modifierString )
{
return modifierString != null && value.equals(modifierString);
}
}
Then, your code looks like this instead:
if (DataValueModifier.EQUAL.isModifier(dataValue))
{
//...
}
But, more importantly, why are you using dataValue instead of the enum in the first place? If you are getting command line input or something or parsing a string equation and then need to figure out the expression I guess I understand. But if you have control of the code then you should just start with the enum and you'll be able to say
if ( dataValueEnum == DataValueModifier.EQUAL ) {
{
//...
}
I'd also consider adding a static method to the enum that converts a given string to the correct enum value. It's not quite as efficient, perhaps, but unless you really care about efficiency it will make your code much cleaner. So add this method to your enum:
public static DataValueModifier toDataValueModifier( String dataValue ) {
if( EQUAL.isModifier( dataValue ) {
return EQUAL;
} else if( GREATER_THAN.isModifier( dataValue ) {
return GREATER_THAN;
} else if...
// Do this for all possible values
} else {
return UNKNOWN;
// Also, add an UNKNOWN to your list of enum values.
}
}
The isModifier and the toDataValueModifier methods might add a bit of ugly code to your DataValueModifier enum, but all your other code will look great. You can now do something like this:
DataValueModifier dataValueEnum = DataValueModifier.toDataValueModifier(dataValue);
if (dataValueEnum == DataValueModifier.EQUAL) {
...
}
or even
switch( DataValueModifier.toDataValueModifier(dataValue) ) {
case EQUAL:
// ...
break;
case GREATER_THAN:
// ...
break;
case GREATER_EQUAL:
// ...
break;
// ... define all the cases you want
case UNKNOWN:
default:
// ...
}
I like to use a static import in these cases.
package mypackage;
public enum DataValueModifier
{
//your enum code
}
then...
import static mypackage.DataValueModifier.*;
public MyClass
{
// code blah blah blah
public void doIt()
{
// more code blah blah
if (dataValue.contains(EQUAL.getValue()))
{
//...
}
}
}
It's a little nicer.

Java, clever way to replace "if not null" statement?

I have a Vector full of longs.
I would like to be able to always call getFirstElement() on a Vector and then perform an action, let's say addToOtherVector(). I want to be able to not worry whether or not there is actually a value to return from my original vector. I think I could do it by overriding addToOtherVector() like so:
//Code to be called when my first vector is not empty
public void addToOtherVector(long s){
othervector.add(s);
}
//Code to be called when my first vector IS empty
public void addToOtherVector(something???){
//does nothing
}
but I'm not sure what i need to do for the something, as it won't accept null as a parameter?
The reason I am doing this is because I don't wish to have to check the size of the vector each time I try to retrieve
Just override the method with a base class. Since Number is the base class to Long, Integer, etc. just use that one :
//Code to be called when my first vector is not empty
public void addToOtherVector(long s){
othervector.add(s);
}
//Code to be called when my first vector IS empty
public void addToOtherVector(Number s){
if (s == null) {
return;
}
othervector.add(((Number) s).longValue());
}
import java.util.Vector;
public class Main {
static Vector otherVector = new Vector();
public static void main(String[] args) {
Vector originalVector = new Vector();
originalVector.add(1);
originalVector.add(null);
originalVector.add(2);
for (Object obj : originalVector) {
addToOtherVector(obj);
}
}
public static void addToOtherVector(long s) {
otherVector.add(s);
System.out.println("adding " + s + " to vector");
}
public static void addToOtherVector(Object obj) {
System.out.println("not adding " + obj + " to vector");
}
}

Dynamically return a list of all class variable values in Java

I am creating a helper class in parsing XML elements, so the developer do not need to know the exact name and capitalization of the XML fields.
private static class TagNames{
public static String RESOURCE_ID = "ResourceId";
public static String RESOURCE_NAME = "ResourceName";
public static String RESOURCE_PRICE = "ResourcePrice";
}
This makes it easier to do things like:
someXMLParser.getValueByTagName(TagNames.RESOURCE_ID);
My question is this. If I want to iterate over all the fields declared in class TagNames, how do I do that? Pseudocode:
For tag in TagNames:
someXMLParser.getValueByTagName(tag)
I know I will probably have to restructure all of this. But I can't figure out a way to make the names easily accessible as well as iterable, without any duplication.
Any suggestions?
You're literally asking for a solution based on reflection, but I think a Java Enum may be a better choice in this case. Building on Frederick's example:
public class EnumTest {
public enum Tags {
RESOURCE_ID("ResourceId"),
REOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice");
private final String tagName;
Tags(String tagName) {
this.tagName = tagName;
}
public String getTagName() {
return tagName;
}
}
public static void main(String[] args) {
for(Tags tag : Tags.values()) {
System.out.println("const:" + tag.name()
+ " tagName:" + tag.getTagName());
}
// API user might do e.g.:
// document.getValueForTag(Tags.REOURCE_NAME);
}
}
Although I agree that you should probably use enums or ResourceBundles, here's a solution to your actual question. A method that generates a Map name -> value from all public constants in a given class (the only thing that's missing should be try / catch or throws)
public static Map<String, Object> getConstantValues(Class<?> clazz){
Map<String, Object> constantValues = new LinkedHashMap<String, Object>();
for(Field field : clazz.getDeclaredFields()){
int modifiers = field.getModifiers();
if(Modifiers.isPublic(mod)
&& Modifiers.isStatic(mod) && Modifiers.isFinal(mod)){
constantValues.put(field.getName(), field.get(null));
}
}
return constantValues;
}
You may want to consider using a ResourceBundle instead of a class to store the tag names. May require a little bit of reworking of your code but it will be easier to produce a list of tags compared to what you are doing now, and adding a new tag won't require much work other then adding a line to the properties file.
You can do this quite easily using enum and an accompanying array:
public class Main {
public enum TagName { RESOURCE_ID, REOURCE_NAME, RESOURCE_PRICE }
private static String[] tags = {"ResourceID", "ResourceName", "ResourcePrice"};
public static String getValueByTagName(TagName tag) {
return tags[tag.ordinal()];
}
public static void main(String[] args) {
System.out.println("Calling by getValueByTagName:");
System.out.println(getValueByTagName(TagName.RESOURCE_ID));
System.out.println("Calling TagName.values() for loop:");
for (TagName t : TagName.values()) {
System.out.println(getValueByTagName(t));
}
}
}
Using an enum is a good fit, especially if you use a custom constructor and the built in "values" method:
public class Main {
public static enum TagName {
RESOURCE_ID("ResourceId"),
RESOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice"),
;
private String s;
private TagName(String s) { this.s = s; }
public String toString() { return this.s; }
public static String[] strings() {
List<String> ss = new ArrayList<String>();
for (TagName tagName : TagName.values()) {
ss.add(tagName.toString());
}
return ss.toArray(new String[ss.size()]);
}
}
public static void main(String[] args) {
// Use TagName.values() for the enums, or for strings...
for (String s : TagName.strings()) {
System.out.println(s);
}
}
}
This way you can simply add new tags and they'll automatically get picked up by the "strings" method; for extra performance you could compute that string array just once, statically, since you can't change the set of enums dynamically. You could get even fancier by auto-generating the tag strings from their constant values, if they are really normalized...

Categories