Idiomatic Java: constraining data [closed] - java

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Playing with a simple Java Point class where I would like to constrain the X and Y values to be doubles that must be in the range -10 to 10, inclusive. I've written some code, but it's been years since I've written java and I would like to know if this is how it would be written in modern Java:
public class Point {
private double x;
private double y;
public Point(double x, double y) {
constrain("x", x);
constrain("y", y);
this.x = x;
this.y = y;
}
// is there a cleaner/shorter way of handling this, such as a direct way of declaring a
// subtype of double that I could use in method signatures?
protected static void constrain(String name, double val) {
if ( val < -10 || val > 10 ) {
throw new IllegalArgumentException(name + " must be between -10 and 10");
}
}
public double getX() { return x; }
public void setX(double x) {
constrain("x", x);
this.x = x;
}
public double getY() { return y; }
public void setY(double y) {
constrain("y", y);
this.y = y;
}
#Override
public String toString() {
return ("[" + x + "," + y + "]");
}
}

This is probably how I'd do it:
public class Point
{
private static final double X_MIN = -10.0, X_MAX = 10.0;
private static final double Y_MIN = -10.0, Y_MAX = 10.0;
private double x, y;
public Point(double x, double y) throws IllegalArgumentException
{
setX(x);
setY(y);
}
public double getX()
{
return x;
}
public double getY()
{
return y;
}
public void setX(double x) throws IllegalArgumentException
{
if (x < X_MIN || x > X_MAX)
{
throw new IllegalArgumentException("X out of range.");
}
this.x = x;
}
public void setY(double y) throws IllegalArgumentException
{
if (y < Y_MIN || y > Y_MIN)
{
throw new IllegalArgumentException("Y out of range");
}
this.y = y;
}
#Override
public String toString()
{
return String.format("[%.1f,%.1f]", x, y);
}
}

If the X and Y values are always from the same domain then you could encapsulate them in a class that does the checking for you:
class Coord {
private final double scalarValue;
public Coord(double scalarValue) throws IllegalArgumentException {
if (Math.abs(scalarValue) > MAX_COORD) {
throw new IllegalArgumentException("Coordinate out of range");
}
this.scalarValue = scalarValue;
}
public double getScalar() {
return scalarValue;
}
}
That puts the check in one place and allows you to expand coordinate functionality in the future without messing up your Point class. It also explicitly makes coordinates immutable which is likely to be a good idea (depending on use case).
Then your point constructor becomes:
public Point(Coord x, Coord y);

Related

How do you put {0,0} into an array and able to change it when a if statement is met

