I want to use a map in Groovy where the keys will be instances of an unmutable class.
This is something I do often in Java and it works fine, like in this example class:
public class TestMap {
static final class Point {
final int x; final int y;
public Point(int x, int y) {this.x = x;this.y = y;}
}
public static void main(String[] args) {
Map<Point, String> map = new HashMap<>();
final Point origin = new Point(0, 0);
map.put(origin, "hello world !" );
if(!map.containsKey(origin))
throw new RuntimeException("can't find key origin in the map");
if(!map.containsKey(new Point(0,0))) {
throw new RuntimeException("can't find new key(0,0) in the map");
}
}
}
But when I try to achieve the same thing with Groovy, it doesn't work.
Why ?
Here is a sample non working example in Groovy:
class Point {
final int x; final int y
Point(int x, int y) { this.x = x; this.y = y }
public String toString() { return "{x=$x, y=$y}" }
}
def origin = new Point(0, 0)
def map = [(origin): "hello"]
map[(new Point(1,1))] = "world"
map.put(new Point(2,2), "!")
assert map.containsKey(origin) // this works: when it's the same ref
assert map.containsKey(new Point(0,0))
assert map.containsKey(new Point(1,1))
assert map.containsKey(new Point(2,2))
assert !map.containsKey(new Point(3,3))
You need to have an equals and hashCode method on your Point class so that the instances can be found as keys in the HashMap
You can do this quickly by adding an annotation in Groovy:
import groovy.transform.*
#EqualsAndHashCode
class Point {
final int x; final int y
Point(int x, int y) { this.x = x; this.y = y }
public String toString() { return "{x=$x, y=$y}" }
}
Related
I'm newbie in Java. I'm not sure why line my2.print_list(); is printing only object my2. I want to print every time whole list of objects. I'm adding every object to list in constructor. I'm 90% sure that for loop in function print_list is good. The compiler shows no problems. I'll appreciate all help.
public class Main {
public static void main(String[] args) {
// write your code here
rectangle my = new rectangle(5);
rectangle my1 = new rectangle(3,6);
rectangle my2 = new rectangle(10,7);
System.out.println( my2.getCounter());
my2.print_list(); ////////////////////<- described line
}
}
/// my class rectangle
import java.util.ArrayList;
import java.util.List;
public class rectangle {
public static int counter =0;
public int x;
public int y;
public List<rectangle> List = new ArrayList<rectangle>();
public rectangle(int x, int y) {
this.x = x;
this.y = y;
System.out.println("Rec");
List.add(this);
counter++;
}
public rectangle(int x) {
this.x = x;
this.y = x;
System.out.println("Sqr");
List.add(this);
counter++;
}
#Override
public String toString() {
return "x->"+x+" y->"+y+" Field: "+(x*y);
}
public void print_list()
{
for(rectangle x : List)
{
System.out.println(x);
}
}
Every instance of your class has its' own instance of List. Make it static if it should be shared (which is the only way your List will be populated). Also, please rename the variable List (it looks exactly like the interface java.util.List). Also, there's no reason to make it public.
private static List<rectangle> myList = new ArrayList<rectangle>();
And then change print_list like
public void printList()
{
for(rectangle x : myList)
{
System.out.println(x);
}
}
Also, the class name should be Rectangle (to follow Java naming conventions).
Change
public List<rectangle> List = new ArrayList<rectangle>();
to
public static List<rectangle> List = new ArrayList<rectangle>();
So there's only one instance of List.
So I had the following code below and called Operators Op = new Operators() elsewhere. However, I got an error in the getMethod call. I admit I'm not completely sure how to use it and got this result by reading other people's code, so any help would be great. Thanks.
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class Operators {
static Map<String, Method> METHODS = new HashMap<String, Method>();
String ADD = "+"; String MULTIPLY = "*"; String SUBTRACT = "-"; String DIVIDE = "/";
private static Class[] inputTypes = {Float.class, Float.class};
Operators() throws NoSuchMethodException, SecurityException {
METHODS.put(ADD, getMethod("add"));
METHODS.put(MULTIPLY, getMethod("multiply"));
METHODS.put(SUBTRACT, getMethod("subtract"));
METHODS.put(DIVIDE, getMethod("divide"));
}
static Method getMethod(String s) throws NoSuchMethodException {
return Operators.class.getMethod(s, inputTypes);
}
public static float add(float x, float y) {
return x+y;
}
public static float multiply(float x, float y) {
return x*y;
}
public static float subtract(float x, float y) {
return x-y;
}
public static float divide(float x, float y) {
return x/y;
}
}
Edit. The line referenced was return Operators.class.getMethod(s, inputTypes); inside the getMethod method.
It might give me a better idea of how to help you once I understand what on earth you are trying to do, but on first glance, this might be it:
the inputTypes-array houses two Float.class-es, but your methods use the primitive types. Float with a capital letter is different from float lowercase, hence I would expect a NoSuchMethodException.
you can also avoid to declare the input parameters type by changing the class as following and you can do it outside the constructor:
public class Operators {
static final String ADD = "+";
static final String MULTIPLY = "*";
static final String SUBTRACT = "-";
static final String DIVIDE = "/";
private static Method[] methods;
static Map<String, Method> methodsMap = new HashMap<String, Method>();
static {
methods = Operators.class.getMethods();
try {
methodsMap.put(ADD, getMethod("add"));
methodsMap.put(MULTIPLY, getMethod("multiply"));
methodsMap.put(SUBTRACT, getMethod("subtract"));
methodsMap.put(DIVIDE, getMethod("divide"));
} catch (NoSuchMethodException e) {
// handle error
e.printStackTrace();
}
}
static Method getMethod(String s) throws NoSuchMethodException {
for (Method method : methods) {
if (method.getName().equalsIgnoreCase(s))
return method;
}
throw new NoSuchMethodException(s);
}
public static float add(float x, float y) {
return x + y;
}
public static float multiply(float x, float y) {
return x * y;
}
public static float subtract(float x, float y) {
return x - y;
}
public static float divide(float x, float y) {
return x / y;
}
}
and you can use the methods map:
System.out.println(Operators.methodsMap.get("+").invoke(null, 1.0, 1.0));
So I have this piece of code:
private ArrayList<Triangle3D> combine(ArrayList<Triangle2D> leftTriangles, ArrayList<Triangle2D> rightTriangles) {
ArrayList<Triangle3D> returnTriangles = new ArrayList<Triangle3D>();
for (Triangle2D eL : leftTriangles){
Triangle2D eR = eL.getOtherTriangle(rightTriangles);
if(eR != null){
ArrayList<Point3d> corners = new ArrayList<Point3d>(3);
for(Tuple<Integer, Integer> cornerL : eL.getCorners()){
Tuple<Integer, Integer> cornerR = eR.getCorrespondingCorner(cornerL);
if(cornerL != cornerR){
corners.add(addDistances(cornerL, cornerR));
}
}
returnTriangles.add(new Triangle3D(corners, eL.getColor()));
}
}
return returnTriangles;
}
But for some reason whenever i excecute the line:
returnTriangles.add(new Triangle3D(corners, eL.getColor()));
The previous "corners" values of the Triangle3D elements that are already in the list get overriden by the newle added ones. Which I think is weird because I clearly make a new Arraylist on this line:
ArrayList<Point3d> corners = new ArrayList<Point3d>(3);
I defined the Tuple class myself as following:
package vision.polyhedradetection;
public class Tuple<X, Y> {
private final X x;
private final Y y;
public Tuple(X x, Y y) {
this.x = x;
this.y = y;
}
public X getX() { return x; }
public Y getY() { return y; }
public Tuple<X, Y> copy(){
return new Tuple<X,Y>(this.x, this.y);
}
#Override
public String toString() {
return "(" + x + "," + y + ")";
}
#Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof Tuple)){
return false;
}
Tuple<Integer, Integer> other_ = (Tuple<Integer, Integer>) other;
return other_.x == (this.x) && other_.y == (this.y);
}
}
EDIT:
I found the root of the problem. But still don't know how to fix it. It's in my Triangle3D class. This is my class:
package vision.polyhedradetection;
import javax.vecmath.Point3d;
import java.util.List;
public class Triangle3D {
private static Point3d corner1 = new Point3d();
private static Point3d corner2 = new Point3d();
private static Point3d corner3 = new Point3d();
private int color;
public Triangle3D(Point3d corner1, Point3d corner2, Point3d corner3, int color) {
this.corner1 = corner1;
this.corner2 = corner2;
this.corner3 = corner3;
this.color = color;
}
public Triangle3D(List<Point3d> corners, int color) {
this.corner1 = corners.get(0);
this.corner2 = corners.get(1);
this.corner3 = corners.get(2);
this.color = color;
}
private static Point3d centroid;
public Triangle3D(Point3d centroid, int color) {
this.centroid = centroid;
this.color = color;
}
public Point3d[] getCorners() {
Point3d[] Corners = {corner1, corner2, corner3};
return Corners;
}
public int getColor() {
return this.color;
}
public Point3d getCentroid() {
if (this.centroid != null) return this.centroid;
else {
Double x = (double) Math.round((corner1.x + corner2.x + corner3.x) / 3);
Double y = (double) Math.round((corner1.y + corner2.y + corner3.y) / 3);
Double z = (double) Math.round((corner1.z + corner2.z + corner3.z) / 3);
this.centroid = new Point3d(x, y, z);
return this.centroid;
}
}
}
The problem lies in this code in my combine function:
returnTriangles.add(new Triangle3D(corners, eL.getColor()));
For some reason when I create this new Triangle3D my corner1, corner2, corner3 in the "new" creating triangle are already set (thus they are pointing to my already existing corners). How do I get rid of this dependency? I don't get it since i make new corners when I create that class.
Can you provide me with example data where I can see the value being overridden?
ArrayList.add add an element, it does not replace an element.
Your corners is within the for loop scope, so it shouldn't save any previous data.
I do not think you have debugged it properly and mistakenly think that it replaces the previous value. I would gladly help you, but I need the same data as the data that you have used.
I have a problem. I just used the example of jackson json for deserializing builder pattern but I always get an empty json.
I use jackson-databind version 2.8.4
Am I missing something?
So my code is as follows:
The Value class
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
#JsonDeserialize(builder=ValueBuilder.class)
public class Value {
private final int x, y;
protected Value(int x, int y) {
this.x = x;
this.y = y;
}
}
The ValueBuilder Class
import com.fasterxml.jackson.annotation.JsonCreator;
//#JsonPOJOBuilder(buildMethodName = "build", withPrefix = "with")
public class ValueBuilder {
private int x;
private int y;
// can use #JsonCreator to use non-default ctor, inject values etc
public ValueBuilder() { }
// if name is "withXxx", works as is: otherwise use #JsonProperty("x") or #JsonSetter("x")!
public ValueBuilder withX(int x) {
this.x = x;
return this; // or, construct new instance, return that
}
public ValueBuilder withY(int y) {
this.y = y;
return this;
}
#JsonCreator
public Value build() {
return new Value(x, y);
}
}
The Start Class
public class Start {
public static void main(String[] args) throws IOException {
Value newValue = new ValueBuilder().withX(2).withY(4).build();
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(newValue);
System.out.println(jsonString);
}
}
You're only missing accessible getters for x and y in your Value class - the ObjectMapper requires access to those in order to serialize.
Add the following to your Value class definition:
public int getX() {
return x;
}
public int getY() {
return y;
}
No need for additional annotations in this context.
Your JSON will print out like:
{"x":2,"y":4}
You could also make the fields public to reach the same result, but that would defile proper encapsulation.
I am wondering why i have to deal with two types of arguments;that of a constructor and that of a method.For instance i have this simple class that adds two numbers
class Calc{
private int x = 6;
private int y;
private char z = 'z';
public int getx(){
return x;
}
public char selfrecur(){
return this.z;
}
public int add(int one,int two){
return one + two;
}
public static void main(String[] args) {
Calc gx = new Calc();
System.out.println(gx.x);
System.out.println(gx.add(44,3));
System.out.println(gx.selfrecur());
}
}
That works,and wow,wasn't that great.Now,i have this idea of having the constructor provide the arguments and the function's work will be to do the heavy computations.For instance in my class Kalc
class Kalc{
//** This example won't work **
private int x;
private int y;
private int z;
public Kalc(int v1,int v2,int v3){
this.x = v1;
this.y = v2;
this.z = v3;
}
public int add(){
return newObject.x + newObject.y + newObject.z;
//Gets the values of a new object and add them up
}
public int multiply(){
return newObject.x * newObject.y * newObject.z;
//Gets the values of a new object and multiply them
}
public static void main(String[] args) {
Kalc k = new Kalc(4,5,6);
System.out.println(k.add());
System.out.println(k.multiply());
}
}
I have been looking here http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html for clues but so far nothing.Is this even possible?.
Edit
class Kalc{
private int x;
private int y;
private int z;
public Kalc(int v1,int v2,int v3){
this.x = v1;
this.y = v2;
this.z = v3;
}
public int add(){
return this.x + this.y + this.z;
}
public static void main(String[] args) {
Kalc k = new Kalc(4,5,6);
System.out.println(k.add);
}
}
Error
C:\ja>javac Kalc.java
Kalc.java:17: error: cannot find symbol
System.out.println(k.add);
^
symbol: variable add
location: variable k of type Kalc
1 error
C:\ja>
Use this key word:
public int add(){
return this.x + this.y + this.z;
}
You can use this key word inside non-static methods too.
About your edit:
add is a function (and not a member) of class Kalc so you can call it as a function only:
System.out.println(k.add());
You can do the below
class Kalc{
private int x;
private int y;
private int z;
public Kalc(int v1,int v2,int v3)
{
this.x = v1;
this.y = v2;
this.z = v3;
}
public int add(){
return x+y+z;
}
public int multiply(){
return x*y*z;
}
public static void main(String[] args) {
Kalc k = new Kalc(4,5,6);
System.out.println(k.add());
System.out.println(k.multiply());
}
}
What is newObject?
You have instantiated an object with prescribed values. If you want to add them with an instance method, try this
return this.x + this.y + this.z;
I think you need to print :
System.out.println(k.add());
Instead of :
System.out.println(k.add);
as in the second case the compiler show k.add as add variable
but in the first case add() the compiler show add() as a function which you define in Kalc Class