This should be easily and quickly answerable. It is about throwing exceptions, and I have very little understanding of that topic (because I am a novice).
The code below represents of the most important methods from my simple 'maze game' program. In this method, I am (obviously) enumerating the possible user keyboard commands and giving the instructions for their execution by calling other sub-methods. Evidently, I want all keyboard inputs that aren't "help", "status" ... "down" to result in the error message at the bottom of the method.
I know that what I've got here is dumb and makes no sense, but that's because I literally have no idea what I'm doing when it comes to throwing exceptions, and I am too lazy to do any serious reading. So I would love if someone could just tell me how to write what I want to write here.
public static void performAction(String action) throws IllegalArgumentException {
if (action.equalsIgnoreCase("help")) {
printHelp(); }
else if (action.equalsIgnoreCase("status")) {
printStatus(); }
else if (action.equalsIgnoreCase("board")) {
printBoard(); }
else if (((action.charAt(0) == 'S') || (action.charAt(0) == 's')) && ((action.charAt(1) == 'a') || (action.charAt(1) == 'A')) && ((action.charAt(2) == 'v') || (action.charAt(2) == 'V')) &&
((action.charAt(3) == 'e') || (action.charAt(3) == 'E')) && (action.charAt(4) == ' ')) {
String [] parts = action.split(" ");
String saveCommand = parts[0];
String fileName = parts[1];
try { saveGame(fileName); }
catch(IOException e) {
System.err.printf("Error: Could not save the current game configuration to \'%s\'.", fileName);
return; } }
else if (action.equalsIgnoreCase("left")) {
int a = getCurrentXPosition();
int b = getCurrentYPosition();
moveTo((a - 1), b); }
else if (action.equalsIgnoreCase("right")) {
int a = getCurrentXPosition();
int b = getCurrentYPosition();
moveTo((a + 1), b); }
else if (action.equalsIgnoreCase("up")) {
int a = getCurrentXPosition();
int b = getCurrentYPosition();
moveTo(a, (b - 1)); }
else if (action.equalsIgnoreCase("down")) {
int a = getCurrentXPosition();
int b = getCurrentYPosition();
moveTo(a, (b + 1)); }
else {
try {}
catch (IllegalArgumentException e) {
System.err.printf("Error: Could not find command \'%s\'.\nTo find the list of valid commands, please type 'help'. \n", action); }
}
}
else {
System.err.printf("Error: Could not find command \'%s\'.\nTo find the list of valid commands, please type 'help'. \n", action);
throw IllegalArgumentException ;
}
This will log the message and then exit the method by throwing IllegalArgumentException exception
Related
Full Disclosure: This was an assignment, it has been marked already, but I want to understand why I'm getting this error.
I'm having some issues understanding why junit.framework.AssertionFailedError is being thrown. Normally when errors occur I could at least look at the stack trace and see what is happening. In this case, the output console shows this:
Testcase: testIsCorrectMCQ(mr_3.myTester): FAILED
null
junit.framework.AssertionFailedError
at mr_3.MyTester.testIsCorrectMCQ(Assign03Tester.java:207)
testIsCorrectMCQ(mr_3.MyTester): FAILED
In the test result tab in NetBeans, copying the stack trace gives me:
junit.framework.AssertionFailedError
at mr_3.myTester.testIsCorrectMCQ(myTester.java:207)
In the tester file, I have this:
#Test
public void testIsCorrectMCQ() {
System.out.println("isCorrect of MCQ");
MCQuestion instance = new MCQuestion(1,"Capital city of Canada is", 'A',
"Ottawa", "Vancouver", "New York", "Toronto");
assertFalse(instance.isCorrect("B"));
assertTrue(instance.isCorrect("A")); // line 207
}
My isCorrect method is this:
#Override
public boolean isCorrect(Object guess) {
if (guess == null)
return false;
if (guess instanceof String) {
String userGuess = (String)guess;
return (userGuess.charAt(0) == this.getAnswer());
}
if (guess instanceof Character) {
Character userGuess = (Character)guess;
return (userGuess == this.getAnswer());
}
else return false;
}
Any help in understanding what is happening is greatly appreciated.
Edit 1 : My MCQuestion source code
public class MCQuestion extends Question {
private char answer;
private String[] options;
public MCQuestion() {
super();
questionType = QuestionType.MULTIPLE_CHOICE;
}
public MCQuestion(int id, String text, char answer, String... options) {
super(id, text);
setOptions(options);
setAnswer(answer);
questionType = QuestionType.MULTIPLE_CHOICE;
}
public String[] getOptions() {
String[] getOptions = new String[this.options.length];
System.arraycopy(this.options, 0, getOptions, 0, this.options.length);
return getOptions;
}
public void setOptions(String... options) {
if (options.length > 0) {
this.options = new String[options.length];
for (int i = 0; i < options.length; i++) {
if (options[i].isEmpty())
throw new IllegalArgumentException("You have nothing in this option");
else
this.options[i] = options[i];
}
}
else throw new IllegalArgumentException("You have no options set");
}
public char getAnswer() {
return this.answer;
}
public void setAnswer(char ans) {
ans = Character.toLowerCase(ans);
int index = ans - 97;
if (Character.isLetter(ans) && index >= 0 && index < this.options.length)
this.answer = ans;
else throw new IllegalArgumentException(ans + " is not a valid answer option");
}
#Override
public boolean isCorrect(Object guess) {
if (guess == null)
return false;
if (guess instanceof String) {
String userGuess = (String)guess;
return (userGuess.charAt(0) == this.getAnswer());
}
if (guess instanceof Character) {
Character userGuess = (Character)guess;
return (userGuess == this.getAnswer());
}
else return false;
}
#Override
public String toString() {
String option = "";
if (this.options.length == 0)
option = "No options added, yet!";
else {
char index = 'a';
for (String e: options)
option += index + ") " + e + "\n";
}
return (super.toString() + "\n" + option);
}
}
You execute ans = Character.toLowerCase(ans); for whatever reason in your setAnswer() method before saving it in this.answer. This means that (userGuess.charAt(0) == this.getAnswer()) will return false when you provide the answer in upper case, but compare it with the stored lower case character.
Depending on if you want case insensitive answers or not, you should add or remove the Character.toLowerCase() call to your isCorrect() method as well.
So I'm pretty new to coding with Java (started yesterday). What I am trying to do is to make an Input of an Integer, if the int c it is higher than 1 or lower than 0 (if it is not 1 or 0), I want it to start again. If int c equals either 1 or 0, I want the alogrithm to continue. I tried to insert some kind of loops after if(c > 1 || c < 0) but it does not seem to work and only spams my console with the result. Is there any easy way to make the algorithm start over again? I'm already trying to fix this for more than 2 hours, but I'm just confusing me over and over again.
// more code up here but it is unimportant
int c = sc.nextInt();
if(c > 1 || c < 0) {
result = result + wrong;
System.out.println(result);
} else if (c == 1) {
result = result + notImplemented;
System.out.println(result);
} else if (c == 0) { //more code follows here but is unimportant
So you want to ask for input again, i assume.
A simple way could be:
int c = sc.nextInt();
while (c > 1 || c < 0) {
c = sc.nextInt();
}
//code continues
You can use while in this case and use break to exit:
while (scanner.hasNext()) {
int c = sc.nextInt();
if(c > 1 || c < 0) {
result = result + wrong;
System.out.println(result);
} else if (c == 1) {
result = result + notImplemented;
System.out.println(result);
break;
} else if (c == 0) {
...
break;
}
}
scanner.close();
You need to use a loop so you have
while(true){
int c = sc.nextInt();
if(c > 1 || c < 0) {
result = result + wrong;
System.out.println(result);
break;
} else if (c == 1) {
result = result + notImplemented;
System.out.println(result);
} else if (c == 0) { //more code follows here but is unimportant
...
}
Since you say you are new, I'll do a little explanation:
A While loop repeats what is in it's code block (i.e within the { }) for as long as a certain condition is true. In the case of my answer I did while(true) meaning it will keep repeating until something causes it to stop. In this case I used a break which forces the loop to end/stop.
Use hasNextInt() and a while loop to iterate over the data:
while (sc.hasNextInt()) {
int aInt = sc.nextInt();
//logic here
}
Documentation for hasNextInt() method:
https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#hasNextInt()
You can put your code in a function (which I hope is already the case) and then when you don't have the expected result and want to call it again, just do so by calling your function inside itself.
It's called recursion.
You can learn more here .
For example :
// more code up here but it is unimportant
public void myFunction(){
int c = sc.nextInt();
if(c > 1 || c < 0) {
result = result + wrong;
System.out.println(result);
} else if (c == 1) {
result = result + notImplemented;
System.out.println(result);
} else if (c == 0) { //more code follows here but is unimportant
}
//You want to call your function again
myFunction();
}
I am trying to write a basic program in Java that checks if an IP address is valid. I am trying to use no external classes other than the Scanner class and also no regular expressions.
My code, available at this gisttakes in 4 integers as input, one for each octet. I also have this codewhich is a little more readable than the first but is longer.
My question is, is there any other way to implement this idea in significantly fewer lines, and if so, how would I accomplish this?
While this code segment is a bit verbose, it is simple, self-descriptive, and has proven to be tight.
private static boolean isIPAddressValid(String ip) {
boolean result = true;
int i = 0;
int [] val = new int[4];
if ((ip == null) || (ip.trim().length() == 0))
{
//null ip address entered
result = false;
}
else
{
if (!(ip.contains(".")))
{
//no '.' found
result = false;
}
else
{
String [] parts = ip.split("\\.");
if (!(parts.length == 4))
{
//not 4 quadrants
result = false;
}
else
{
for (String s : parts) {
try {
val[i] = Integer.parseInt(s);
if ((val[i] < 0) || (val[i] > 255))
{
//this quadrant's value exceeds limits
result = false;
}
i++;
} catch (Exception e) {
//failed to parse quadrant to an integer");
result = false;
}
}
}
}
}
return result;
}
only some minor enhancements (i think your code looks very good - my opinio so far) it is clearly to read and all work blocks are properly to understand....
boolean isFailed = false;
if (first < 0 || first > 255) {
System.out.println("Octet 1 is invalid");
isFailed = true;
}
if (second < 0 || second > 255) {
System.out.println("Octet 2 is invalid");
isFailed = true;
}
if (third < 0 || third > 255) {
System.out.println("Octet 3 is invalid");
isFailed = true;
}
if (fourth < 0 || fourth > 255) {
System.out.println("Octet 4 is invalid");
isFailed = true;
}
if (!isFailed){
System.out.println("IP Address: " + first + "." + second + "." + third + "." + fourth);
}
so i simply invert the order of printing - that saves you only that big check before...
your approach was to can check each octet...
you can simply do this 4 times or write a method for it:
private static boolean check(int octet, int index){
if (0xFF & octet < 256) return true;
System.out.println("Octet "+index+" is invalid";
return false;
}
and use this method in your main method
if (check(first,0) && check (second, 2) && check (third, 3) && check(fourth, 4) ){
System.out.println("your ip is valid");
}
note - this only reveals the first invalid octet - if you want to check all you need another boolean
boolean result = check(first,0) &&
check (second, 2) &&
check (third, 3) &&
check(fourth, 4); //reveals all errors
a totally different approach would be to use http://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#getByName%28java.lang.String%29
try{
/*InetAdress adress =*/ InetAdress.
getByName(""+first+"."+second+"."+third+"."+forth)
System.out.println("your ip is valid");
}catch (UnknownHostException e){
//TODO represent that error message into a nice expression
System.out.println("your ip is invalid");
}
but this as well doesn't provide information about that octet which is invalid...
(by the way - what is wrong with your code? it's fine, really!)
I was just bored and wrote this regexp
public static boolean isValid(String ip) {
boolean isvalid;
isvalid = ip.matches(
"(([0-9]|[0-9]{0,2}|1[0-9]*{0,2}|2[0-5][0-5]|0{0,3}).){3}" +
"([0-9]|[0-9]{0,2}|1[0-9]*{0,2}|2[0-5][0-5]|0{0,3})"
);
return isvalid;
}
And it was tested on the following dataset:
String[] ips = {
"0.0.0.0",
"0.111.222.0",
"0.0.0.000",
"0.00.0.000",
"1.1.1.1",
"2.2.2.2",
"12.13.14.15",
"29.29.29.29",
"99.99.000.1",
"111.102.144.190",
"255.255.199.199",
"266.255.255.255", //inv
"255.265.255.255", //inv
"255.255.258.255", //inv
"255.255.255.259", //inv
"299.100.110.255" //inv
};
for (String s : ips) {
if (isValid(s) == false) {
System.err.println(s + " is invalid");
}
}
Okay, Now that I've updated my code it looks like this:
public static double getDouble (String userShape, String parameter) throws BadShapeData
{
String missingValue = parameter, value = "", shape = userShape;
String s2 = "Enter a value for " + missingValue;
value = JOptionPane.showInputDialog(s2);
if (null == value || value.length() == 0) {
throw new BadShapeData("Error, nothing was entered. Must be double.");
}
try {
return Double.parseDouble(value);
}
catch (NumberFormatException e) {
throw new BadShapeData("Error entering " + value + ". Must be double.");
}
}
And this is also in my code :
public static void main(String args[]) {
int choice;
do {
choice = menu();
if(choice != 0) {
System.out.println(makeShape(choice));
}
} while (choice != 0);
}
public static Shape3D makeShape(int choice) {
if(choice == 1)
return new Cone(getDouble("Cone", "Radius"), getDouble("Cone", "Height"));
else if(choice == 2)
return new Cylinder(getDouble("Cylinder", "Radius"), getDouble("Cylinder", "Height"));
else if(choice == 3)
return new Sphere(getDouble("Sphere", "Radius"));
else if(choice == 4)
return new Box(getDouble("Box", "Length"), getDouble("Box", "Width"), getDouble("Box", "Height"));
else if(choice == 5) return new Pyramid(getDouble("Pyramid", "Base"), getDouble("Pyramid", "Height"));
else return new Cube(getDouble("Cube", "Size"));
}
However now the error I'm getting says "Error: unreported exception BadShapeData; must be caught or declared to be thrown" and is being highlighted where I use the getDouble method
I would remove the return statement that is inside your finally, to outside. I'm not 100% on this, but I think it might be swallowing the exception.
And what value are you passing? notice that if you pass a float, an int, a long, etc. It will correctly parse as a double, because all those types are assignment-compatible with a double. If you want to see the exception being thrown, then pass a different type altogether, for example the string "xyz".
Be aware that a char is a number, so it's possible to assign it to a double variable. For example, this line will not result in a compilation or execution error; it's perfectly valid, albeit potentially confusing:
double c = 'x';
UPDATE:
Try changing your code like this:
try {
return Double.parseDouble(value);
} catch (NumberFormatException e) {
throw new BadShapeData(value);
}
Of course, you must add throws BadShapeData to the method declaration, like this:
public static double getDouble (String userShape, String parameter) throws BadShapeData
Also you must be aware that from this point onwards, all the parts in the code that call the getDouble() method will have to handle the exception - by catching it or letting it pass through. This is how Exceptions work in Java, as you should know by now.
Either place all calls to getDouble in a full or individual try/catch block(s):
public static void main(String args[]) {
int choice;
do {
choice = menu();
if(choice != 0) {
System.out.println(makeShape(choice));
}
} while (choice != 0);
}
public static Shape3D makeShape(int choice) {
try {
if(choice == 1)
return new Cone(getDouble("Cone", "Radius"), getDouble("Cone", "Height"));
else if(choice == 2)
return new Cylinder(getDouble("Cylinder", "Radius"), getDouble("Cylinder", "Height"));
else if(choice == 3)
return new Sphere(getDouble("Sphere", "Radius"));
else if(choice == 4)
return new Box(getDouble("Box", "Length"), getDouble("Box", "Width"), getDouble("Box", "Height"));
else if(choice == 5) return new Pyramid(getDouble("Pyramid", "Base"), getDouble("Pyramid", "Height"));
else return new Cube(getDouble("Cube", "Size"));
} catch (BadShapeData e) {
System.out.println(e.getMessage());
//do whatever with exception
}
}
OR have makeShape throw the exception then use a try/catch block in void main():
public static void main(String args[]) {
int choice;
do {
choice = menu();
if(choice != 0) {
try {
System.out.println(makeShape(choice));
} catch (BadShapeData e) {
System.out.println(e.getMessage());
//do whatever with exception
}
}
} while (choice != 0);
}
public static Shape3D makeShape(int choice) throws BadShapeData {
if(choice == 1)
return new Cone(getDouble("Cone", "Radius"), getDouble("Cone", "Height"));
else if(choice == 2)
return new Cylinder(getDouble("Cylinder", "Radius"), getDouble("Cylinder", "Height"));
else if(choice == 3)
return new Sphere(getDouble("Sphere", "Radius"));
else if(choice == 4)
return new Box(getDouble("Box", "Length"), getDouble("Box", "Width"), getDouble("Box", "Height"));
else if(choice == 5) return new Pyramid(getDouble("Pyramid", "Base"), getDouble("Pyramid", "Height"));
else return new Cube(getDouble("Cube", "Size"));
}
Which method you choose to implement depends on your needs. Go with first if void main need not know of the BadShapeData exception. Go with second if void main should know and do something about it.
Try this, then:
public static double getDouble (String userShape, String parameter) {
String prompt = "Enter a value for " + parameter;
String value = JOptionPane.showInputDialog(prompt);
if (null == value || value.length() == 0) {
throw new BadShapeData("Error, nothing was entered. Must be double.");
}
try {
return Double.parseDouble(value);
}
catch (NumberFormatException e) {
throw new BadShapeData("Error entering " + str + ". Must be double.");
}
}
public class BadShapeData extends RuntimeException {
public BadShapeData(String message) {
super(message);
}
}
The problem you have is that you hide the exception in finally block;
The finaly block is executed after you throw an exception. This mean it never go out as in finally you return
You should avoid to use return key word in finall block.
Remove return statement in finally block. You just swallow your exception. Instead of this put return outside finally.
Refer related question: Exception is swallowed by finally
UPDATE:
Catch your BadShapeData as it is a checked exception. Another way, which I prefer, to use RuntimeException as base class. It's more flexible, though less safe.
To explain what I'm doing, I'm basically taking a string of X's and O's as an input String, converting it to an array, so XXXOXOXOO as the input would be the same array. Then I'm checking each possible scenario where one could win, coordinate wise, and if it matches it through if statements it returns the number corresponding to who won.
But it's not quite working, haha. It seems to only output O as the winner, in clear cases where X should win.
Could anyone lend a hand? Much appreciated in advance, thanks.
import java.util.Scanner;
public class TicTacToe {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
System.out.println("Type in a board for analysis");
String b = keyboard.nextLine();
drawBoard(b);
int result = decide(b);
if (result == 1) {
System.out.println("Win for X");
}
else if (result == 0) {
System.out.println("Win for O");
}
else if (result == 3) {
System.out.println("Draw");
}
else {
System.out.println("Game Unfinished");
}
}
public static int decide(String scheme) {
int decision = 0;
String boardScheme[] = new String[9];
for (int i = 0; i < 9; i++) {
boardScheme[i] = scheme.substring(i,i+1);
}
if ((boardScheme[0] == boardScheme[1] && boardScheme[0] == boardScheme[2]) || (boardScheme[0] == boardScheme[3] && boardScheme[0] == boardScheme[6]) || (boardScheme[0] == boardScheme[4] && boardScheme[0] == boardScheme[8])) {
if (boardScheme[0] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
else if (boardScheme[3] == boardScheme[4] && boardScheme[3] == boardScheme[5]) {
if (boardScheme[3] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
else if (boardScheme[6] == boardScheme[7] && boardScheme[6] == boardScheme[8]) {
if (boardScheme[6] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
else if (boardScheme[1] == boardScheme[4] && boardScheme[1] == boardScheme[7]) {
if (boardScheme[1] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
else if ((boardScheme[2] == boardScheme[5] && boardScheme[2] == boardScheme[8]) || (boardScheme[2] == boardScheme[4] && boardScheme[2] == boardScheme[6])) {
if (boardScheme[2] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
return decision;
}
public static void drawBoard(String scheme) {
if (scheme.length() == 9) {
String board[] = new String[9];
for (int i = 0; i < 9; i++) {
board[i] = scheme.substring(i,i+1);
}
System.out.println(board[0] + " | " + board[1] + " | " + board[2]);
System.out.println(board[3] + " | " + board[4] + " | " + board[5]);
System.out.println(board[6] + " | " + board[7] + " | " + board[8]);
}
else {
System.out.println("Please input 9 characters, no more, no less.");
}
}
}
You are not covering all the possible cases. What would happen if you had missed a case? sorry, I went through them and indeed you do cover each case correctly. However, as noted by Hovercraft Full Of Eels in the comment to the question, you are comparing strings incorrectly. Still I would suggest the below.
You are setting decision = 0, so whenever a case occur which you are not covering, then you will end up returning 0. Which will output 'O' wins.
So, what you need to do is to figure out each possible case that can happen and then check for it. I would also suggest that you use codereview.stackexchange.com and ask for advice on how to restructure your code a bit, it will make it easier for you in the end.
For example what if you had a function horizontalWin(int column) and verticalWin(int row) and diagonalWin().
Good luck!