Dequeue Testing - java

Could anyone tell me / explain how can I make a proper test of a Dequeue?
I have implemented a Priority Queue and in order to verify it I have done some junit tests.
I'm rather new to java so maybe I'm making some huge mistakes when trying to verify my implementation of a priority queue.
The test code :
#Test
public void testDequeue() throws MyException {
System.out.println("Dequeue");
PQueue q=new PQueue();
PQueue o=new PQueue();
q.Enqueue("abc", 1); // Enqueue with an object and a priority
q.Dequeue();
System.out.println(q.dim()); // to see if the dequeue worked
o.Enqueue("def", 2);
assertTrue(o.equals(q));
}
Pqueue Code:
public class PQueue<E> implements IPQueue<E>,Serializable{
private int size,front,rear;
private LinkedList<ListNode> list;
public PQueue()
{
front=0;
rear=0;
list=new LinkedList<ListNode>();
}
public void Enqueue(E obj, int p) throws MyException
{
if (obj==null) throw new MyException("Did not enqueued");
if (rear==0)
{
front=rear=1;
list.add(new ListNode(obj, p));
}
else
{
rear++;
int x= list.size();
for(int i=0;i<x-1;++i)
{
if(list.get(i).GetPriority() < p) list.add(i, new ListNode(obj, p));
}
}
}
public E Dequeue() throws MyException
{
if(rear==0) throw new MyException("Cannot dequeue; queue is empty!");
rear--;
return (E) list.getLast();
}
public int IsEmpty()
{
if(rear==0)
return 1;
else
return 0;
}
public int IsFull()
{
if(rear-front+2>size)
return 1;
else
return 0;
}
public void MakeEmpty()
{
size=0;
}
public int dim()
{
return rear;
}
public LinkedList<ListNode> getList()
{
return list;
}
#Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if (!(obj instanceof PQueue)) {
return false;
}
PQueue p = (PQueue)obj;
return (obj==p);
}
}

Your tests should test all possiblities of how the code may react to inputs. It is usually helpful to think about the testcases prior of coding the actual code which shall be tested. (Search for 'Test Driven Development' for a interesting, more dogmatic view on this issue)
I just wrote 4 tests: 2 testing the regular behavior, 2 testing exceptional cases.
I usually create some 'instance' member which I used for testing, which reduces each unit test by one line where I would otherwise have to create an instance (less code, less work).
Do not test ListNode in the code (that should be tested in ListNodeTest).
My tests below assume that new ListNode(2,1).equals( new ListNode(2,1) ).
private final PQueue<Integer> instance = new PQueue<Integer>();
#Test
public void testDequeue() throws Exception
{
System.out.println( "Dequeue" );
instance.Enqueue( 2, 1 );
assertEquals( new ListNode<Integer>(2, 1), instance.Dequeue() );
}
#Test
public void testDequeue_DequeuedTwice() throws Exception
{
System.out.println( "Dequeue_DequeuedTwice" );
instance.Enqueue( 2, 1 );
instance.Enqueue( 3, 2 );
assertEquals( new ListNode<Integer>(2, 1), instance.Dequeue() );
}
#Test( expected=MyException.class)
public void testDequeue_Empty() throws Exception
{
System.out.println( "Dequeue_Empty" );
instance.Dequeue();
}
#Test( expected=MyException.class)
public void testDequeue_DequeuedTwice() throws Exception
{
System.out.println( "Dequeue_DequeuedTwice" );
instance.Enqueue( 2, 1 );
instance.Dequeue();
instance.Dequeue();
}
One point, you may define new ListNode<Integer>(2, 1) as a static final for the test. I did not. Maybe I would have if I had used it 3 times...
Some other notes:
Have a look at http://www.oracle.com/technetwork/java/codeconventions-135099.html#367. Method names in Java are supposed to start with a lowercase letter.
You may argue that I myself violate that convention by introducing underscores '_' in the method names of testcase. I think thats handy, so I knowningly violate that convention for unit tests. Flame me for that.
Maybe you should also have a closer look at the junit FAQ http://junit.sourceforge.net/doc/faq/faq.htm.
You may think about changing the name of PQueue to PrioQueue or PriorityQueue.
And I would heavily recommend to test the equals() method thoroughly, in order to get from the code what you expect. Have a look what equals() is usually supposed to do. You are also missing a hashCode() method, which is commonly implemented when overwriting equals() yourself.

