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.
}
Related
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 { ... }
In the Java 8 tutorial about interface, one example says that when a class implements an interface, one has to type cast the interface type into the class type in order to invoke methods of this class, as shown by the following example from the java 8 tutorial:
public class RectanglePlus
implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
public RectanglePlus() {
origin = new Point(0, 0);
}
public RectanglePlus(Point p) {
origin = p;
}
public RectanglePlus(int w, int h) {
origin = new Point(0, 0);
width = w;
height = h;
}
public RectanglePlus(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
// a method for moving the rectangle
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
// a method for computing
// the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement
// the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect
= (RectanglePlus)other;
if (this.getArea() < otherRect.getArea())
return -1;
else if (this.getArea() > otherRect.getArea())
return 1;
else
return 0;
}
}
In the method isLargerThan(Relatable other), other is casted to type RectanglePlus in order to invoke getArea().
In the other example about default methods in interface, the compareTo(Card o) method doesn't type cast o to type PlayingCard, but can invoke int hashCode() directly, I don't understand this. Thanks for your help.
package defaultmethods;
public class PlayingCard implements Card {
private Card.Rank rank;
private Card.Suit suit;
public PlayingCard(Card.Rank rank, Card.Suit suit) {
this.rank = rank;
this.suit = suit;
}
public Card.Suit getSuit() {
return suit;
}
public Card.Rank getRank() {
return rank;
}
public boolean equals(Object obj) {
if (obj instanceof Card) {
if (((Card)obj).getRank() == this.rank &&
((Card)obj).getSuit() == this.suit) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public int hashCode() {
return ((suit.value()-1)*13)+rank.value();
}
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
public String toString() {
return this.rank.text() + " of " + this.suit.text();
}
public static void main(String... args) {
new PlayingCard(Rank.ACE, Suit.DIAMONDS);
new PlayingCard(Rank.KING, Suit.SPADES);
}
}
In short: Because hashCode is defined in java.lang.Object and every other class extends Object implicitly.
So when you have
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
the compiler already knows that o is of type Card which extends Object which defines a hashCode method. No need for an explicit cast.
On the other hand in your isLargerThan method the parameter is of type Relatable:
public int isLargerThan(Relatable other) {
RectanglePlus otherRect
= (RectanglePlus)other;
if (this.getArea() < otherRect.getArea())
return -1;
else if (this.getArea() > otherRect.getArea())
return 1;
else
return 0;
}
And judging from the link you provided, the getArea method is defined in RectanglePlus only. Since the compiler only sees Relatable it does not know anything about a getArea method at this point and you need to explicitly cast other to RectanglePlus to be able to access it.
Note that you should actually do an instanceof check before casting to avoid a ClassCastException when other is not a RectanglePlus (you don't know if there might be other classes implementing Relatable).
Let me try a non-code related example:
If people have a pet they usually give it a name. So whatever pet you have, one can always ask for its name (cf. hashCode). But they cannot ask you to make it bark (cf. getArea) unless they know that it is a dog.
And you will probably fail to make a cat bark (cf. ClassCastException).
first off I tried researching my problem but I have no idea how to word my question ... so I am not sure if there is a question out there that solves my problem and also not sure if this is the best wording for my question either.
So, I have a Superclass Shape
public abstract class Shape {
protected String name;
protected String type;
public Shape(){
name = "";
type = "";
}
public void print (){
System.out.printf("Name = %s, Type = %s", name, type);
}
}
and a Subclass 2D
public abstract class TwoDimensionalShape extends Shape{
protected double length;
protected double area;
public TwoDimensionalShape(double length){
if (length<0.0)
throw new IllegalArgumentException("ERROR: POSITIVE NUMBER REQUIRED");
this.length = length;
type = "Two Dimensional Shape";
}
public abstract void getArea();
#Override
public void print(){
System.out.printf("Name = %s, Type = %s, Length of side = %d, Area = %d",
name, type, length, area);
}
}
along with several smaller subclasses that extend off 2D (and another almost identical class 3D). My problem is with the test code, it doesn't calculate area. Class Test code
Circle S1 = new Circle(2.5);
etc.
shapesArray[0] = S1;
etc.
for(Shape CS : shapesArray){
CS.getArea();
if(CS.Type == "Three Dimensional Shape"){
CS.getVolume();
}
CS.print();
System.out.println(" ");
}
}
I removed the getArea and getVolume methods and the print statement worked fine. Which lead me to think there is a problem with the way each subclass interacts with the superclass, however, the subclass print methods override and return the correct values (except for area :( )
With the area and volume commands, the code doesn't compile and I get this error
ShapeTest.java:25: error: cannot find symbol
CS.getArea();
three times.
Here is one of the subclasses, in case it holds important info needed for a solution.
public class Circle extends TwoDimensionalShape {
public Circle(double length){
super(length);
name = "Circle";
}
#Override
public void getArea(){
area = Math.PI * length * length;
}
#Override
public void print(){
System.out.printf("Name = %s, Type = %s, Radius = %f, Area = %f",
name, type, length, area);
}
}
I am not experienced enough to understand the problem entirely and I have been changing loops, location of variables and methods in the classes but I have not made progress. I thank you for reading this long question and id appreciate any help you can offer.
Your type Shape doesn't declare that method.
The compiler doesn't know that you intend to put TwoDimensionalShape objects into that array. It only see that you said: this array contains Shapes; and shapes do no have those other two methods!
So you could do:
declare that array to contain only TwoDimensionalShape objects. Of course, then you can't add 3D
use if (thing is instanceof TwoDimensionalShape) { and then cast to that type
And then: you dont need a string type. All objects have a class; and that class already defines its exact type. That is why you use instanceof to determine types; not by adding a string field and comparing that string (the wrong way with ==) to other strings!
Your super most class Shape should have all the methods you want to access through polymorphic feature of java.
One would assign a sub-type instance of to a supertype variable to handle all possible subtype classes in a uniform fashion, e.g. using methods declared (but possibly overriden) by the supertype class.
I have made minor changes to your classes.
abstract class Shape {
protected String name;
protected String type;
public Shape() {
name = "";
type = "";
}
public void print() {
System.out.printf("Name = %s, Type = %s", name, type);
}
public abstract void getArea();
public abstract void getVolume();
}
// ----------------
abstract class TwoDimensionalShape extends Shape {
protected double length;
protected double area;
public TwoDimensionalShape(double length) {
if (length < 0.0)
throw new IllegalArgumentException(
"ERROR: POSITIVE NUMBER REQUIRED");
this.length = length;
type = "Two Dimensional Shape";
}
#Override
public void print() {
System.out.printf(
"Name = %s, Type = %s, Length of side = %d, Area = %d", name,
type, length, area);
}
}
//------------------
class Circle extends TwoDimensionalShape {
public Circle(double length) {
super(length);
name = "Circle";
}
#Override
public void getArea() {
area = Math.PI * length * length;
}
#Override
public void print() {
System.out.printf("Name = %s, Type = %s, Radius = %f, Area = %f", name,
type, length, area);
}
#Override
public void getVolume() {
System.out.println("Vaolume method invoked");
}
}
//------------------
public class Dim {
public static void main(String[] args) {
Shape[] shapesArray = new Shape[10];
Circle S1 = new Circle(2.5);
shapesArray[0] = S1;
for (Shape CS : shapesArray) {
if (CS != null) {
CS.getArea();
if (CS.type.equals("Three Dimensional Shape")) {
CS.getVolume();
}
CS.print();
System.out.println(" ");
}
}
}
}
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.
Basically I have been tasked with tackling the following scenario:
When you are designing your class/es, you have to decide what attributes and methods you will include in. For example, if you decide to work in millimeters, your size variable (length) could be of type integer (but later, when calculating the cost, you will have to convert the volume into square inches, because the cost is given per cubic inch of plastic (Table 2 and Table 3 of the coursework)). The volume of plastic material used will be the difference between the outer and inner volume of a pipe. If you decided to prompt the length in meters, then the type should be double, or float, etc.
Once you have validated the user order, your program should determine, based on Table 1, what is the type of the ordered pipe.
Table 1. Types of plastic pipes available.
Type Plastic’s grade Colour print Inner insulation Outer reinforcement Chemical resistance
0 1 2
I 1 – 3 YES NO NO NO NO YES/NO
II 2 – 4 NO YES NO NO NO YES/NO
III 2 – 5 NO NO YES NO NO YES/NO
IV 2 – 5 NO NO YES YES NO YES/NO
V 3 – 5 NO NO YES YES YES YES/NO
That's all fine but the part that is getting me is this bit here:
Say in your main class you have determined that client’s order is a pipe of type I, then you can create an object of TypeI and for this object you can call the cost() method to calculate the cost and to show it to the user.
It is basically asking to not instantiate any objects before figuring out which one you need to instantiate, which is hard when it classes a big if statement in the verification as a 'Brute force method'.
Here is what I have so far.
Main
public class Cw1 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
ArrayList<Pipe> pipeList = new ArrayList<Pipe>();
// TODO code application logic here
Grade g1 = new Grade(1,3,true,false,false,false,false);
Grade g2 = new Grade(2,4,false,true,false,false,false);
Grade g3 = new Grade(2,5,false,false,true,false,false);
Grade g4 = new Grade(2,5,false,false,true,true,false);
Grade g5 = new Grade(3,5,false,false,true,true,true);
pipeList.add(g1);
pipeList.add(g2);
pipeList.add(g3);
pipeList.add(g4);
pipeList.add(g5);
for (Pipe p: pipeList)
{
p.setGrade(1);
p.setColour0(false);
p.setColour1(false);
p.setColour2(true);
p.setIns(true);
p.setReinf(true);
p.validate();
}
}
}
Grade (It must have abstracting in the solution)
public class Grade extends Pipe {
public Grade(int minGrade, int maxGrade, boolean hasColour0, boolean hasColour1, boolean hasColour2, boolean hasIns, boolean hasReinf) {
super(minGrade, maxGrade, hasColour0, hasColour1, hasColour2, hasIns, hasReinf);
}
}
And pipe
public abstract class Pipe {
public boolean isChemRes() {
return chemRes;
}
public void setChemRes(boolean chemRes) {
this.chemRes = chemRes;
}
public boolean isColour0() {
return colour0;
}
public void setColour0(boolean colour0) {
this.colour0 = colour0;
}
public boolean isColour1() {
return colour1;
}
public void setColour1(boolean colour1) {
this.colour1 = colour1;
}
public boolean isColour2() {
return colour2;
}
public void setColour2(boolean colour2) {
this.colour2 = colour2;
}
public double getDiameter() {
return diameter;
}
public void setDiameter(double diameter) {
this.diameter = diameter;
}
public boolean isIns() {
return ins;
}
public void setIns(boolean ins) {
this.ins = ins;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public boolean isReinf() {
return reinf;
}
public void setReinf(boolean reinf) {
this.reinf = reinf;
}
public Pipe(int minGrade, int maxGrade, boolean hasColour0, boolean hasColour1, boolean hasColour2, boolean hasIns, boolean hasReinf) {
this.minGrade = minGrade;
this.maxGrade = maxGrade;
this.hasColour0 = hasColour0;
this.hasColour1 = hasColour1;
this.hasColour2 = hasColour2;
this.hasIns = hasIns;
this.hasReinf = hasReinf;
}
public Pipe() {
}
//<editor-fold desc="Class variables">
private int grade;
private double length, diameter;
private boolean colour0, colour1, colour2, ins, reinf, chemRes;
private int minGrade, maxGrade;
private boolean hasColour0, hasColour1, hasColour2, hasIns, hasReinf;
// </editor-fold>
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
//<editor-fold desc="Public Methods">
public double calcVol()
{
return 0;
}
public double calcCost()
{
return 0;
}
public void validate()
{
if ((grade >= minGrade && grade <= maxGrade) & (colour0 == true && hasColour0 || colour1 == true && hasColour1 || colour2 == true && hasColour2) && (ins == hasIns) && (reinf == hasReinf))
{
System.out.print("True");
}
else
{
System.out.print("False");
}
}
// </editor-fold>
}
So basically, I don't understand how I could achieve the same result without instantiating the objects before hand and validating them?
The class isn't high level, we have only just learned polymorphism.
Usually, the data which tells you which objects to create comes from an external source: a file, a socket, another object etc. In your case, you could use a text file. Create the Grade instances passing the values you read to the constructor and then call validate and cost on each.
public class PipeFactory(){
public Pipe CreatePipe( int minGrade, int maxGrade, boolean hasColour0, boolean hasColour1, boolean hasColour2, boolean hasIns, boolean hasReinf ){
if( (minGrade == 1 || maxGrade == 3) /* ... Complete this condition yourself */ )
return new TypeIPipe();
if( (minGrade == 2 || maxGrade == 4 /* ... Complete this condition yourself */ )
return new TypeIIPipe();
//If for other types...
//If no pipe was created, parameters are invalid, so we throw an exception
throw new InvalidArgumentException( "Can't create a pipe with these parameters" );
}
}