My recommendation is to break the problem into sub-problems and create a solution for each. This is called Problem Decomposition. Once all of the solutions are created, integrate them. In theory, integrating all of the solutions together should solve the entire problem. In your case, I think this a good, logical way to decompose your problem:
- Box creation (Setting dimension on each Box)
- Storing the boxes
- Calculating Volume
- Calculating Surface Area
- Capturing user input
- Iterating through Box collection
Box Creation
My recommendation is that, since all these subproblems are all related to your Box
object, create helper classes and/or methods to handle each one. In this case, you can create a method that given height, width, and length, returns a new instance of Box
.
public static Box createBox (int height, int width, int length) {
return new Box(height, width, length);
}
In turn, your Box
class should be storing these parameters as global members:
public class Box {
private final int height, width, length;
public Box (int height, int width, int length) {
this.height = height;
...
}
... (other methods omitted)
}
I know this looks like overkill, and I agree. BUT, what this does is teach you a very valuable lesson in Single Responsibility Principle as well as code modularization which helps testing these smaller jobs independently. I am a strong believer that, helper classes should contain nothing but static methods. Why? Because it doesn't make much sense to create instances of objects that never hold data. In Java, Math
class is an example of what I am talking about.
Alternatively, you could create boxes without dimension and set the height, width, and length separately, but I don't believe this is a good way to go about it. For example, if one or more parameters are not set, you could end up with erroneous behavior. Lastly, your Box
class should create immutable objects so that dimensions cannot be changed once an instance of the class is created. I will address this point last.
Storing the boxes
If this is a single-class project, maybe you want to make this collection (most likely a java.util.List
type) a global attribute of your class. If this project contains more than one class, the class that calls your createBox
method will have some code to add the return value of this method into some list. Something like this should do:
Box box1 = BoxUtils.createBox(1, 2, 3);
myList.add(box1);
Box box2 = BoxUtils.createBox(4, 5, 6);
myList.add(box2);
...
You get the idea. That said, this should be better done in a loop. We will get back to this later. For now, just remember this is NOT done by the box utilities or helper class. This is done by the class that calls it; in your case, BoxTest
public class BoxTest {
public static void main(String[] args) {
// TODO get user input
// create box
// add box to list
...
}
Calculate Volume
This method should be in Box
class...
box.getVolume();
Since the parameters are passed via the constructor, you don't need to pass them to this method again. However, you could argue that since you have a utilities class for all box related helper methods, you could move this responsibility there and have the Box
class to be a simple POJO (that does not how to calculate its own volume or area). I prefer this approach. If you decide to do this, you need to pass a Box
instance to the helper method and return the result.
Box box = new Box(1, 2, 3);
int volume = BoxUtils.calculateVolume(box); // preferred
Calculate Surface Area
This method should also be in Box
class or box utilities...
int area = box.getSurfaceArea(); // In Box, or
int area = BoxUtils.getSurfaceArea(box); // in BoxUtils (preferred)
Capturing User Input
Iterating through the collection of boxes was left for last for a reason. I think you should firs try to get your problem working with a single box first. Make sure you open and close your Scanner
object properly, get the user input correctly, etc. Then, once you test your solution to your satisfaction, expand your solution to capture inputs and create boxes in a loop operation. That way if it fails, you know your problem is isolated to this one part of the problem and not something else. For situations like this is why Problem Decomposition is crucial.
Your original problem uses double
for your height, width, and length. I am using int
for simplicity.
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter height, width, and length for the box (space-separated i.e. 10 20 30)");
int height = input.nextInt();
int width = input.nextInt();
int length = input.nextInt();
input.close();
Box box = new Box(height, width, length);
System.out.println(box); // I overrode Object#toString() in Box class to do this.
}
My output
Enter height, width, and length for the box (space-separated i.e. 10 20 30)
10 20 30
height: 10; width: 20; length: 30
Iterating Through Box Collection
You mentioned that you wanted to use enhanced for loop for this. You probably won't be able to do this for what I am recommending. See this article for details. Instead, a traditional for loop will do just fine. Since I know everything has worked so far, I can now modify my existing solution to introduce looping to capture the user inputs
public static void main(String[] args) {
Box[] boxArray = new Box[4];
Scanner input = new Scanner(System.in);
for (int i = 0; i < boxArray.length; i++) {
System.out.println("\nEnter height, width, and length for the box (space-separated i.e. 10 20 30)");
int height = input.nextInt();
int width = input.nextInt();
int length = input.nextInt();
Box box = new Box(height, width, length);
System.out.println(box);
// TODO print volume and area
}
input.close();
}
Notice that the code is basically the same. I just created an array to store the boxes and a loop to repeat capturing the user's input until the array is full (4 boxes). You could modify this loop to go on forever and only break after a special character is pressed (which is out of scope for what you need to do).
Once I get this part done, it is time to add printing out (calculate) the volume and area for each box. You can do this inside the same loop (recommended) or create another loop and iterate through the array to display these results.
Now, to finish, I just replaced the TODO with the following code:
System.out.println("Box " + (i+1) + " surface area: " + BoxUtils.calculateSurfaceArea(box));
System.out.println("Box " + (i+1) + " volume: " + BoxUtils.calculateVolume(box));
Now when I execute the code, I will get an output that resembles the following:
Enter height, width, and length for the box (space-separated i.e. 10 20 30)
1 2 3
Box 1 surface area: 22.0
Box 1 volume: 6.0
Coding for Immutability
Coding for immutability is out of scope for your requirement, but I think it is important to mention. Immutability has many benefits, one of which is thread safety. It is obviously not without drawbacks, but in my opinion the benefits outweighs them. For this example, I just made the fields of the Box
class private
and final
, and I did not provide setter methods. So, your Box
class should look like this:
public class Box {
private final int height, width, length;
public Box(int height, int width, int length) {
this.height = height;
this.width = width;
this.length = length;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public int getLength() {
return length;
}
@Override
public String toString() {
return "height: " + height + "; " + "width: " + width + "; " + "length: " + length;
}
}
Your BoxUtils
like this:
public class BoxUtils {
private BoxUtils() {
throw new AssertionError("BoxUtils cannot be instantiated");
}
public static Box createBox (int height, int width, int length) {
return new Box(height, width, length);
}
public static double calculateVolume(Box box) {
return box.getWidth() * box.getHeight() * box.getLength();
}
public static double calculateSurfaceArea(Box box) {
int width = box.getWidth();
int height = box.getHeight();
int length = box.getLength();
return 2 * ((width * length) + (height * length) + (height * width));
}
}
and finally your BoxTest
like this:
public class BoxTest {
public static void main(String[] args) {
Box[] boxArray = new Box[4];
Scanner input = new Scanner(System.in);
for (int i = 0; i < boxArray.length; i++) {
System.out.println("\nEnter height, width, and depth for the box (space-separated i.e. 10 20 30)");
int height = input.nextInt();
int width = input.nextInt();
int depth = input.nextInt();
Box box = new Box(height, width, depth);
System.out.println("Box " + (i+1) + " surface area: " + BoxUtils.calculateSurfaceArea(box));
System.out.println("Box " + (i+1) + " volume: " + BoxUtils.calculateVolume(box));
}
input.close();
}
}