This doesn't make sense:
PQueue p = (PQueue)obj;
return (obj==p);
It's identical to:
return (p==p);
You might have meant:
return (this == p);
but that wouldn't really work either - that case is already dealt with by the first if clause.
If you want to compare the contents of the queues for equality, you'll need to iterate over them and check each of the items in both queues. Since you're using a linked list, you can do that directly:
return this.list.equals(p.list);

Related

Assert two List have same subtypes in a certain order

I would like to check if two lists (let's say, ArrayLists) have exactly the same instance classes, based in an expected List.
To do so, I have built the next method, but I was wondering whether there is another fancy way using certain library, like assertJ.
private void assertConcreteTypes(List actual, List expected) {
for (int i = 0; i < actual.size(); i++){
assertThat(actual.get(i)).isExactlyInstanceOf(expected.get(i).getClass());
}
}
Any suggestion would be more than welcome. Thanks!
You can create a custom Assertj asserter and leverage it for asserting types.
class TypeAssert extends AbstractAssert<TypeAssert, List<?>> {
public TypeAssert(List<?> actual) {
super(actual, TypeAssert.class);
}
public TypeAssert hasElementsOfExactlyTheSameTypeAs(List<?> expected) {
isNotNull();
for (int i = 0; i < actual.size(); i++) {
if (!actual.get(i).getClass().equals(expected.get(i).getClass())) {
failWithMessage("Expected [%s]th element to be of type: %s but was of type: %s",
i, expected.get(i).getClass(), actual.get(i).getClass());
}
}
return this;
}
}
You'll need a static method that will expose the object of our Custom Exporter.
class Assertions {
// static factory method which exposes custom asserted
static TypeAssert assertThat(List<?> actual) {
return new TypeAssert(actual);
}
}
And then you can use the above method for asserting based on type.
List<Object> actual = List.of(new Employee());
List<Object> expected = List.of(new StringBuilder());
Assertions.assertThat(actual).hasElementsOfExactlyTheSameTypeAs(expected);
If you are asserting based on a type only at a very few places then I think the approach you have mentioned is much cleaner and readable. But if you need such assertion at several places then may be creating a custom assertion is a good choice.
You need to take into account lists of different sizes as well as null elements in the lists.
This seems quite readable and caters to these edge cases:
private void assertConcreteTypes(List actual, List expected) {
assertEquals(classes(expected), classes(actual));
}
private List<Class<?>> classes(List<Object> list) {
return list.stream().map(v -> v == null ? null : v.getClass()).collect(Collectors.toList());
}

Remove independent if conditions

Refer below code structure which I want to refactor:
#Builder
#Value
class ReasonAndAction {
String reason;
String action;
}
ReasonAndAction decideReasonAndAction(Input input) {
if(condition1(input)) {
return reactionAndAction1;
}
if(condition2(input)) {
return reactionAndAction2;
}
if(condition3(input)) {
return reactionAndAction3;
}
return ReasonAndAction.builder()
.reason("default")
.action("default")
.build();
}
All the if conditions are independent and may have some default behavior (else case). There may be need to add more if conditions with next versions which will make code bit ugly.
I want to remove if conditions and abstract out in separate classes and execute independently rather sequential.
Expected Behaviour :
Dont Have all If conditions at same place
If 2 or more if conditions are satisfied at the same time , then return new ReasonAndAction object in decideReasonAndAction method . Example - action : DO_SOMETHING , reason : CONDITION_1_AND_CONDITION_2_MET
Basically , execute all if conditions independently and get the result of all if conditions and then take action and reason accordingly.
What Java design pattern can be used here(if any) for meaningful abstraction such that default behavior(else condition at the end) is also maintained?
Can somebody please explain with example/pseudocode?
Your question is very interesting. And you have one condition:
If 2 or more conditions are satisfied, there are two or more actions and two or more reasons.
In my view, it can be solved by delegating of checking these conditions before the execution of class. However, the class should be very simple.
So let us start. This is a bad design as if we want to add new operation, then we need to add new else condition. So by doing this, we violate open closed principle of SOLID.
public class Calculator
{
public int Exec(int a, int b, string operation)
{
if (operation == "+")
return a + b;
else if (operation == "-")
return a - b;
else if (operation == "/")
return a / b;
return a * b;
}
}
What can we do? We can create an interface and use dependency inversion principle of SOLID.
Our interface:
public interface IOperation
{
int Exec(int a, int b);
}
and class:
public class CalculatorWithDependencyInversionPrinciple
{
public int Exec(IOperation operation, int a, int b)
{
return operation.Exec(a, b);
}
}
and extensions:
public class SumOperation : IOperation
{
public int Exec(int a, int b)
{
return a + b;
}
}
And if you want to add new functionality, then you need to add new class with implemented Operation interface. So our class CalculatorWithDependencyInversionPrinciple is closed for modification, but it is open for extension.
And this is a strategy pattern in action.
And you can call it like this:
int result = new CalculatorWithDependencyInversionPrinciple()
.Exec(new SumOperation(), 1, 2);
Output will be: 3
So far so good, but we want to have different operators ("Reasons" in your task) and our code should be simple and testable. In addition, we will try to make that our classes will have just one single responsibility. Read more about Single Responsibility Principle of SOLID.
So this is our operators:
public enum Operator // Reason
{
Plus,
Minus,
Divide,
Multiply
}
And this is mapping between Operator and its Operation:
public class OperationToOperator
{
public Dictionary<Operator, IOperation> OperationByOperator =
new Dictionary<Operator, IOperation>
{
{ Operator.Plus, new SumOperation() },
{ Operator.Minus, new MinusOperation() },
{ Operator.Divide, new DivideOperation() },
{ Operator.Multiply, new MultiplyOperation() },
};
}
Our condition class:
public class Condition
{
public Operator Operator { get; private set; }
public int A { get; private set; }
public int B { get; private set; }
public Condition(Operator operato, int a, int b)
{
Operator = operato;
A = a;
B = b;
}
}
and code would be executed like this:
List<Condition> conditions = new List<Condition>
{
new Condition(Operator.Plus, 1, 2),
new Condition(Operator.Minus, 4, 3),
new Condition(Operator.Multiply, 5, 6),
new Condition(Operator.Divide, 8, 2),
};
OperationToOperator operationToOperator = new OperationToOperator();
CalculatorWithDependencyInversionPrinciple calculatorWithDependencyInversionPrinciple
= new CalculatorWithDependencyInversionPrinciple();
foreach (Condition condition in conditions)
Console.WriteLine
(
calculatorWithDependencyInversionPrinciple.Exec
(
operationToOperator.OperationByOperator[condition.Operator],
condition.A,
condition.B
)
);
So we've created simple classes that are testable and we used Strategy pattern.

When building containers why is using Java Generics better than using the Object Class? (Java Generics & DataStructures)

So I have been reviewing my data structures and came across an interesting thought regarding Java generics and the Object class. I have implemented and run a "generic bag" in two different ways (Notice below: IObjectBag.java, ObjectBag.java, IGenericBag.java, and GenericBag.java) and have used them both (Notice: Below main.java and Output). I have removed some of the unnecessary code as per stack overflow rules but if you want the full implementation, let me know.
Also, I have researched the topic in many websites, books and courses in addition to looking at the source code for the ArrayList class here and I understand that my GenericBag is a better option than my ObjectBag but not well enough to explain it in a practical way during an interview. And I am confused that my GenericBag uses more casting operations than my ObjectBag in its implementation (see Remove and PrintBag).
So, other than the syntactic sugar, why is my GenericBag better? Please use my classes as examples.
Are there any important differences in runtime/overhead/space/time I am not noticing?
How would you answer this question or expect it to be answered in an interview?
Bonus questions: If you want, please answer the bonus questions in the Main and GenericBag comments (I think I can answer them myself though, just want to hear your opinion).
IObjectBag interface:
public interface IObjectBag {
void add(Object item);
Object remove(Object item) throws NoSuchElementException;
boolean isEmpty();
int find(Object item);
Object get(int index);
int numItems();
}
ObjectBag class:
public class ObjectBag implements IObjectBag {
private Object [] items; // the java class attribute that will hold out "ints"
private int numItems;
public static void printBag(IObjectBag bag) {
for(int i = 0; i < bag.numItems(); i++) {
System.out.println(bag.get(i));
}
}
public ObjectBag(int size) {
this.items = new Object[size]; // fills array with null values
this.numItems = 0;
}
public void add(Object item){
// adds item to end of bag
}
public Object remove(Object item) {
int index = this.find(item);
if(index == -1) throw new NoSuchElementException("oops nothing found");
Object out = this.items[index];
this.items[index] = null;
this.numItems -= 1;
if(index + 1 != this.items.length && this.items[index + 1] != null) {
for(int i = index; i < this.items.length; i++) {
if(i + 1 != this.items.length) this.items[i] = this.items[i + 1];
}
this.items[this.items.length - 1] = null;
}
return out;
}
public int find(Object item) {
// return index given item or -1
}
public Object get(int index) {
// returns item given index
}
}
IGenericBag class:
public interface IGenericBag <T> {
void add(T item);
T remove(T item) throws NoSuchElementException;
boolean isEmpty();
int find(T item);
T get(int index);
}
GenericBag class:
public class GenericBag<T> implements IGenericBag<T> {
// private T[] items; can't use this b/c see comment in constructor
private Object[] items;
private int numItems;
public static void printBag(GenericBag bag) {
for(int i = 0; i < bag.numItems(); i++) {
System.out.println(bag.get(i));
}
}
public GenericBag(int size) {
// this.items = new T[size]; Bonus: throws generic array creation error (why?)
this.items = new Object[size];
this.numItems = 0;
}
public void add(T item){
this.items[this.numItems] = item;
this.numItems += 1;
}
public T remove(T item) {
int index = this.find(item);
if(index == -1) throw new NoSuchElementException("oops nothing found");
T out = (T) this.items[index];
this.items[index] = null;
this.numItems -= 1;
if(index + 1 != this.items.length && this.items[index + 1] != null) {
for(int i = index; i < this.items.length; i++) {
if(i + 1 != this.items.length) this.items[i] = this.items[i + 1];
}
this.items[this.items.length - 1] = null;
}
return out;
}
public int find(Object item) {
// given object return index or throw exception
}
public T get(int index) {
return (T) this.items[index];
}
}
Main class:
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
System.out.println("Hello StackOverFlow!");
Object int1 = new Integer(1);
Object int2 = new Integer(2);
Object int3 = new Integer(3);
/* using my object bag ************************************************/
System.out.println("using my object bag");
IObjectBag myObjectBag = new ObjectBag(3);
myObjectBag.add(int1);
myObjectBag.add(int2);
myObjectBag.add(int3);
myObjectBag.remove(int2);
ObjectBag.printBag(myObjectBag);
/* using my generic bag ***********************************************/
System.out.println("using generic bag");
// Bonus Question: using object like above causes error at add method (why?)
Integer int4 = new Integer(4);
Integer int5 = new Integer(5);
Integer int6 = new Integer(6);
GenericBag<Integer> myGenericBag = new GenericBag<Integer>(3);
//Bonus Question: using Interface decllaration like above causes error in print bag (why?)
myGenericBag.add(int4);
myGenericBag.add(int5);
myGenericBag.add(int6);
myGenericBag.remove(int4);
GenericBag.printBag(myGenericBag);
}
}
Output:
Hello StackOverFlow!
using my object bag
1
3
using generic bag
5
6
Problems with your ObjectBag that are 'automaticaly' solved by the type safety offered by your GenericBag implementation:
Accessing an entry returns Object, at this stage you do not know of what type Object is.
You can insert any types of Objects (mixed) e.g a String and an Integer into the same list, this is an anti pattern and causes non readable code (try it with your Generics bag!)
Because your compiler knows the type of your GenericBag after you have declared it, at any stage of your code if you hover over your genericBag instance you will know its type, this makes your code more readable and also extendable for other people
Generics also offer way more, imagine you want your GenericBag to only accept numbers, then you could write it as follows:
public class GenericBag<T extends Number>
My suggestion for you is to read some articles on Java basics and especially Generics, having a praxis based way of learning is a good thing, but there are plenty articles that can give you some very nice theoretical insight on the matter.
https://www.baeldung.com/java-generics
Reason of using, let's say, GenericBag<String> over ObjectBag is essentially the same as for using String (or any other type) over an Object:
Type safety.
You declare that some method returns a collection of Strings and nothing else, thus preventing yourself from putting there other objects, or trying to treat what you get from a bag as some other type. This might sound stupid when you have 100 lines of code, but this may save you lot of debugging time when you work with decent codebase.
Although, type safety is not a silver bullet, it is just an instrument, that some people find useful and some don't. I'm pretty sure it is a popular holywar topic for any programming forum.
If you feel comfortable working without this paradigm (Javascript background, right?), you might consider trying some dynamically typed language like Python instead of Java.

