List<Enum> contains String - java

I have a list of enums like the below -
List<Status> statusList;
Status is defined as below
enum Status { YES , NO , MAYBE }
The list contains
Status stat = Status.YES;
statusList.add(stat);
I have a variable
Status statusVar = Status.YES;
I am trying to a comparison like below but it is not working as I guess it is comparing the references. The below returns false. Can you please suggest a solution?
statusList.contains(statusVar)
EDIT: Below is the code that is not working. Status is string not Enum
import java.util.ArrayList;
import java.util.List;
public class Test {
private enum Status {
YES , NO , MAYBE
}
public static void main (String[] args){
List<Status> statusList = new ArrayList<Status>();
String status = "YES";
statusList.add(Status.YES);
if(statusList.contains(status)){
System.out.println(" Yes ");
} else {
System.out.println(" No ");
}
}
}

If you are performing a contains, it will be much more efficient if you use an EnumSet
Set<Status> status = EnumSet.of(Status.YES);
assert status.contains(Status.YES);
However, List<Status> will also work.
You are right it does compare the reference, but this will only fail if you have
multiple ClassLoaders and the Class Status is actually different.
you create new instances of the Status which you can do using Unsafe.allocateInstance(Status.class)
What is more likely is you are not testing what you think you are and the situation isn't exactly as you have described.

private enum Status {
YES , NO , MAYBE
;
public Status getByName(String name){
for (Status st : Status.values()) {
if (st.toString().equals(name)){
return st;
}
}
return null;
}
}
try this!

You could add a function toString() and contains() as helpers:
private enum Status {
YES("Yes") , NO ("Yes") , MAYBE("Yes");
private final String label;
/**
* Instantiates a new Status.
* #param label the label
*/
private Status (final String label) {
this.label = label;
}
#Override
public String toString() {
return label;
}
public static boolean contains(final String test) {
for (final Status value : Status.values()) {
if (value.toString().equals(test)) {
return true;
}
}
return false;
}
}

enum Status { YES , NO , MAYBE }
public static void main(String[] args) {
List<Status> lista = new ArrayList<>();
lista.add(Status.YES);
Status stat = Status.YES;
System.out.println(lista.contains(Status.YES));//true
System.out.println(lista.contains(stat));//true
}
I made this code and print both ways and it worked perfectly
or
you remembered to instantiate the variable statusList

Related

Setting Variable Name from String in Java from User Input

