I want to restrict my function divide to always be called from a try block. But when the function is called from main, without using try block, it does not show "Unhandled Exception" error?
class Main {
public static void main(String[] args) {
System.out.println(Main.divide(5.0f, 2.0f));
System.out.println(divide(5.0f, 2.0f));
}
static float divide(float x, float y) throws ArithmeticException {
if (y == 0)
throw new ArithmeticException("Cannot divide by 0!");
else
return x/y;
}
}
Output:
2.5
2.5
To make use of "throws" keyword to throw the checked exception, you can force the calling method to handle the exception.
Make this change:
From:
static float divide(float x, float y) throws ArithmeticException {
To:
// Custom checked exception
static class UserDefinedException extends Exception {
public UserDefinedException(String str) {
super(str);
}
}
// Good approach
static float divide(float x, float y) throws UserDefinedException {
if (y == 0)
throw new UserDefinedException("Cannot divide by 0!");
else
return x/y;
}
// Bad approach
//static float divide(float x, float y) throws Exception { ... }
Related
I have a class called Ship which should take the physical dimensions weight, height, and name to its constructor. I got a customized Exception too that should be thrown when a user tries to instantiate a Ship object with illegal parameters...
The user cant enter 0 for weight and height and won't also try to enter an empty name for the name of the ship
class Ship {
private double weight;
private int height;
private String name;
public Ship(int w, int h, String name) {
// I am not sure if object instance check logic should go here
// but it should throw this custom exception class defined
}
}
class CustomIllegalArgumentException extends Exception {
public CustomIllegalArgumentException(String r) {
super(r);
}
}
If your constructor doesn't like the parameters it gets, it can throw the said exception.
public Ship(int w, int h, String name) throws CustomIllegalArgumentException{
if (w <= 0 || h <= 0) {
throw new CustomIllegalArgumentException("Invalid ship size!");
}
if (name == null || name.length() == 0) {
throw new CustomIllegalArgumentException("Give your ship a name!");
}
// rest of your logic.
}
as a homework assigment, I am asked to build some sort of calculator with java.
In order to make it easier to create expressions, I wanna add constructors that provide "shortcuts" for creating the Num and Var classes. For example, instead of writing new Plus(new Var("x"), new Num(5)) I would like to be able to write new Plus("x", 5) and get the same resulting expression.
in order to not repeat code lines I've created an abstract class called BinaryExpression, inside it are all the possible combination I need for my constructors.
I'm trying to figure out an elegant way to construct a plus class without the need to re-write the same code again.
public abstract class BinaryExpression implements Expression {
protected Expression x;
protected Expression y;
public BinaryExpression(Expression x, Expression y) {
this.x = x;
this.y = y;
}
public BinaryExpression(String x, Expression y) {
this(new Var(x),y);
}
public BinaryExpression(Double x, Expression y) {
this(new Num(x), y);
}
public BinaryExpression(Expression x, String y) {
this(x ,new Var(y));
}
public BinaryExpression(Expression x, Double y) {
this(x ,new Num(y));
}
public BinaryExpression(String x, String y) {
this(new Var(x) ,new Var(y));
}
public BinaryExpression(Double x, Double y) {
this(new Num(x) ,new Num(y));
}
public BinaryExpression(Double x ,String y){
this(new Num(x) ,new Var(y));
}
public BinaryExpression(String x ,Double y){
this(new String(x) ,new Num(y));
}
I searching for a solution like this:
public class Plus extends BinaryExpression {
public Plus(<String,Double, Expression> x, <String,Double, Expression> y) {
super(x, y);
}
so I only accept this class types that way they will fit themselves to their designated constructor inside BinaryExpression class.
thanks :)
The problem is that you need some general container for objects which can be treated as if they were instances of Expression without them actually being instances of Expression. (example: String, Double)
This answer assumes the following:
class Num implements Expression
class Var implements Expression
and that the following constructor exists, or that no constructor is defined for the class Expression
public Expression() {}
I think a good solution would be as #markspace suggested. You can make sure it compiles by using instanceof to determine what to cast the arguments to.
public Plus(Object a, Object b) {
Expression exprA = convertToExpression(a);
Expression exprB = convertToExpression(b);
if(exprA == null || exprB == null) {
// could error handle here or in the place below
}
// do initialization here
}
//
public Expression convertToExpression(Object obj) {
Expression exprObj = null;
if(obj instanceof String) {
exprObj = new Var(obj);
} else if(obj instanceof Double) {
exprObj = new Num(obj);
} else {
// error handle here or in the place above
}
return exprObj;
}
Also, is the last constructor incorrect in your code above?
It seems like it should read like this:
public BinaryExpression(String x, Double y) {
this(new Var(x), new Num(y));
}
I am building an Interactive-Fiction-Game in Java, but am having a trouble using a second class to be used in the main class. I am using Eclipse.
Here is my main Class:
import java.util.Scanner;
import static java.lang.System.out;
public class mainClass {
public static void main(String[] args) {
String cmdIF;
Scanner input = new Scanner(System.in);
int x = 0;
int y = 0;
out.print("Welcome to the world! Which way do you want to go?");
String northD = "You walk into a forest.";
if(x=1) {
out.print(northD);
}
cmdIF = input.nextLine();
choosePath();
}
public void choosePath(actionClass cmdCenter) {
actionClass.cmdCenter();
}
}
And the class that contains the method:
public class actionClass {
public void cmdCenter() {
if(cmdIF.equalsIgnoreCase("NORTH") || cmdIF.equalsIgnoreCase("GO NORTH")) { out.println(northD); x++; }
else if(cmdIF.equalsIgnoreCase("EAST") || cmdIF.equalsIgnoreCase("GO EAST")) { out.println(eastD); y++; }
else if(cmdIF.equalsIgnoreCase("SOUTH") || cmdIF.equalsIgnoreCase("GO SOUTH")) { out.println(southD); x--; }
else if(cmdIF.equalsIgnoreCase("WEST") || cmdIF.equalsIgnoreCase("GO WEST")) { out.println(westD); y--; }
else { out.println("You can't do that."); }
}
}
Whenever I execute the code I get this error:
Exception in thread "main" java.lang.Error: Unresolved compilation
problem: The method choosePath(actionClass) in the type mainClass is
not applicable for the arguments ()
at mainClass.main(mainClass.java:14)
How can I make these methods work together?
in first step you access the method like this
actionClass.cmdCenter();
is not static so just make cmdCenter static like this
public static void cmdCenter
and choosePath() have parameter so you have to use it like this choosePath(actionClass) and since you use it in static method you have to create instance or make choosePath static
public static void choosePath(actionClass)
but you don't have to just remove paramater from choosePath
//public void choosePath(actionClass cmdCenter) {
public static void choosePath()
and seems you have to pass x and y variable to cmdCenter too so its become like this
public static void cmdCenter(String cmdIF, int x, int y)
and rest the code its fine
fixed version of your code :
public class Main {
static String cmdIF;
static int x = 0;
static int y = 0;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Welcome to the world! Which way do you want to go?");
String northD = "You walk into a forest.";
if(x ==1) {
System.out.print(northD);
}
cmdIF = input.nextLine();
choosePath();
}
public static void choosePath() {
actionClass.cmdCenter(cmdIF, x, y);
}
}
and
public class actionClass {
public static void cmdCenter(String cmdIF, int x, int y) {
if(cmdIF.equalsIgnoreCase("NORTH") || cmdIF.equalsIgnoreCase("GO NORTH")) { out.println("GO NORTH"); x++; }
else if(cmdIF.equalsIgnoreCase("EAST") || cmdIF.equalsIgnoreCase("GO EAST")) { out.println("GO EAST"); y++; }
else if(cmdIF.equalsIgnoreCase("SOUTH") || cmdIF.equalsIgnoreCase("GO SOUTH")) { out.println("GO SOUTH"); x--; }
else if(cmdIF.equalsIgnoreCase("WEST") || cmdIF.equalsIgnoreCase("GO WEST")) { out.println("GO WEST"); y--; }
else { System.out.println("You can't do that."); }
}
}
Change the cmdCenter() method in actionClass to be declared as:
public void cmdCenter(String cmdIF)
Then change choosePath() to be
public void choosePath(actionClass action, String cmdIf) {
action.cmdCenter(cmdIf);
}
and obviously change your main() method's call to choosePath() appropriately. And you'll need to new up an instance of actionClass to pass into choosePath().
I have to change my code to solution from using reflection to generation random parameters.
I couldn't figure out how to made this implementation...
Here is class generator:
public class SweetsGenerator implements Generator<Sweets>, Iterable<Sweets> {
private static final Logger LOG = Logger.getLogger(SweetsGenerator.class);
#SuppressWarnings("rawtypes")
private Class[] types = {
WhiteChocolate.class, MilkChokolate.class, DarkChocolate.class,
DesertChocolate.class, PorousChocolate.class,
};
private static Random rand = new Random();
public SweetsGenerator() {
}
private int size = 0;
public SweetsGenerator(int sz) {
size = sz;
}
public Sweets next() {
try {
return (Sweets) types[rand.nextInt(types.length)].newInstance();
} catch (Exception e) {
LOG.error("RuntimeException", e);
throw new RuntimeException(e);
}
}
class SweetsIterator implements Iterator<Sweets> {
int count = size;
public boolean hasNext() {
return count > 0;
}
public Sweets next() {
count--;
return SweetsGenerator.this.next();
}
public void remove() { // Not implemented
LOG.error("UnsupportedOperationException");
throw new UnsupportedOperationException();
}
};
public Iterator<Sweets> iterator() {
return new SweetsIterator();
}
}
How to circumvent this approach and create new class element, for example as:
new WhiteChocolate((rand.nextDouble() * 100) + 1, (rand.nextDouble() * 200) + 1);
I can't it combine with randomise generation class witch element we can create.
Here is content of Sweets abstract class and one of it implementation:
public abstract class Sweets {
private double sugarLevel;
private double weight;
public double getSugarLevel() {
return sugarLevel;
}
public double getWeight() {
return weight;
}
public void setSugarLevel(double sugarLevel) {
this.sugarLevel = sugarLevel;
}
public void setWeight(double weight) {
this.weight = weight;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName() + " " + sugarLevel + " " + weight);
return sb.toString();
}
}
public class Chocolate extends Sweets {
public Chocolate() {
}
public Chocolate(double aSugarLevel, double aWeight) {
setSugarLevel(aSugarLevel);
setWeight(aWeight);
}
}
UPDATE:
I tried to modify next() by skiwi suggestion.
Changed version is next:
public Sweets next() {
Sweets current = instances[rand.nextInt(instances.length)];
Double param1 = (rand.nextDouble() * 100) + 1;
Double param2 = (rand.nextDouble() * 200) + 1;
System.out.println("parameters: " + Math.round(param1) + " " + Math.round(param2));
try {
return (Sweets) current.getClass()
.getConstructor(Double.class, Double.class)
.newInstance(Math.round(param1), Math.round(param2));
// Report programmer errors at run time:
} catch (Exception e) {
LOG.error("RuntimeException", e);
throw new RuntimeException(e);
}
}
But it throws next bunch of exceptions:
23:25:51,337 ERROR main SweetsGenerator:next:52 - RuntimeException
java.lang.NoSuchMethodException: com.epam.lab.chocolate.DarkChocolate.<init>(java.lang.Double, java.lang.Double)
at java.lang.Class.getConstructor0(Class.java:2800)
at java.lang.Class.getConstructor(Class.java:1708)
at com.epam.lab.SweetsGenerator.next(SweetsGenerator.java:48)
at com.epam.lab.NewYearGift.generate(NewYearGift.java:37)
at com.epam.lab.GiftList.generateGift(GiftList.java:47)
at com.epam.lab.GiftList.main(GiftList.java:59)
Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodException: com.epam.lab.chocolate.DarkChocolate.<init>(java.lang.Double, java.lang.Double)
at com.epam.lab.SweetsGenerator.next(SweetsGenerator.java:53)
at com.epam.lab.NewYearGift.generate(NewYearGift.java:37)
at com.epam.lab.GiftList.generateGift(GiftList.java:47)
at com.epam.lab.GiftList.main(GiftList.java:59)
Caused by: java.lang.NoSuchMethodException: com.epam.lab.chocolate.DarkChocolate.<init>(java.lang.Double, java.lang.Double)
at java.lang.Class.getConstructor0(Class.java:2800)
at java.lang.Class.getConstructor(Class.java:1708)
at com.epam.lab.SweetsGenerator.next(SweetsGenerator.java:48)
... 3 more
Solution for this problem was to change one line:
return (Sweets) current.getClass().getConstructor(double.class, double.class)
.newInstance(Math.round(param1), Math.round(param2));
How to safe this logic of generator and create randomly elements with parameters?
Any suggestions?
If you have a constructor contract like public WhiteChololate(Double a, Double b), you can call the following to create a new instance:
Double a = 1d;
Double b = 2d;
WhiteChocolate.class.getConstructor(Double.class, Double.class).newInstance(a, b);
This will construct the required instance, not ethat I am using this syntax over Class<?>.newInstance(), since as described here:
Note that this method propagates any exception thrown by the nullary constructor, including a checked exception. Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler. The Constructor.newInstance method avoids this problem by wrapping any exception thrown by the constructor in a (checked) InvocationTargetException.
So using Constructor.newInstance(...) is both more safe and is the only one that will satisfy your needs.
Note that you need to specify the parameters type in the .getConstructor() call and not the value yet.
This question already has answers here:
"Main method not found" error when starting program? [duplicate]
(7 answers)
Closed 5 years ago.
I need help with the main method, I'm getting this error:
Error: Main method not found in class Calculate, please define the main method as:
public static void main(String[] args)
Here's the code:
class Calculate {
private double fn;
private double sn;
private char op;
public void setNumber(double fnum, double snum){
this.fn = fnum;
this.sn = snum;
}
public double getNumber1(){
return fn;
}
public double getNumber2(){
return sn;
}
public void setOper(char oper){
this.op = oper;
}
public char getOper(){
return op;
}
public void getAnswer(){
double ans;
switch (getOper()){
case 'a': {
ans = add(getNumber1(), getNumber2());
ansOutput(ans);
break;
}case 'b': {
ans = sub (getNumber1(), getNumber2());
ansOutput(ans);
break;
}case 'c': {
ans = mul (getNumber1(), getNumber2());
ansOutput(ans);
break;
}case 'd': {
ans = div (getNumber1(), getNumber2());
ansOutput(ans);
break;
}default:
System.out.println("--------------------------");
System.out.println("Invalid choice of operator");
System.out.println("--------------------------");
}
}
public static double add(double x,double y){
return x + y;
}
public static double sub(double x, double y){
return x - y;
}
public static double mul(double x, double y){
return x * y;
}
public static double div(double x, double y){
return x / y;
}
public static void ansOutput(double x){
System.out.println("----------- -------");
System.out.printf("the answer is %.2f\n", x);
System.out.println("-------------------");
}
}
Restart your IDE and everything will be fine
From the docs
In the Java programming language, every application must contain a main method whose signature is:
public static void main(String[] args)
The modifiers public and static can be written in either order (public static or static public), but the convention is to use public static as shown above. You can name the argument anything you want, but most programmers choose "args" or "argv".
As you say:
error: missing method body, or declare abstract public static void main(String[] args); ^ this is what i got after i added it after the class name
You probably haven't declared main with a body (as ';" would suggest in your error).
You need to have main method with a body, which means you need to add { and }:
public static void main(String[] args) {
}
Add it inside your class definition.
Although sometimes error messages are not very clear, most of the time they contain enough information to point to the issue. Worst case, you can search internet for the error message. Also, documentation can be really helpful.
My suggestions :
Keep the program modular. Keep the Calculate class in a separate Calculate.java file and create a new class that calls the main method. This would make the code readable.
For setting the values in the number, use constructors. Do not use like the methods you have used above like :
public void setNumber(double fnum, double snum){
this.fn = fnum;
this.sn = snum;
}
Constructors exists to initialize the objects.This is their job and they are pretty good at it.
Getters for members of Calculate class seem in place. But setters are not. Getters and setters serves as one important block in the bridge of efficient programming with java. Put setters for fnum and snum as well
In the main class, create a Calculate object using the new operator and the constructor in place.
Call the getAnswer() method with the created Calculate object.
Rest of the code looks fine to me.
Be modular. You could read your program in a much better way.
Here is my modular piece of code.
Two files : Main.java & Calculate.java
Calculate.java
public class Calculate {
private double fn;
private double sn;
private char op;
public double getFn() {
return fn;
}
public void setFn(double fn) {
this.fn = fn;
}
public double getSn() {
return sn;
}
public void setSn(double sn) {
this.sn = sn;
}
public char getOp() {
return op;
}
public void setOp(char op) {
this.op = op;
}
public Calculate(double fn, double sn, char op) {
this.fn = fn;
this.sn = sn;
this.op = op;
}
public void getAnswer(){
double ans;
switch (getOp()){
case '+':
ans = add(getFn(), getSn());
ansOutput(ans);
break;
case '-':
ans = sub (getFn(), getSn());
ansOutput(ans);
break;
case '*':
ans = mul (getFn(), getSn());
ansOutput(ans);
break;
case '/':
ans = div (getFn(), getSn());
ansOutput(ans);
break;
default:
System.out.println("--------------------------");
System.out.println("Invalid choice of operator");
System.out.println("--------------------------");
}
}
public static double add(double x,double y){
return x + y;
}
public static double sub(double x, double y){
return x - y;
}
public static double mul(double x, double y){
return x * y;
}
public static double div(double x, double y){
return x / y;
}
public static void ansOutput(double x){
System.out.println("----------- -------");
System.out.printf("the answer is %.2f\n", x);
System.out.println("-------------------");
}
}
Main.java
public class Main {
public static void main(String args[])
{
Calculate obj = new Calculate(1,2,'+');
obj.getAnswer();
}
}
Where you have written the code
public class Main {
public static void main(String args[])
{
Calculate obj = new Calculate(1,2,'+');
obj.getAnswer();
}
}
Here you have to run the class "Main" instead of the class you created at the start of the program. To do so pls go to Run Configuration and search for this class name"Main" which is having the main method inside this(public static void main(String args[])). And you will get your output.
you seem to have not created an main method, which should probably look something like this (i am not sure)
class RunThis
{
public static void main(String[] args)
{
Calculate answer = new Calculate();
answer.getNumber1();
answer.getNumber2();
answer.setNumber(answer.getNumber1() , answer.getNumber2());
answer.getOper();
answer.setOper(answer.getOper());
answer.getAnswer();
}
}
the point is you should have created a main method under some class and after compiling you should run the .class file containing main method. In this case the main method is under RunThis i.e RunThis.class.
I am new to java this may or may not be the right answer, correct me if i am wrong