Populating a Boolean Array in Java

As a fairly green Java coder I've set myself the hefty challenge of trying to write a simple text adventure. Unsurprisingly, I've encountered difficulties already!
I'm trying to give my Location class a property to store which exits it contains. I've used a boolean array for this, to essentially hold true/false values representing each exit. I'm not entirely convinced that
a) this is the most efficient way to do this and
b) that I'm using the right code to populate the array.
I would appreciate any and all feedback, even if it is for a complete code over-haul!
At present, when instantiating a Location I generate a String which I send through to the setExits method:
String e = "N S U";
secretRoom.setExits(e);
In the Location class, setExits looks like this:
public void setExits(String e) {
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
else if (e.contains("S"))
bexits[2] = true;
else if (e.contains("E"))
bexits[3] = true;
else if (e.contains("U"))
bexits[4] = true;
else if (e.contains("D"))
bexits[5] = true;
}
I'll be honest, I think this looks particularly clunky, but I couldn't think of another way to do it. I'm also not entirely sure now how to write the getExits method...
Any help would be welcome!
The most efficient and expressive way is the following:
Use enums as Exits and use an EnumSet to store them. EnumSet is an efficient Set implementation that uses a bit field to represent the enum constants.
Here is how you can do it:
public enum Exit { North, West, South, East, Up, Down; }
EnumSet<Exit> set = EnumSet.noneOf(Exit.class); // An empty set.
// Now you can simply add or remove exits, everything will be stored compactly
set.add(Exit.North); // Add exit
set.contains(Exit.West); // Test if an exit is present
set.remove(Exit.South); //Remove an exit
Enum set will store all exits in a single long internally, so your code is expressive, fast, and saves a lot of memory.
Is there any reason why you are doing this with Strings and aren't passing in booleans, i.e.
public void setExits(boolean N, boolean E, boolean S, boolean W, boolean U, boolean D)
Or having setters?
public void setNorthOpen(boolean open)
{
bexits[4] = open;
}
Secondly, why are you storing the exits as an array of booleans, it's a small finite set, why not just
boolean N,S,E,W,U,D;
As then you don't need to keep track of which number in the array each direction is.
Also
This is a correct answer (if not completely optimal like that of #gexicide) but I fully encourage anyone to look at the other answers here for an interesting look at how things can be done in Java in different ways.
For future reference
Code which works belongs on Code Review, not Stack Overflow. Although as #kajacx pointed out, this code shouldn't -in fact- work.
OK, first of all, your setExits() method will not work as intended, chained if-elseif will maximally execute 1 branch of code, for example:
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
Even if e contains both N and W, only bexits[0] will be set. Also this method will only add exits (for example calling setExits("") will not delete any existing exits.
I would change that method to:
bexits[0] = e.contains("N");
bexits[1] = e.contains("W");
...
Also, i definetly wouldn't remember that north is on index 0, west in on 1, ... so a common practice is to name your indexes using final static constants:
public static final int NORTH = 0;
public static final int WEST = 1;
...
Then you can write in your setExits method:
bexits[NORTH] = e.contains("N");
bexits[WEST] = e.contains("W");
...
(much more readible)
Finally, if you want your code even more well-arranged, you can make a Exits class representing avaliable exits, and backed by boolean array. Then on place where you create your String, you could create this class instead and save yourself work with generating and then parsing a string.
EDIT:
as #gexicide answers, there is a really handy class EnumSet which would be probably better for representing the exits than bollean array.
The EnumSet in the other answer is the best way to do this, I just wanted to add one more thing though for the future when you start looking not just at whether you can move but where you are moving to.
As well as EnumSet you also have EnumMap.
If you define a Room class/interface then inside the Room class you can have
Map<Direction, Room> exits = new EnumMap<>(Direction.class);
You can now add your links into the map as follows:
exits.put(Direction.NORTH, theRoomNorthOfMe);
Then your code to move between rooms can be very general purpose:
Room destination=currentRoom.getExit(directionMoved);
if (destination == null) {
// Cannot move that way
} else {
// Handle move to destination
}
I would create an Exit enum and on the location class just set a list of Exit objects.
so it would be something like:
public enum Exit { N, S, E, W, U, D }
List<Exit> exits = parseExits(String exitString);
location.setExits(exits);
Given what your code looks like, this is the most readable implementation I could come up with:
public class Exits {
private static final char[] DIRECTIONS = "NSEWUD".toCharArray();
public static void main(String... args) {
String input = "N S E";
boolean[] exits = new boolean[DIRECTIONS.length];
for(int i = 0; i< exits.length; i++) {
if (input.indexOf(DIRECTIONS[i]) >= 0) {
exits[i] = true;
}
}
}
}
That being said, there's a number of cleaner solutions possible. Personally I would go with enums and an EnumSet.
By the way, your original code is incorrect, as it will set as most one value in the array to true.
If you're defining exits as a string, you should use it. I would do it like:
public class LocationWithExits {
public static final String NORTH_EXIT="[N]";
public static final String SOUTH_EXIT="[S]";
public static final String EAST_EXIT="[E]";
public static final String WEST_EXIT="[W]";
private final String exitLocations;
public LocationWithExits(String exitLocations) {
this.exitLocations = exitLocations;
}
public boolean hasNorthExit(){
return exitLocations.contains(NORTH_EXIT);
}
public static void main(String[] args) {
LocationWithExits testLocation=new LocationWithExits(NORTH_EXIT+SOUTH_EXIT);
System.out.println("Has exit on north?: "+testLocation.hasNorthExit());
}
}
using array of booleans might cause a lot of problems if you forget what exactly means bexits[0]. Os it for north or south? etc.
or you can just use enums and list of exits available . Then in methid test if list contain a certain enum value
Personally, I think you can hack it around a bit using an enum and turn the following:
public void setExits(String e) {
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
else if (e.contains("S"))
bexits[2] = true;
else if (e.contains("E"))
bexits[3] = true;
else if (e.contains("U"))
bexits[4] = true;
else if (e.contains("D"))
bexits[5] = true;
}
into
public enum Directions
{
NORTH("N"),
WEST("W"),
SOUTH("S"),
EAST("E"),
UP("U"),
DOWN("D");
private String identifier;
private Directions(String identifier)
{
this.identifier = identifier;
}
public String getIdentifier()
{
return identifier;
}
}
and then do:
public void setExits(String e)
{
String[] exits = e.split(" ");
for(String exit : exits)
{
for(Directions direction : Directions.values())
{
if(direction.getIdentifier().equals(exit))
{
bexits[direction.ordinal()] = true;
break;
}
}
}
}
Although after having written it down, I can't really tell you if it's that much better. It's easier to add new directions, that's for sure.
All the approaches listed in the answeres are good. But I think the approach you need to take depends on the way you are going to use the exit field. For example if you are going to handle exit as strings then Ross Drews approach would require a lot of if-else conditions and variables.
String exit = "N E";
String[] exits = exit.split(" ");
boolean N = false, E = false, S = false, W = false, U = false, D = false;
for(String e : exits){
if(e.equalsIgnoreCase("N")){
N = true;
} else if(e.equalsIgnoreCase("E")){
E = true;
} else if(e.equalsIgnoreCase("W")){
W= true;
} else if(e.equalsIgnoreCase("U")){
U = true;
} else if(e.equalsIgnoreCase("D")){
D = true;
} else if(e.equalsIgnoreCase("S")){
S = true;
}
}
setExits(N, E, S, W, U, D);
Also if you have an exit and you want to check whether a location has that particular exit then again you will have to do the same
public boolean hasExit(String exit){
if(e.equalsIgnoreCase("N")){
return this.N; // Or the corresponding getter method
} else if(e.equalsIgnoreCase("E")){
return this.E;
} else if(e.equalsIgnoreCase("W")){
return this.W;
} else if(e.equalsIgnoreCase("U")){
return this.U;
} else if(e.equalsIgnoreCase("D")){
return this.D;
} else if(e.equalsIgnoreCase("S")){
return this.S;
}
}
So if you are going to manipulate it as a string, in my opinion the best approach would be to go for list and enum. By this way you could do methods like hasExit, hasAnyExit, hasAllExits, hasNorthExit, hasSouthExit, getAvailableExits etc etc.. very easily. And considering the number of exits (6) using a list (or set) wont be an overhead. For example
Enum
public enum EXIT {
EAST("E"),
WEST("W"),
NORTH("N"),
SOUTH("S"),
UP("U"),
DOWN("D");
private String exitCode;
private EXIT(String exitCode) {
this.exitCode = exitCode;
}
public String getExitCode() {
return exitCode;
}
public static EXIT fromValue(String exitCode) {
for (EXIT exit : values()) {
if (exit.exitCode.equalsIgnoreCase(exitCode)) {
return exit;
}
}
return null;
}
public static EXIT fromValue(char exitCode) {
for (EXIT exit : values()) {
if (exit.exitCode.equalsIgnoreCase(String.valueOf(exitCode))) {
return exit;
}
}
return null;
}
}
Location.java
import java.util.ArrayList;
import java.util.List;
public class Location {
private List<EXIT> exits;
public Location(){
exits = new ArrayList<EXIT>();
}
public void setExits(String exits) {
for(char exitCode : exits.toCharArray()){
EXIT exit = EXIT.fromValue(exitCode);
if(exit != null){
this.exits.add(exit);
}
}
}
public boolean hasExit(String exitCode){
return exits.contains(EXIT.fromValue(exitCode));
}
public boolean hasAnyExit(String exits){
for(char exitCode : exits.toCharArray()){
if(this.exits.contains(EXIT.fromValue(exitCode))){
return true;
}
}
return false;
}
public boolean hasAllExit(String exits){
for(char exitCode : exits.toCharArray()){
EXIT exit = EXIT.fromValue(exitCode);
if(exit != null && !this.exits.contains(exit)){
return false;
}
}
return true;
}
public boolean hasExit(char exitCode){
return exits.contains(EXIT.fromValue(exitCode));
}
public boolean hasNorthExit(){
return exits.contains(EXIT.NORTH);
}
public boolean hasSouthExit(){
return exits.contains(EXIT.SOUTH);
}
public List<EXIT> getExits() {
return exits;
}
public static void main(String args[]) {
String exits = "N E W";
Location location = new Location();
location.setExits(exits);
System.out.println(location.getExits());
System.out.println(location.hasExit('W'));
System.out.println(location.hasAllExit("N W"));
System.out.println(location.hasAnyExit("U D"));
System.out.println(location.hasNorthExit());
}
}
Why not this if you want a shorter code:
String symbols = "NWSEUD";
public void setExits(String e) {
for (int i = 0; i < 6; i++) {
bexits[i] = e.contains(symbols.charAt(i));
}
}
If you want a generic solution you can use a map, which maps from a key (in your case W, S, E.. ) to a corresponding value (in your case a boolean).
When you do a set, you update the value the key is associated with. When you do a get, you can take an argument key and simply retrieve the value of the key. This functionality does already exist in map, called put and get.
I really like the idea of assigning the exits from a String, because it makes for brief and readable code. Once that's done, I don't see why you would want to create a boolean array. If you have a String, just use it, although you might want to add some validation to prevent accidental assignment of strings containing unwanted characters:
private String exits;
public void setExits(String e) {
if (!e.matches("[NSEWUD ]*")) throw new IllegalArgumentException();
exits = e;
}
The only other thing I would add is a method canExit that you can call with a direction parameter; e.g., if (location.canExit('N')) ...:
public boolean canExit(char direction) {
return exits.indexOf(direction) >= 0;
}
I like enums, but using them here seems like over-engineering to me, which will rapidly become annoying.
**Edit**: Actually, don't do this. It answers the wrong question, and it does something which doesn't need to be done. I just noticed #TimB's answer of using a map (an EnumMap) to associate directions with rooms. It makes sense.
I still feel that if you only need to track exit existence, a String is simple and effective, and anything else is over-complicating it. However, only knowing which exits are available isn't useful. You will want to go through those exits, and unless your game has a very plain layout it won't be doable for the code to infer the correct room for each direction, so you'll need to explicitly associate each direction with another room. So there seems to be no actual use for any method "setExits" which accepts a list of directions (regardless of how it's implemented internally).
public void setExits(String e)
{
String directions="NwSEUD";
for(int i=0;i<directions.length();i++)
{
if(e.contains(""+directions.charAt(i)))
{
bexits[i]=true;
break;
}
}
}
the iterative way of doing the same thing..
Long chains of else if statements should be replaced with switch statements.
Enums are the most expressive way to store such values as long as the efficiency is not a concern. Keep in mind that enum is a class, so creation of a new enum is associated with corresponding overhead.

Using enum as a parameter

So, I am trying to use an enumerated data type as parameter in the place of an object being passed in. I know that a simple switch statement would work but that doesn't really seem elegant to me. I have searched and found that enums can also have actions attached to them but I'm not so clear how to use it in this case or if it is even possible, or if i am just really tired. let me try to use code to explain what I'm asking.
First I have a class with certain fields of other objects that I am basically trying to use the enums to reference. In this case I have a method that acts on one of the fields of trees, because their are multiple trees the method needs to know which tree to act on.
public class bstContactManage()
{
// fields of other objects
BST searchTreeFirstName = new BST(new ComparatorObjOne);
BST searchTreeLastName = new BST(new ComparatorObjTwo);
// and so on and so forth
public boolean modify(Contact contactToFind, BST ToFindIn, String newContactInfo)
{
Contact contUpdate = new Contact(ContactToFind)//save for readdition to tree
contUpdate.update(newContactInfo);
toFindIn.remove(contactToFind);
if(toFindIn.add(contUpdate)) return true;
else return false;
}
}
what I'm wondering or more or less pondering is how to replace the BST parameter with a an enum
i know i could use a switch statement but that doesn't seem any more effective maybe more elegant than passing it an int value and letting it go wild!
so is there a way to get method to look something like
public boolean modify(Contact contactToFind, Enum BSTType, String newContactInfo)
{
Contact contUpdate = new Contact(ContactToFind)//save for readdition to tree
contUpdate.update(newContactInfo);
BSTType.remove(contactToFind);
if(BSTType.add(contUpdate)) return true;
else return false;
}
most of my question stems from the fact that an object such as
bstContactManage man = new bstContactManage()
will be instantiated in another class, and therefore it isn't safe or doesn't seem proper to me to do something like
man.modify(contactIn, man.searchTreeFirstName, "String");
update:
so for more clarification i have another method find which searches a given BST, and currently i am implementing it like this
public List<Contact> find(BinarySearchTree treeUsed, String findThis)
{
//create a new contact with all fields being the same, find is dependent and comparator on tree;
Contact tempContact = new Contact(findThis, findThis, findThis);
return treeUsed.getEntry(tempContact); // where getEntry returns a list of all matching contacts
}
I could do something like
public List<Contact> find(EnumField field, String findThis)
{
BST treeUsed;
switch(Field){
case FIRST:
treeUsed = this.searchTreeFirstName;
break;
cast LAST:
treeUsed = this.searchTreeLastName;
break;
Contact tempContact = new Contact(findThis, findThis, findThis);
return treeUsed.getEntry(tempContact); // where getEntry returns a list of all matching contacts
}
Enum could provide different implementation of its method. A good example would be Math operation:
enum Op {
PLUS {
int exec(int l, int r) { return l + r; }
},
MINUS {
int exec(int l, int r) { return l - r; }
};
abstract int exec(int l, int r);
}
Then I could do Op.PLUS.exec(5, 7) to perform 5 plus 7
See http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html for more detail on how to use enum.
In your case, I wouldn't use enum for something having loads of logic and state, but here is how you could use enum with methods having different implementations.
enum BSTType {
SearchTreeFirstName {
void someMethod(Contact c) {...}
},
SearchTreeLastName {
void someMethod(Contact c) {...}
};
abstract void somemethod(Contact c);
}
public boolean modify(Contact contactToFind, BSTType bstType, String newContactInfo) {
// ...
bstType.someMethod(contact);
// ...
}
By looking at the variable name and class name, I think what you actually meant is indexing Contact in a TreeSet either by first name or last name
enum IndexType implements Comparator<Contact> {
IndexByFirstName {
#Override
public int compare(Contact o1, Contact o2) {
return o1.firstName.compareTo(o2.firstName);
}
},
IndexByLastName {
#Override
public int compare(Contact o1, Contact o2) {
return o1.lastName.compareTo(o2.lastName);
}
};
}
TreeSet<Contact> contacts = new TreeSet<Contact>(IndexType.IndexByLastName);

Categories