So I've scoured the internet for a fix, and i've gotten tips to use maps, the reflect method, and a ton of other stuff, but nothing has worked the way I wanted.
My goal is to do something like this:
I have a string divided into an array. Example: "setVal strength 3"
lineArray[0] = setVal
lineArray[1] = strength
lineArray[2] = 3
I want to take lineArray[1] and add "Feats." to the beginning of it, so it it, for example, something like "Feats.strength" (which I can do with a string variable)
I then want to set that variable (Feats.strength, it's a double called strength in the Feats class) to lineArray[2] (which is a double).
else if(lineArray[0].equals("setVal") && lineArray.length == 2){
//Take lineArray[1], which is the name of a variable in
another class, specifically Feats.strength, Feats.agility, etc.
//Set that value in lineArray[1] to lineArray[2]
//Something like
set("Feats." + lineArray[1], lineArray[2]);
Feats.resetStat();
}
Does that make any sense? Thanks for the help in advance!
Maybe something like this would work?
// Application.java
public class Application {
public static void main(String[] args){
String field = "setVal strength 3";
Feats.resolveValue(field);
String field2 = "getVal strength";
Integer value = Feats.resolveValue(field2);
String field3 = "clearAll";
Feats.resolveValue(field3);
}
}
--
// Feats.java
public class Feats {
private static final Logger LOGGER = LoggerFactory.getLogger(Feats.class);
private static final Map<String, Integer> ATTRIBUTES = new HashMap<>();
public static String resolveString(String fieldInput){
String response = null;
String[] values = fieldInput.split(" ");
Action action;
try {
action = Action.valueOf(values[0].trim().toUppercase());
} catch(Exception e){
LOGGER.error("Not a valid Action in input: " + fieldInput);
return response;
}
switch(action){
case SETVALUE:
setValue(values[1].trim(), values[2].trim());
break;
case CLEARALL:
clearAll();
break;
case GETVALUE:
response = getValue(values[1].trim());
break;
default:
assert true;
}
return response;
}
private static void setValue(String attrName, String attrValue){
ATTRIBUTES.put(attrName, attrValue);
}
private static String getValue(String attrName){
return ATTRIBUTES.get(attrName);
}
private static void clearAll(){
ATTRIBUTES.clear();
}
}
--
// Action.java
public enum Action {
SETVALUE, CLEARALL, GETVALUE
}
So I solved it. Thanks to #shmosel for telling me to use a field.
long temp = Long.parseLong(lineArray[2]);
try {
Feats.class.getField(lineArray[1]).set(lineArray[1], temp);;
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e1) {
e1.printStackTrace();
}

If JComboBox is editable, how to cast the entered string to object?

So I have this class "Member" :
package pkgData;
import java.io.Serializable;
public class Member implements Comparable<Member>, Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private String city;
public Member(String nameOfMember,String location) {
super();
this.name = nameOfMember;
this.city=location;
}
public String getNameOfMember() {
return name;
}
public String getLocationOfMember() {
return city;
}
public void setNameOfMember(String nameOfMember) {
this.name = nameOfMember;
}
#Override
public String toString() {
return name +", " + city;
}
#Override
public int compareTo(Member o) {
int result =this.getNameOfMember().compareTo(o.getNameOfMember());
if(result==0){
result = this.getLocationOfMember().compareTo(o.getLocationOfMember());
}
return result;
}
}
And I have a JComboBox which is EDITABLE and the model of the ComboBox is DefaultComboBoxModel.
So the problem is that if I cast the selectedItem:
Member nameOfMember = (Member)memberModel.getSelectedItem();
if(nameOfMember== null)
throw new Exception("please select a name and a location");
It only checks if the entered string is empty. If I enter a string like "Name, Location" I always get the exception that String cannot be cast to Member. Which String to I have to enter that the String can be cast to Member?
Here is my JComboBox:
private JComboBox<Member> getComboBoxMember() {
if (comboBoxMember == null) {
comboBoxMember = new JComboBox<Member>();
comboBoxMember.setEditable(true);
comboBoxMember.setModel(memberModel);
}
return comboBoxMember;
}
and here the global variables:
private DefaultComboBoxModel<Member> memberModel;
private JComboBox<Member> comboBoxMember;
String nameOfMember = (String) memberModel
.getSelectedItem();if(nameOfMember==null)throw new Exception("please select a name and a location");else
{
String[] parts = nameOfMember.split(",");
String part1 = parts[0]; // name
String part2 = parts[1]; // location
Member member=new Member(part1, part2);
}
String split & cast method
What you can do is first of all test if the string you get is null, or if it matches well you format. Then, you can create a new object with these elements.
Here's a small example code :
String memberData = (String)memberModel.getSelectedItem();
if(memberData == null || memberData.split(", ")[0].isEmpty() || memberData.split(", ")[1].isEmpty()) {
throw new Exception("Data is incorrect, please provide name and location separated with ", ");
}
Member member = new Member(memberData.split(", ")[0], memberData.split(", ")[1]);
JComboBox method
With Java 7 happened a new possibility of extension to JComboBox, which can now be generically parameterized (as for ArrayLists) in the form JComboBox<Type>. Thus, the objects you can get with getSelectedItem() can now be casted to the generic type you gave in parameter to JComboBox. The only problem is that, when a JComboBox is edited, as in your case, the data is casted to a simple String.
What you can do in your listener method (I will use ActionListener) is the following :
class ItemAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
try {
//In case the user has not modified the object
Member member = (Member)box.getSelectedItem();
//Just an example here
if(member != null) {
System.out.println(member.toString());
}
} catch(ClassCastException ex) {
//In case the object has been modified
String data = (String)box.getSelectedItem();
//Apply first method here
}
}
}
But the problem with this method is that you end up using the first method still.

Appropriate Java design pattern to avoid method duplication

