I'm trying to implement this automaton example : http://www.javacodegeeks.com/2012/03/automaton-implementation-in-java.html.
However, an error keeps on being displayed while running the program :
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 3
at java.lang.String.charAt(String.java:686)
at mealy.Input.read(Input.java:7)
at mealy.States$4.next(Input.java:46)
at mealy.Test.main(Test.java:9)
I tried modifying the lines responsible for the error but nothing changed. Could someone please take a look at this program and help me find a solution?
I have the following .java :
State.java :
interface State {
public State next(Input in);
}
NB : I had to change the original "public Stat next()" into "public State next(Input in);"
Input.java :
class Input {
private String input;
private int current;
public Input(String input) {this.input = input;}
char read() { return input.charAt(current++); }
}
enum States implements State {
Init {
#Override
public State next(Input word) {
switch(word.read()) {
case 'a': return A;
default: return Fail;
}
}
},
A {
#Override
public State next(Input word) {
switch(word.read()) {
case 'a': return A;
case 'b': return B;
case 'c': return C;
case 'd': return null;
default: return Fail;
}
}
},
B {
#Override
public State next(Input word) {
switch(word.read()) {
case 'b': return B;
case 'c': return C;
case 'd': return null;
default: return Fail;
}
}
},
C {
#Override
public State next(Input word) {
switch(word.read()) {
case 'c': return C;
case 'd': return null;
default: return Fail;
}
}
},
Fail {
#Override
public State next(Input word) {
return Fail;
}
};
public abstract State next(Input word);
}
Test.java :
public class Test {
public static void main(String args[]){
State s;
Input in = new Input("abc");
for(s = States.Init; s != null || s != States.Fail; s = s.next(in)) {}
if(s == States.Init) {System.out.println("Valid!");}
else {System.out.println("Failed");}
}
}
There appears to be a bug in the Input class. When you attempt to read the character after the last one, it throws an exception you are not handling in main. I would change Input so that it return a token you can handle in your state machine.
BTW I suggest you have a look at this for context. http://vanillajava.blogspot.co.uk/2011/06/java-secret-using-enum-as-state-machine.html
I assume Attila was looking to provide a simple, working example. I will see if he can fix his code.
you need to change read() method like below
char read() {
if(current>=input.length()) // this if condition should be checked
return 'z'; // you need to change your character according to your need
return input.charAt(current++);
}
the error is in this line
char read() { return input.charAt(current++); }
You don't check the length of the String input (which i consider a bad name inside a class Input) and after calling read() three times you try to access the 4th letter of a 3 letter String, which then throws the exception you see.
Update:
Addressing your comment I'd suggest changing the return value of read() to a new interface ReadResult:
public interface ReadResult {
boolean isOkay();
char getReadCharacter();
}
with two implementations. one for positive results...
public class ReadOkay implements ReadResult{
private char readCharacter;
public ReadOkay(char readCharacter) {
this.readCharacter = readCharacter;
}
#Override
public boolean isOkay() {
return true;
}
#Override
public char getReadCharacter() {
return readCharacter;
}
}
and one for negative results
public class ReadFailed implements ReadResult {
#Override
public boolean isOkay() {
return false;
}
#Override
public char getReadCharacter() {
throw new IllegalStateException("Read failed! no character data there to return!");
}
}
Having this you can change read() to let it return then new interface
public ReadResult read() {
if (input != null && current >= 0 && current < input.length()) {
return new ReadOkay(input.charAt(current++));
} else {
return new ReadFailed();
}
}
and update your States accordingly.
replace:
switch(word.read()) {
with:
ReadResult result = word.read();
if (!result.isOkay()) {
return Fail;
}
switch (result.getReadCharacter()) {
Related
I am trying to take a 3 class program and pass a boolean for reserving a room. I have driver program, building, room programs. I set the reserve to false and I can't figure out how to print out a text statement when it's already set to true. I think I am either doing the passing of the boolean through the classes from the driver wrong or missing something. I have played with reserveRoom in building class with an if statement to see if it's already true to print a statement and no matter which way I go it doesn't work.
Any help would be appreciated.
Thank you.
From my driver program that sends the boolean to the building program
System.out.print ("Which room would you like to reserve?");
System.out.print (building);
System.out.print ("reserve: ");
reservNum = input.nextInt();
building.reserveRoom(reserve, reservNum);
From my building class.
public void reserveRoom (boolean reserve, int count)
{
//class constant
//class variables
/*****************************************************/
room [count].updateReserve(reserve);
} // end
From the room class.
public void updateReserve(boolean newReserve)
{
//class constant
//class variables
/*****************************************************/
if (newReserve == false)
{
roomAvail = true;
}
else
{
roomAvail = false;
}
} // END
Well, there is some information missing in your question, however it think you are looking for:
public void updateReserve(boolean newReserve) {
if(newReserve && !roomAvail) {
System.out.println("Sorry this room is taken")
} else {
roomAvail = !newReserve;
}
}
With whatever i could understand about your question this is what i came up with -
public class Reservation {
public static void main(String args[]) {
Building building = new Building(20);
boolean reserve= false;
System.out.println("Which room would you like to reserve?");
System.out.println(building);
System.out.println("reserve: ");
int reservNum = 2;
building.reserveRoom(reserve, reservNum);
System.out.println("Is Reserved?:"+building.getRoom(reservNum).getRoomAvail());
}
}
class Building {
Room room[];
public Building(int numOfRooms) {
room = new Room[numOfRooms];
for(int i=0; i<numOfRooms; i++) {
room[i] = new Room();
}
}
public String toString() {
return "This Building has "+room.length+"rooms";
}
public Room getRoom(int roomNum){
return room[roomNum];
}
public void reserveRoom (boolean reserve, int count)
{
//class constant
//class variables
/*****************************************************/
room [count].updateReserve(reserve);
} // end
}
class Room {
boolean roomAvail;
public boolean getRoomAvail() {
return roomAvail;
}
public void updateReserve(boolean newReserve)
{
//class constant
//class variables
/*****************************************************/
if (newReserve == false)
{
roomAvail = true;
}
else
{
roomAvail = false;
}
} // END
}
I've created this method and I'm unsure why it says there's a missing return statement. do I need to change the print to a return? (it's the method at the very bottom) I'm a bit of a Java beginner so any help will be appreciated!
public class Book {
private String title;
private String author;
private int copies;
private boolean borrowed;
public Book( String inAuthor, String inTitle, int inNumberOfCopies ) {
this.author = inAuthor;
this.title = inAuthor;
this.copies = inNumberOfCopies;
}
public void borrowed() {
borrowed = true;
}
public void rented() {
borrowed = true;
}
public void returned() {
borrowed = false;
}
public boolean isBorrowed() {
return borrowed;
}
public String getAuthor() {
return this.author;
}
public static String getTitle() {
return getTitle();
}
public int getTotalCopies() {
return this.copies;
}
public int getAvailableCopies() {
}
public void withdrawCopy() {
int found = 0;
for (Book b : Library.getListOfBooks()) {
if (b.getTitle().equals(title)) {
if (found == 0) {
found = 1;
}
if (!b.isBorrowed()) {
b.borrowed=true;
found = 2;
break;
}
if (found == 0) {
System.out.println("Sorry, this book is not in our catalog.");
} else if (found == 1) {
System.out.println("Sorry, this book is already borrowed.");
} else if (found == 2) {
System.out.println("You successfully borrowed " + title);
}
}
}
}
public String returnCopy() {
boolean found = false;
for (Book book : Library.getListOfBooks()) {
if (getTitle().equals(title) && book.isBorrowed()) {
book.returned();
found = true;
}
if (found) {
System.out.println("you successfully returned " + title);
}
}
}
}
public String returnCopy()
String after public means that this method will return a String.
Your public String returnCopy() is currently not returning anything.
If you don't want to return anything, you can use void like this:
public void returnCopy(){
// code
}
Same issue with public int getAvailableCopies(), this is supposed to return an int but you are not returning anything.
Be careful:
this method:
public static String getTitle() {
return getTitle();
}
is a recursive method without a base condition. This will cause an error and force your application to crash.
You've defined the method as returning a String but you don't return a value anywhere in the method body. Simplest fix is probably to change the return type to void...
public void returnCopy() {...
}
All the above answer are pointing to the same issue, you have defined methods that are breaking the contract about what they return..
In you code you have as well something like this:
public int getAvailableCopies() {
}
so you are telling the compiler, you have a method with the name getAvailableCopies, it takes no params and return an integer.
BUT if you don't return anything, then you are contradicting your own method, your own contract, this is an enough reason for a compiler to complain...
Conclusion:
keep in mind the information that defines the method.
I am using enumeration with switch case but I am getting the following error:
NEWS FEED is not a constant in FragmentName
This is my enum string constant,
public enum FragmentName{
FRAGMENT_NEWSFEED("NEWS FEED"),
FRAGMENT_MESSAGES("MESSAGES"),
FRAGMENT_EVENTS("EVENTS"),
FRAGMENT_WHOISAROUDNME("WHOS AROUND");
private final String text;
private FragmentName(final String text) {
this.text = text;
}
#Override
public String toString() {
return text;
}
}
//This is my function from where i check for corresponding enum constant
public void changeTitle(String title) {
switch (Enums_String.FragmentName.valueOf(title)) {
case FRAGMENT_NEWSFEED:
System.out.println("1");
break;
case FRAGMENT_EVENTS:
System.out.println("2");
break;
case FRAGMENT_MESSAGES:
System.out.println("3");
break;
case FRAGMENT_WHOISAROUDNME:
System.out.println("4");
break;
}
}
When I call
changeTitle("NEWS FEED");
it creates an exception in the changeTitle function even the value passed is same, so any help would be appreciated as I have tried my every effort to solve this.
Add this code to your enum
private static final Map<String, FragmentName> map = new HashMap<>();
static {
for (FragmentName en : values()) {
map.put(en.text, en);
}
}
public static FragmentName valueFor(String name) {
return map.get(name);
}
Now instead of valueOf use valueFor
switch (Enums_String.FragmentName.valueFor(title))
// ^^^^^^^^
The valueOf
Returns the enum constant of the specified enum type with the
specified name. The name must match exactly an identifier used to
declare an enum constant in this type. (Extraneous whitespace
characters are not permitted.
What you want do id get the enum by a member value for that you have write a function to do so like fromString below
public enum FragmentName {
FRAGMENT_NEWSFEED("NEWS FEED"),
FRAGMENT_MESSAGES("MESSAGES"),
FRAGMENT_EVENTS("EVENTS"),
FRAGMENT_WHOISAROUDNME("WHOS AROUND");
private final String text;
private FragmentName(final String text) {
this.text = text;
}
#Override
public String toString() {
return text;
}
public static FragmentName fromString(String value) {
for (FragmentName fname : values()) {
if (fname.text.equals(value)) {
return fname;
}
}
return null;
}
}
and replace your switch case like
switch (FragmentName.fromString(title)) {
Create a method like this :
public static FragmentName getFragmentNameByText(String text) {
for (FragmentName fragment : values()) {
if (fragment.text.equals(text)) {
return fragment;
}
}
return null;
}
and call this instead of valueOf().
You can change your function to compare the string values passed in:
public void changeTitle(String title) {
if(title.equals(FRAGMENT_NEWSFEED.toString())) {
System.out.println("1");
} else if(title.equals(FRAGMENT_MESSAGES.toString())) {
System.out.println("2");
} else if(title.equals(FRAGMENT_EVENTS.toString())) {
System.out.println("3");
} else if(title.equals(FRAGMENT_WHOISAROUDNME.toString())) {
System.out.println("4");
} else {
// throw an error
}
}
You can't operate an switch off of a function call, so you have to use an if-else block.
in this homework i have to do a predicate method that prints a question and then waits for a question. if the user enters no, the method should return false, if the user enters yes the method should return true. I have done that ! but in this part i have problems: if the user enters another thing the program must say something like "wrong answer" and repeat the question. I can't return a string because is a boolean method and i dont know how to resolve this.
Thank you!!
import acm.program.ConsoleProgram;
public class YesNo extends ConsoleProgram{
public void run () {
String answer = readLine ("would you like instructions? ");
println (StrBoo (answer));
}
private boolean StrBoo(String answer){
if (answer.equals("yes")) {
return true;
} else if (answer.equals("no")) {
return false;
} else {
return false;
}
}
}
First StrBoo is a poor method name. I would call it getAnswer(), and use something like,
private static boolean getAnswer() {
while (true) {
String answerStr = readLine ("would you like instructions? ");
answerStr = (answerStr != null) ? answerStr.trim() : "";
if ("yes".equalsIgnoreCase(answerStr)) {
return true;
} else if ("no".equalsIgnorecase(answerStr)) {
return false;
} else {
System.out.println("Wrong answer");
}
}
return false;
}
The correct design for such kind of program is to throw an exception. Here is an example:
import acm.program.ConsoleProgram;
public class YesNo extends ConsoleProgram
{
class WrongAnswerException extends Exception
{
}
public void run ()
{
try
{
String answer = readLine("would you like instructions? ");
println(StrBoo(answer));
}
catch(WrongAnswerException e)
{
println("You have to write yes or no!")
}
}
private boolean StrBoo(String answer) throws WrongAnswerException
{
if ("yes".equals(answer))
{
return true;
}
else if ("no".equals(answer))
{
return false;
}
else
{
throw new WrongAnswerException()
}
}
}
I want to have something like this below (example how I would do this in C#), to get typed value from SQLiteDB:
private T GetValueFromDB<T>(String colName) {
object returnValue = null;
switch (typeof(T)) {
case Boolean:
returnValue = dbData.getInt(colName) == 1;
break;
case Int32:
returnValue = dbData.getInt(colName);
break;
case Int64:
returnValue = dbData.getLong(colName);
break;
case String:
returnValue = dbData.getString(colName);
break;
}
return (T)returnValue;
}
Is there a possibility (with switch case or if else) to implement it in Java?
If you already know the type when calling the method, you could do something like this:
private T GetValueFromDB<T>(String colName, Class<T> returnType) {
if(returnType.equals(Boolean.class)) {
return (T)(dbData.getInt(colName) == 1);
} else if(returnType.equals(Int32.class)) {
// and so on
}
}
Java uses type erasure so it is impossible to determine type of T at runtime.
I have made inteface switch, maybe it can be useful for someone :
new ISwitch(pagerCtrl.getPager().getFragmentByID(fragment_id))
.addCase(new ISwitch.CaseListener<Type1>() {
#Override
public void Case(Type1 instance) {
}
}).addCase(new ISwitch.CaseListener<Type2>() {
#Override
public void Case(Type2 instance) {
}
}).addDefault(new ISwitch.DefaultListener() {
#Override
public void Default() {
}
}).build();
public class ISwitch {
public interface CaseListener<T> {
void Case(T instance);
}
public interface DefaultListener {
void Default();
}
Object value;
LinkedList<CaseListener<?>> col = new LinkedList<>();
DefaultListener defaultListener;
public ISwitch(Object value) {
this.value = value;
}
public void build() {
boolean wasNotifiedMinimumOnce = false;
for (CaseListener<?> c : col) {
try {
CaseListener<Object> l = (CaseListener<Object>) c;
l.Case(value);
wasNotifiedMinimumOnce = true;
break;
} catch (ClassCastException e) {
}
}
if ( !wasNotifiedMinimumOnce ) {
if ( defaultListener != null ) {
defaultListener.Default();
}
}
}
public ISwitch addCase(CaseListener<?> caseListener) {
col.add(caseListener);
return this;
}
public ISwitch addDefault(DefaultListener defaultListener) {
this.defaultListener = defaultListener;
return this;
}
}
The small drawback of implementation is that we cant make check instanceof, that why i catch it on cast. For me its not big deal, but it can be performance issue on java server code executed XXXXXX times each seconds.