My plan is to create an array with only two values, which is {0,0} because I want to change its value in order to simulate how the coordinate moves.
I want to move the coordinate up to (0,1) when a random number is assigned to x,
let's say I have a line of if loop,
if(x=0){ //I would change the value from {0,0} to {0,1} }
I tried to write the code in this way,
public static int x = 0;
public static int y = 0;
public static void randomWalk(int [] moving_point) {
int r = ThreadLocalRandom.current().nextInt(4);
if(r == 0) {
moving_point[x,y] = moving_point[x,y+1];
}
}
but it is not correct,
is this a possible thing to do? and how?
Thank you!
The innermost code must be changed to:
moving_point[1] = moving_point[1] + 1;
The 1 gives you the index of the 'y' position in your moving_point array, but will not modify your fields.
public static int x = 0;
public static int y = 0;
public static void randomWalk(int [] moving_point) {
int r = ThreadLocalRandom.current().nextInt(4);
if(r == 0) {
moving_point[x,y] = moving_point[x,++y];
}
}
I would suggest to use Pre-Increment(++x) in this scenario. Pre-increment means that the variable is incremented BEFORE it's evaluated in the expression.
moving_point[1]++;
inside the for.
I suggest you not to pass an array to the function since the method can't assume its length. You can either pass two ints or pass a class, there are severals already implemented: Point is just an example.
The arguably 'correcter' way to represent a Coordinate in Java is to create a Coordinate class:
public class Coordinate {
private int x;
private int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void moveUp(int distance) {
y += distance;
}
public void moveDown(int distance) {
y -= distance;
}
public void moveLeft(int distance) {
x -=distance;
}
public void moveRight(int distance) {
x += distance;
}
#Override
public String toString() {
return String.format("{%d,%d}", x, y);
}
}
public static void randomWalk(Coordinate point) {
int r = ThreadLocalRandom.current().nextInt(4);
if(r == 0) {
point.moveUp(1);
}
}
This allows you to succinctly represent multiple Coordinates in your software, as well as allowing you to write some very intuitive methods, such as the moveUp/Down/Left/Right in the above example.
Another good reason for doing this is that there are no constraints on your array, so someone could inadvertently add a third, fourth or fifth value, which clearly wouldn't make sense. Using a separate class makes the code more self-documenting.
Back to the example, you can now run:
Coordinate c = new Coordinate(0, 0);
System.out.println(c); // prints "{0,0}"
randomWalk(c);
System.out.println(c); // prints "{0,1}" IF you were lucky to get a random 0...
NB:
Here, Coordinate space is interpreted as like on a graph in school, increasing x to the right and increasing y going up. On computer screens the y-space is usually flipped (the origin is the top left of the screen), so as an exercise consider how you might correct that. (Hint, it only involves changingmoveUp() and moveDown())
Edit:
Following your comment, to be able to record the path, you'll probably want to use a LinkedHashMap instead of ArrayList (efficiency of lookups while keeping the ordering) and make Coordinate immutable by returning a new instance from each moveX operation. You will also need to implement equals() and hashCode().
public class Coordinate {
private final int x;
private final int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Coordinate moveUp(int distance) {
return new Coordinate(x, y+distance);
}
public Coordinate moveDown(int distance) {
return new Coordinate(x, y-distance);
}
public Coordinate moveLeft(int distance) {
return new Coordinate(x-distance, y);
}
public Coordinate moveRight(int distance) {
return new Coordinate(x+distance, y);
}
#Override
public String toString() {
return String.format("{%d,%d}", x, y);
}
#Override
public int hashCode() {
//we need to do something a bit more clever than "x+y", otherwise {1,0} might end up with the same hash as {0,1}
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(obj == null) return false;
if(getClass() != obj.getClass()) return false;
Coordinate other = (Coordinate)obj;
if(x != other.x) return false;
if(y != other.y) return false;
return true;
}
}
public class Walker {
private LinkedHashSet<Coordinate> path = new LinkedHashSet<>();
private Coordinate last;
public Walker(Coordinate startingPoint) {
path.add(startingPoint);
last = startingPoint;
}
public Set<Coordinate> getPath() {
return path;
}
public void randomWalk() {
int r = ThreadLocalRandom.current().nextInt(4);
if(r == 0) {
Coordinate nextStep = last.moveUp(1);
if(path.add(nextStep)) {
//Set returns "true" if the item was added, "false" otherwise.
last = nextStep;
} else {
//So if not added, we've already been there.
//take alternative action, retry, whatever...
}
}
}
}
Walker w = new Walker(new Coordinate(0,0));
for(int i=0; i<10; i++) {
w.randomWalk();
}
System.out.println(w.getPath());

Calling a constructor from a class in the main method?

I've read some of the other questions, but still couldn't seem to figure out how to get mine to work, any help is appreciated. The code I have so far is given below. I want to be able to call a newPointParameters to create a new class.
public class Lab4ex1 {
public static void main(String[] args) {
System.out.println("" + 100);
new newPointParameter(42,24);
}
class Point {
private double x = 1;
private double y = 1;
public double getx() {
return x;
}
public double gety() {
return y;
}
public void changePoint(double newx, double newy) {
x = newx;
y = newy;
}
public void newPointParameters(double x1, double y1) {
this.x = x1;
this.y = y1;
}
public void newPoint() {
this.x = 10;
this.y = 10;
}
public double distanceFrom(double x2, double y2) {
double x3 = x2 - this.x;
double y3 = y2 - this.y;
double sqaureadd = (y3 * y3) + (x3 * x3);
double distance = Math.sqrt(sqaureadd);
return distance;
}
}
}
So, currently, neither newPointParameters nor newPoint are constructors. Rather, they are just methods. To make them into constructors, they need to share the same name as the class the construct
class Point {
private double x = 1;
private double y = 1;
public Point() {
this.x = 10;
this.y = 10;
}
public Point(double x, double y) {
this.x = x;
this.y = y;
}
Then, when you want to create a new point, you simply do the following
For a default point
public class Lab4ex1 {
public static void main(String[] args) {
System.out.println("" + 100);
//this will create a new Point object, and call the Point() constructor
Point point = new Point();
}
For the Point with parameters
public class Lab4ex1 {
public static void main(String[] args) {
System.out.println("" + 100);
//this will create a new Point object, and call the
//Point(double x, double y) constructor
Point point = new Point(10.0, 10.0);
}
It should be
public static void main(String[] args) {
System.out.println("" + 100);
Point p = new Point();
p.newPointParameter(42,24);
}
newPointParameters is not a constructor. I think this is what you are looking to do:
public Point(double x1, double y1) {
x = x1;
y = y1;
}
Then you can create a Point object in your main class using this constructor:
Point p = new Point(42, 24);
It looks like you also intended for newPoint() to be a constructor, so it should look like this:
public Point() {
x = 10;
y = 10;
}

translate coordinate method java [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I can't seem to get my transform method right. Any suggestions on how I could make the method translate the point better? i.e. when this method is invoked, it should be able to give the new point. Also I'm having issues creating the slope method...I know slope is y2-y1/x2-x1 but how would I make that into a method. Is there a Math class I can import for the slope? Thanks much appreciated
import java.util.*;
public class Point {
private int x; // to store variables for x & y
private int y;
private double slope;
//default constructor
public Point () {
double x = 0;
double y = 0;
}
//alternate constructor
public Point (double x1, double y1) {
double x = x1;
double y = y1;
}
//set coordinates
public void setCoord (double x1, double y1){
double x = x1;
double y = y1;
}
//print method
public void print () {
System.out.print(x + "," + y);
}
//toString Method
public String toString() {
return "(" + x + "," + y + ")";
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void equals () {
if (x==y)
System.out.println(" Coordinates are the same ");
else {
System.out.println(" Coordinates are different ");
}
}
public void copy(Point temp) {
x=temp.x;
y=temp.y;
}
public Point getCopy() {
Point temp = new Point();
temp.x = x;
temp.y = y;
return temp;
}
public void distanceFromOrigin(int x1, int y1) {
double dx = x-x1;
double dy = y-y1;
}
//calculate the distance from one point to another
public void distance (double x1, double y1) {
double distance = Math.sqrt((x * x1) + (y * y1));
}
//shift the location of a point by a given amount
public void transform (double dx, double dy) {
double transform = ((x+dx) (y+dy));
}
// returns true if any given point lines up horizontally with a given point.
public boolean isHorizontal () {
return true;
}
// returns true if any given point lines up vertically with a given point.
public boolean isVertical () {
return true;
}
// returns the slope of the line
public double slope() {
return slope;
}
}
public void equals (Object o) {
if(o instanceof Point) {
Point p = (Point)o;
return p.x == x && p.y == y;
} else {
return false;
}
}
public Point getCopy() {
return new Point(x, y);
}
public double slope(Point otherPoint) {
return ((double)(otherPoint.y - y)) / ((double)(otherPoint.x / x));
}
public double distance (Point otherPoint) {
double dx = otherPoint.x - x;
double dy = otherPoint.y - y;
return Math.sqrt((dx * dx) + (dy * dy));
}
public double distanceFromOrigin() {
return distance(new Point(0, 0));
}
public boolean isHorizontal (Point otherPoint) {
return otherPoint.y == y;
}
public boolean isVertical(Point otherPoint) {
return otherPoint.x == x;
}
public void transform (double dx, double dy) {
x += dx;
y += dy;
}

How to send an Object through a constructor?

I am currently facing a problem and can't find the way. Here is the question...
Complete the Point class bellow:
public class Point{
private int x;
private int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
}
So that the following code produces the output bellow:
public class TestClass{
public static void testEqual(Point p1, Point p2){
if (p1.equals(p2)){
System.out.println("The two points are equal\n"+p1);
}else{
System.out.println("The two points are not equal");
System.out.println("First Point: "+ p1);
System.out.println("Second Point: " + p2);
}
}
public static void main(String [] args){
Point p1 = new Point(2,3);
Point p2 = Point.clonePoint(p1);
Point p3 = new Point(1,1);
Point p4 = new Point(2,3);
testEqual(p1,p2);
testEqual(p1,p3);
testEqual(p1,p4);
testEqual(p2,p4);
}
}
Outputs
The two points are equal
The X Coordinate is 2 and the Y Coordinate is 3
The two points are not equal
First Point: The X Coordinate is 2 and the Y Coordinate is 3
Second Point: The X Coordinate is 1 and the Y Coordinate is 1
The two points are equal
The X Coordinate is 2 and the Y Coordinate is 3
The two points are equal
The X Coordinate is 2 and the Y Coordinate is 3
I can understand all the things but except this line Point p2 = Point.clonePoint(p1);
How can I solve it?
Add get methods for returning the point coordinates to your Point class:
public int getX()
{
return x;
}
public int getY()
{
return y;
}
Then add the following clonePoint() static method to your Point class:
public static Point clonePoint(Point p)
{
return new Point(p.getX(), p.getY());
}
Then add the following equals() method to your Point class:
public boolean equals(Point p)
{
return (p.getX() == getX()) && (p.getY() == getY());
}
This is all you need:
[note the last method 'clone' is a static (class) method that you access by prefixing it with the class name 'Point' followed by '.'].
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return "The X Coordinate is " + x + " and the Y Coordinate is " + y;
}
#Override
public boolean equals(Object otherPoint) {
if (this == otherPoint) return true;
if (otherPoint == null || getClass() != otherPoint.getClass()) return false;
Point point = (Point) otherPoint;
return x == point.x && y == point.y;
}
#Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
public static Point clonePoint(Point p) {
return p != null ? new Point(p.x, p.y) : null;
}
}
I think your homework wants you to add a cloning method to the Point class like this:
public class Point{
private int x;
private int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
public static Point clonePoint(Point p){ return new Point(p.x,p.y); }
}

Return calculated value from enum

please my question are two and very simple
misinterpret enum as is
this idea missing some important abstraction in my code
code example, where oprt.calc(x, y) isn't compilable, with warning cannot find symbol
public enum Operation {
PLUS {
public double calc(double x, double y) {
return x + y;
}
},
MINUS {
public double calc(double x, double y) {
return x - y;
}
},
MULTILPLE {
public double calc(double x, double y) {
return x * y;
}
},
DIVIDED_BY {
public double calc(double x, double y) {
return x / y;
}
};
public static void main(String args[]) {
double x = 15.25;
double y = 24.50;
for (Operation oprt : Operation.values()) {
System.out.println(x + " " + oprt + " "
+ y + " = " + oprt.calc(x, y));
}
}
}
What you miss is abstract declaration of calc() method:
enum Operation {
PLUS {
public double calc(double x, double y) {
return x + y;
}
},
MINUS {
public double calc(double x, double y) {
return x - y;
}
},
MULTILPLE {
public double calc(double x, double y) {
return x * y;
}
},
DIVIDED_BY {
public double calc(double x, double y) {
return x / y;
}
};
**public abstract double calc(double x, double y);**
public static void main(String args[]) {
double x = 15.25;
double y = 24.50;
for (Operation oprt : Operation.values()) {
System.out.println(x + " " + oprt + " "
+ y + " = " + oprt.calc(x, y));
}
}
}
You need to declare an abstract method double calc(double x, double y) in the enum directly, and override it in every enum member.
The correct syntax to use enum methods is:
private enum Operation {
PLUS, MINUS, MULTILPLE, DIVIDED_BY;
public double calc(double x, double y) {
switch (this) {
case PLUS:
return x + y;
case MINUS:
return x - y;
case MULTILPLE:
return x * y;
case DIVIDED_BY:
return x / y;
}
return 0;
}
}
public static void main(String args[]) throws IOException {
double x = 15.25;
double y = 24.50;
for (Operation oprt : Operation.values()) {
System.out.println(x + " " + oprt + " " + y + " = "
+ oprt.calc(x, y));
}
}
You are overriding calc(), while you have no original calc() method. Either declare an abstract method:
public abstract double calc(double x, double y);
or declare a concrete method with a default implementation:
public double calc(double x, double y)
{
// ...
}
It doesn't compile because currently, the calc method only exists in each of the possible values of your enum - but it does not exist on the type Operation itself. That's why your compiler (and mine) doesn't accept it.
So, you need to define the method in the type. Maybe something like this:
public abstract double calc(double x, double y);
Your enum values (PLUS, MINUS, MULTIPLE and DIVIDED_BY each implement that method.
public double calc(double x, double y){}
is same as
private double calc(double x,double y){}
unless you add calc() method to the enum Operation.As per JLS:
Instance methods declared in these class bodies are may be invoked outside
the enclosing enum type only if they override accessible methods in
the enclosing enum type.
So basically , the type of oprt is Operation and as Operationdoesn't have any declaration for method called double calc(double x,double y), you cannot invoke the method using oprt. In short the methods defined in class bodies should be overridden methods, for them to be accessible outside.

Categories

Resources