I have this scenario. I started working with a system that 'process' documents. The problem is, it seems to be the typical scenario where it started small, and went getting bigger and bigger constructing it one chunk at a time and now it needs to be refactored.
Each document type has an identifier (docID), and all of them share the same underlying result structure.
There is a huge master class that does all the job BUT inside this class there are several methods (almost one for each site) with its own logic. They all do almost the same with slight changes (i.e. formatting a string before setting it to a field in the result structure or doing some calculation and then setting the field in the result structure).
For example:
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
private void processDocs(){
Result result = new Result();
result = processDocGeneric(result);
if(docID == 1){
result = processDoc1(result);
}
else if(docID == 2){
result = processDoc2(result);
}
...
}
Ok, so I'm planning to refactor this and I'm considering some design patterns I know but I don't want the feel that I'm killing a roach with a bazooka.
Command pattern is maybe the first that comes to my mind, also Strategy pattern. My major concern with those is that I will have to create a class for every document type that has its own implementation of the processDoc method (There are around 15 at the moment). I mean, if that's the way to go, that would be it but if there's a simpler way of doing it that I don't know, it would be better (since the change is in a single method).
The other thing that I could do is moving all those method to a 'methods' class, and also move the if-else block to a single method with a docID parameter (process(int docID) and then call it from the main class. But that's just splitting the huge class. It would be "cleaner" but not optimal.
What would be the best approach to clean and split this huge class and make it scalable (since there would be new document types to be added in the future)?.
You can use factory or abstract factory design patterns maybe, In this patterns you can get your needed objects without having to specify the exact class of the object that will be created.
I propose a solution based on the Visitable / Visitor Pattern. this solution requires very little change to the Result class, while opening the door to new visiting objects, making it an easily extensible framework. I'm making heavy use of Java8's default interface method.
The Visitor / Visitable Interfaces:
public interface DocVisitor<T extends VisitableDoc> {
default void visit(T document){
switch(document.getDocId()){
case 1:
processDoc1(document);
break;
case 2:
processDoc2(document);
break;
// ... other cases...
default:
processDocGeneric(document);
break;
}
}
void processDocGeneric(VisitableDoc document);
void processDoc1(VisitableDoc document);
void processDoc2(VisitableDoc document);
}
public interface VisitableDoc {
int getDocId();
default void visit(DocVisitor visitor){
visitor.visit(this);
}
}
Slight modification of the Result class:
public class Result implements VisitableDoc { // New interface declared
int getDocId(){
return docId; // This might already exist
}
// Rest is unchanged, the default implementation will suffice
}
A Visitor Implementation:
public class DocProcessor implements DocVisitor<Result> {
#Override
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
#Override
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
#Override
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
}
Usage:
public static final main(String[] args){
List<Result> results = // Obtain results somehow
DocProcessor processor = new DocProcessor();
for(Result result: results){
processor.visit(result);
}
}
[How to] split this huge class and make it scalable (since there would be new document types to be added in the future
What I've done is merely to split Document data on Result class / Document Processing on DocProcessor class. If you have other processing that differ from type to type, and which can be extracted to an external class (no need for private field handling, private methods calling etc.), this framework os completely applicable.
If not, you should REALLY consider refactoring it to use polymophism! Make each Document type its own object. Use a strong abstract class to link them all, and if you have many methods that are shared accross several but not all types, then make sub-types accordingly - or use default methods! Java8 FTW
For this situation is applicable builder pattern.
/**
*
* Hero, the class with many parameters.
*
*/
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
public Profession getProfession() {
return profession;
}
public String getName() {
return name;
}
public HairType getHairType() {
return hairType;
}
public HairColor getHairColor() {
return hairColor;
}
public Armor getArmor() {
return armor;
}
public Weapon getWeapon() {
return weapon;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("This is a ")
.append(profession)
.append(" named ")
.append(name);
if (hairColor != null || hairType != null) {
sb.append(" with ");
if (hairColor != null) {
sb.append(hairColor).append(' ');
}
if (hairType != null) {
sb.append(hairType).append(' ');
}
sb.append(hairType != HairType.BALD ? "hair" : "head");
}
if (armor != null) {
sb.append(" wearing ").append(armor);
}
if (weapon != null) {
sb.append(" and wielding a ").append(weapon);
}
sb.append('.');
return sb.toString();
}
/**
*
* The builder class.
*
*/
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
/**
* Constructor
*/
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}

Java-How do I call a class with a string?

I am a beginner programmer and this is my first question on this forum.
I am writing a simple text adventure game using BlueJ as a compiler, and I am on a Mac. The problem I ran into is that I would like to make my code more self automated, but I cannot call a class with a string. The reason I want call the class and not have it all in an if function is so that I may incorporate more methods.
Here is how it will run currently:
public class textadventure {
public method(String room){
if(room==street){street.enterRoom();}
}
}
public class street{
public enterRoom(){
//do stuff and call other methods
}
}
The if statement tests for every class/room I create. What I would like the code to do is automatically make the string room into a class name that can be called. So it may act like so:
Public method(string room){
Class Room = room;
Room.enterRoom();
}
I have already looked into using Class.forName, but all the examples were too general for me to understand how to use the function. Any help would be greatly appreciated, and if there is any other necessary information (such as more example code) I am happy to provide it.
-Sebastien
Here is the full code:
import java.awt.*;
import javax.swing.*;
public class Player extends JApplet{
public String textOnScreen;
public void start(){
room("street1");
}
public void room(String room){
if(room=="street1"){
textOnScreen=street1.enterRoom();
repaint();
}
if(room=="street2"){
textOnScreen=street2.enterRoom();
repaint();
}
}
public void paint(Graphics g){
g.drawString(textOnScreen,5,15);
}
}
public abstract class street1
{
private static String textToScreen;
public static String enterRoom(){
textToScreen = "You are on a street running from North to South.";
return textToScreen;
}
}
public abstract class street2
{
private static String textToScreen;
public static String enterRoom(){
textToScreen = "You are on another street.";
return textToScreen;
}
}
Seeing as you are rather new to programming, I would recommend starting with some programs that are simpler than a full-fledged adventure game. You still haven't fully grasped some of the fundamentals of the Java syntax. Take, for example, the HelloWorld program:
public class HelloWorld {
public static void main(String[] args) {
String output = "Hello World!"
System.out.println(output);
}
}
Notice that public is lowercased. Public with a capital P is not the same as public.
Also notice that the String class has a capital S.* Again, capitalization matters, so string is not the same as String.
In addition, note that I didn't have to use String string = new String("string"). You can use String string = "string". This syntax runs faster and is easier to read.
When testing for string equality, you need to use String.equals instead of ==. This is because a == b checks for object equality (i.e. a and b occupy the same spot in memory) and stringOne.equals(stringTwo) checks to see if stringOne has the same characters in the same order as stringTwo regardless of where they are in memory.
Now, as for your question, I would recommend using either an Enum or a Map to keep track of which object to use.
For example:
public class Tester {
public enum Location {
ROOM_A("Room A", "You are going into Room A"),
ROOM_B("Room B", "You are going into Room B"),
OUTSIDE("Outside", "You are going outside");
private final String name;
private final String actionText;
private Location(String name, String actionText) {
this.name = name;
this.actionText = actionText;
}
public String getActionText() {
return this.actionText;
}
public String getName() {
return this.name;
}
public static Location findByName(String name) {
name = name.toUpperCase().replaceAll("\\s+", "_");
try {
return Enum.valueOf(Location.class, name);
} catch (IllegalArgumentException e) {
return null;
}
}
}
private Location currentLocation;
public void changeLocation(String locationName) {
Location location = Location.findByName(locationName);
if (location == null) {
System.out.println("Unknown room: " + locationName);
} else if (currentLocation != null && currentLocation.equals(location)) {
System.out.println("Already in room " + location.getName());
} else {
System.out.println(location.getActionText());
currentLocation = location;
}
}
public static void main(String[] args) {
Tester tester = new Tester();
tester.changeLocation("room a");
tester.changeLocation("room b");
tester.changeLocation("room c");
tester.changeLocation("room b");
tester.changeLocation("outside");
}
}
*This is the standard way of formating Java code. Class names are PascalCased while variable names are camelCased.
String className=getClassName();//Get class name from user here
String fnName=getMethodName();//Get function name from user here
Class params[] = {};
Object paramsObj[] = {};
Class thisClass = Class.forName(className);// get the Class
Object inst = thisClass.newInstance();// get an instance
// get the method
Method fn = thisClass.getDeclaredMethod(fnName, params);
// call the method
fn.invoke(inst, paramsObj);
The comments below your question are true - your code is very rough.
Anyway, if you have a method like
public void doSomething(String str) {
if (str.equals("whatever")) {
// do something
}
}
Then call it like
doSomething("whatever");
In Java, many classes have attributes, and you can and will often have multiple instances from the same class.
How would you identify which is which by name?
For example
class Room {
List<Monster> monsters = new ArrayList <Monster> ();
public Room (int monstercount) {
for (int i = 0; i < monstercount; ++i)
monsters.add (new Monster ());
}
// ...
}
Monsters can have attributes, and if one of them is dead, you can identify it more easily if you don't handle everything in Strings.

Why are there compile errors when accessing an Enum from the main method?

So i'm a little bit confused as i've never used an enum before. I want to use this enum in my main method. For some reason, i can't (i keep getting errors anytime i even try to do Status s; in main). I can however call my TestingEnum method from main and of course this works... but i am 100% sure that using the enum this way is just plain wrong. Could someone tell me how i'd go about using this in main properly?
If i try to do: Status s; in my main method, i get this error - "connot find symbol Status s;"
BACKGROUND: new to java and enums...
class MyClass {
public Status s;
public enum Status {
STATUS_OPEN(1),
STATUS_STARTED(2),
STATUS_INPROGRESS(3),
STATUS_ONHOLD(4),
STATUS_COMPLETED(5),
STATUS_CLOSED(6);
private final int status;
Status(int stat) {
this.status = stat;
}
public int getStatus() {
return this.status;
}
}
private void setStatus(Status stat) {
s = stat;
}
public void TestingEnum() {
Status myStat = Status.STATUS_ONHOLD;
setStatus(myStat);
}
#Override
public String toString() {
StringBuilder result = new StringBuilder();
String NEW_LINE = System.getProperty("line.separator");
result.append(NEW_LINE + " Status: " + s + NEW_LINE);
return result.toString();
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
// PROBLEM SETTING STATUS HERE
// I can't do this:
Status s;
}
}
Move the enum to its own class file, or access it with a reference to the enclosing class.
It looks like you defined the Enum as an inner class of another class. If you're doing this, you need to access it with the syntax OuterClass.Status to access it. You made it public, so that will work. You can access it from within the class with no problem because it's contained in the scope of the parent class.
So you can either add the OuterClass. before Status, or you can move the Enum into its own file like any other class.
From the limited code I think the problem is that you try to access
public Status s;
which is not static from the static method main
public static void main(String[] args) {
...
}
Create a instance of your class from main and have a method on that instance use s or declare s as static.
You cannot just instantiate an Enum just before a public class like that. One way to resolve the issues is to have an outer class which will have your Enum class as inner class like this:
public class MyStatus {
static enum Status {
STATUS_OPEN(1),
STATUS_STARTED(2),
STATUS_INPROGRESS(3),
STATUS_ONHOLD(4),
STATUS_COMPLETED(5),
STATUS_CLOSED(6),
ABANDONED(7);
private final int status;
Status(int stat) {
this.status = stat;
}
public int getStatus() {
return this.status;
}
}
private Status s;
public void setStatus(Status stat) {
s = stat;
}
public void TestingEnum() {
Status myStat = Status.ABANDONED;
setStatus(myStat);
}
#Override
public String toString() {
StringBuilder result = new StringBuilder();
String NEW_LINE = System.getProperty("line.separator");
result.append(NEW_LINE + " Status: " + s + NEW_LINE);
return result.toString();
}
}
Also ABANDONED wasn't defined so I just added it in the end.
Based on your edit. The problem you have is the name of the class is nested and called MyClass.Status
Try
public static void main(String[] args) {
MyClass obj = new MyClass();
//PROBLEM SETTING STATUS HERE
//I can't do this:
MyClass.Status s = MyClass.Status.STATUS_OPEN;
}
BTW: Your IDE should be able to auto fix this mistake.
The only compilation error I see is that you have used
Status myStat = Status.ABANDONED;
without defining it. I suggest you add this enum or use one you have defined.
I resolved this error by creating a nonstatic enum as outside the class.
public enum Status {
STATUS_OPEN(1),
STATUS_STARTED(2),
STATUS_INPROGRESS(3),
STATUS_ONHOLD(4),
STATUS_COMPLETED(5),
STATUS_CLOSED(6),
ABANDONED(7);
private final int status;
Status(int stat) {
this.status = stat;
}
public int getStatus() {
return this.status;
}
}
Created MyStatus class without inner enum block:
public class MyStatus {
private Status s;
public void setStatus(Status stat) {
s = stat;
}
public void TestingEnum() {
Status myStat = Status.ABANDONED;
setStatus(myStat);
}
#Override
public String toString() {
StringBuilder result = new StringBuilder();
String NEW_LINE = System.getProperty("line.separator");
result.append(NEW_LINE + " Status: " + s + NEW_LINE);
return result.toString();
}
}
Resolved for me.
You would not be able to refer to Status in main() because, while Status is public, it is not static. You would need to create an instance of your enclosing class and then use it to create an instance of the enum:
MyEnclosingClass clz = new MyEnclosingClass();
Status status = clz.new Status();
This should resolve the error I believe you are probably getting.

Categories