Reflecting changes to a variable in the caller in Java - java

I have a function that is supposed to return a place object, but I also need to test on whether something evaluates to false, and in addition the caller needs to know both of those pieces of information. I have the return type as Place but in Java there are no reference parameters, so if the following if-condition is true, I would like for some way to reflect that in the caller so I can check it, but I can't have more than one return type so I'm stuck as to what to do. My best shot was returning null but I just get the feeling that this is bad programming.
if ( directions.get(i).isLocked() )
Below is the complete function:
Place followDirection(String dir, boolean isLocked) {
dir = dir.toLowerCase(); // make sure the string is lowercase for comparisons
int i = 0;
for ( i = 0; i < directions.size(); i++ ) { // loop until we find a match, remember that if it's locked then we cnanot go in there
if ( directions.get(i).getDirection().equals(dir) ) {
if ( directions.get(i).isLocked() ) {
System.out.println("This room is locked, sorry");
}
else {
return directions.get(i).getToPlace(); // this means we found a match, return the destination
}
}
}
Place p = null;
return p;
}

Technically, there are two options if you don't want to return null (which does not seem bad by the way):
return an object that contains both return values
Pass in a mutable object as parameter.
The second option also feels somewhat dirty.

java is a call by value language but it is a little bit complicated. this language pass the pointers as a value and if you dont change the pointer you can change the object that pass to your function. for example if you pass an complex object to a function and in that function you change the value of a parameter of that object, the caller can see it, in your code you can pass an object than contains dir and isLocked , so you can change those parameters.
Place followDirection(MyObject obj) {
obj.dir = obj.dir.toLowerCase(); // make sure the string is lowercase for comparisons
int i = 0;
for ( i = 0; i < directions.size(); i++ ) { // loop until we find a match, remember that if it's locked then we cnanot go in there
if ( directions.get(i).getDirection().equals(obj.dir) ) {
if ( directions.get(i).isLocked() ) {
System.out.println("This room is locked, sorry");
}
else {
return directions.get(i).getToPlace(); // this means we found a match, return the destination
}
}
}
Place p = null;
return p;
}
MyObject contains :
String dir, boolean isLocked

Related

ANTLR3 parser fails when using memoize

Context
I'm making some changes to a grammar parser in ANTLR3 to recognize certain URLs that I consider valid (for example, if it begins with www or http, or if it ends with .com)
The main rule I have right now is something like this:
url returns [UrlToken token]
: scheme_full? subdomain? middle_url valid_domain_end? port? path_full?
{isValidUrl($scheme_full.text, $subdomain.text, $valid_domain_end.text, $path_full.text, $middle_url.text)}?
{$token = urlTokenFor(
StringUtils.defaultString($scheme_full.text),
StringUtils.defaultString($subdomain.text) + StringUtils.defaultString($middle_url.text) + StringUtils.defaultString($valid_domain_end.text),
StringUtils.defaultString($path_full.text),
StringUtils.defaultString($port.text),
StringUtils.defaultString(null) ); }
;
And the code of isValidUrl is:
private boolean isValidUrl(String scheme, String subdomain, String valid_end, String path, String middle) {
if (scheme != null || subdomain != null || valid_end != null) return true;
if (path != null && middle.contains(".")) return true;
return false;
}
The main idea is that I let the sub-parts match optionally, then check if it's a valid URL using some Java function, and then (in case it is valid) it returns a UrlToken.
I did it like this because the logic to check if a URL is valid was too complicated to leave it to the parser, generated a lot of ambiguity which I wasn't able to fix.
Now, this is currently working fine for me, and is matching the URLs that I want.
The problem is that before the changes I was using the memoize option, and I had to deactivate it to make it work. Since performance is important I'd like to be able to keep memoization enabled.
Why is it failing when using memoize?
I did some debugging on the generated Java code.
This is a piece of the generated code for the url rule:
// grammars/Url.g:94:5: ( scheme_full )?
int alt3=2;
int LA3_0 = input.LA(1);
if ( (LA3_0==LETTERS) ) {
int LA3_1 = input.LA(2);
if ( (LA3_1==SYMBOL) ) {
int LA3_3 = input.LA(3);
if ( (LA3_3==SYMBOL) ) {
int LA3_4 = input.LA(4);
// Inside synpred3_Url(), scheme_full() is executed
if ( ((synpred3_Url()&&(matchesScheme(input.LT(1))))) ) {
alt3=1;
}
}
}
}
switch (alt3) {
case 1 :
// grammars/Url.g:0:0: scheme_full
{
pushFollow(FOLLOW_scheme_full_in_url100);
scheme_full2=scheme_full();
state._fsp--;
if (state.failed) return retval;
}
break;
}
And this is the generated code for the scheme_full as an example:
public final Url.scheme_full_return scheme_full() throws RecognitionException {
Url.scheme_full_return retval = new Url.scheme_full_return();
retval.start = input.LT(1);
int scheme_full_StartIndex = input.index();
try {
if ( state.backtracking>0 && alreadyParsedRule(input, 13) ) { return retval; }
// grammars/Url.g:149:3: ( scheme scheme_separator )
// grammars/Url.g:149:5: scheme scheme_separator
{
pushFollow(FOLLOW_scheme_in_scheme_full374);
scheme();
state._fsp--;
if (state.failed) return retval;
pushFollow(FOLLOW_scheme_separator_in_scheme_full376);
scheme_separator();
state._fsp--;
if (state.failed) return retval;
}
retval.stop = input.LT(-1);
}
catch (RecognitionException re) {
reportError(re);
recover(input,re);
}
finally {
if ( state.backtracking>0 ) { memoize(input, 13, scheme_full_StartIndex); }
}
return retval;
}
This are the conclusions I've come to so far:
Each rule becomes a Java function, each one is executed twice,
the first one in the form of a backtracking to "predict" if the term will be used,
and the second one when it's actually matching.
The return values of the terms such as scheme_full, subdomain, etc. are of the type ParserRuleReturnScope, which contains start and stop tokens.
When memoize is set to true, the first time the terms are executed if the result is successful, it is cached, so that the second time it's gonna execute it doesn't need to do all over again. When the first time is successful (before putting the result in cache) the result (retval) has both start and end tokens properly set.
The problem is that the second time it is executed, and uses the cached result, the stop token comes in null (although the first execution was successful). It can be seen in the scheme_full code, when retval is returned it doesn't have the stop token set yet.
This last thing becomes a problem because when executing the predicate (the isValidUrl) it uses the text attribute of the term, using $scheme_full.text for example. And because the end token is in null, calling the text attribute to the scope returns a null string, and so my validation fails, even though the match was successful.
This whole behavior doesn't happen when memoize is set to false.
Any idea how can I solve this?

Implementing an equals() method to compare contents of two 'bag' objects

I am working on a school assignment. The objective is to practice GUI's, clone() methods, and using/ modifying existing code. I am trying to write an equals method in the way the instructor desires-- by using a clone of the object, removing items from the bag (returns boolean based on success or failure to remove).
The bag is represented in an array, and should return true in cases such as {1,2,3} and {3,2,1}, ie order does not matter, only the number of each number present in the arrays.
Here is the issue
It works in most cases, however there is a bug in cases where the bags contain numbers as such: {1,1,2} and {1,2,2} and other similar iterations. It is returning true instead of false.
I believe it has something to do with the remove() method we are supposed to use. If i understand it correctly, it is supposed to put the value at the 'end' of the array and decrease the manyItems counter (this is a variable for number of items in the array, because array.length is by default in the constructor 10.)
The code is largely written by another person. We had to import the existing files and write new methods to complete the task we were given. I have all the GUI part done so i will not include that class, only the used methods in the IntArrayBag class.
A second pair of eyes would be helpful. Thanks.
public class IntArrayBag implements Cloneable
{
// Invariant of the IntArrayBag class:
// 1. The number of elements in the bag is in the instance variable
// manyItems, which is no more than data.length.
// 2. For an empty bag, we do not care what is stored in any of data;
// for a non-empty bag, the elements in the bag are stored in data[0]
// through data[manyItems-1], and we don�t care what�s in the
// rest of data.
private int[ ] data;
private int manyItems;
public IntArrayBag( )
{
final int INITIAL_CAPACITY = 10;
manyItems = 0;
data = new int[INITIAL_CAPACITY];
}
public IntArrayBag clone( )
{ // Clone an IntArrayBag object.
IntArrayBag answer;
try
{
answer = (IntArrayBag) super.clone( );
}
catch (CloneNotSupportedException e)
{ // This exception should not occur. But if it does, it would probably
// indicate a programming error that made super.clone unavailable.
// The most common error would be forgetting the "Implements Cloneable"
// clause at the start of this class.
throw new RuntimeException
("This class does not implement Cloneable");
}
answer.data = data.clone( );
return answer;
}
public int size( )
{
return manyItems;
}
public boolean remove(int target)
{
int index; // The location of target in the data array.
// First, set index to the location of target in the data array,
// which could be as small as 0 or as large as manyItems-1; If target
// is not in the array, then index will be set equal to manyItems;
for (index = 0; (index < manyItems) && (target != data[index]); index++)
// No work is needed in the body of this for-loop.
;
if (index == manyItems)
// The target was not found, so nothing is removed.
return false;
else
{ // The target was found at data[index].
// So reduce manyItems by 1 and copy the last element onto data[index].
manyItems--;
data[index] = data[manyItems];
return true;
}
}
//I added extra variables that are not needed to try to increase readability,
//as well as when i was trying to debug the code originally
public boolean equals(Object obj){
if (obj instanceof IntArrayBag){
IntArrayBag canidate = (IntArrayBag) obj; // i know this can be changed, this was required
IntArrayBag canidateTest = (IntArrayBag) canidate.clone(); //this was created
//as a clone because it was otherwise referring to the same memory address
//this caused items to be removed from bags when testing for equality
IntArrayBag test = (IntArrayBag) this.clone();
//fast check to see if the two objects have the same number of items,
//if they dont will return false and skip the item by item checking
if (test.size() != canidateTest.size())
return false;
//the loop will go through every element in the test bag it will
//then remove the value that is present at the first index of the test bag
for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
int check = test.data[i];
//remove() returns a boolean so if the value is not present in each bag
//then the conditional will be met and the method will return false
boolean test1 = test.remove(check);
boolean test2 = canidateTest.remove(check);
if (test1 != test2)
return false;
}//end for loop
// if the loop goes through every element
//and finds every value was true it will return true
return true;
}//end if
else
return false;
}//end equals
}
I cannot see the big picture, as I havent coded GUIs in Java before, however, as far as comparing 2 int[] arrays, I would sort the arrays before the comparison. This will allow you to eliminate problem cases like the one you stated ( if sorting is possible), then apply something like:
while(array_1[index]==array_2[index] && index<array_1.length)
{index++;}
and find where did the loop break by checking the final value of index
Is it explicitly stated to use clone? You can achieve it easily by overriding the hashCode() for this Object.
You can override the hashCode() for this object as follows:
#Override
public int hashCode() {
final int prime = 5;
int result = 1;
/* Sort Array */
Arrays.sort(this.data);
/* Calculate Hash */
for(int d : this.data) {
result = prime * result + d;
}
/* Return Result */
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || this.getClass() != obj.getClass()){
return false;
}
return false;
}
If you want to continue using your implementation for equals to compare test and CandidateTest then also you can compute unique hashes and make decision based on the results.
Here is the code snippet:
/* Assuming that you have put size comparison logic on top
and the two objects are of same size */
final int prime = 31;
int testResult = 1;
int candidateTestResult = 1;
for(int i = 0; i < test.size(); i++) {
testResult = prime * testResult + test.data[i];
candidateTestResult = prime * candidateTestResult + candidateTest.data[i];
}
/* Return Result */
return testResult == candidateTestResult;
I believe the problem is in this line:
for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
The problem here is that test and canidateTest are the clones that you made, and you are removing elements from those bags. And any time you remove an element from the bag, the size will decrease (because you decrease manyItems, and size() returns manyItems). This means you're only going to go through half the array. Suppose the original size is 4. Then, the first time through the loop, i==0 and test.size()==4; the second time, i==0 and test.size()==3; the third time, i==2 and test.size()==2, and you exit the loop. So you don't look at all 4 elements--you only look at 2.
You'll need to decide: do you want to go through the elements of the original array, or the elements of the clone? If you go through the elements of the clone, you actually never need to increment i. You can always look at test.data[0], since once you look at it, you remove it, so you know test.data[0] will be replaced with something else. In fact, you don't need i at all. Just loop until the bag size is 0, or until you determine that the bags aren't equal. On the other hand, if you go through the elements of this.data (i.e. look at this.data[i] or just data[i]), then make sure i goes all the way up to this.size().
(One more small point: the correct spelling is "candidate".)
Maybe you should try SET interface
view this in detail :http://www.tutorialspoint.com/java/java_set_interface.htm
A set object cannot contains duplicate elements, so it's suitable for your assignment than build your own class.
For example:[1,1,2] and [1,2,2]
you can use this to test whether they are equal
arr1 = {1,1,2}
arr2 = {1,2,2}
Set<Integer> set = new HashSet<Integer>();
for(int i : arr1){//build set of arr1
if(set.contains(i)==false){
set.add(i)
}
}
for(int i:arr2){
if(set.contains(i)==false){
System.out.println('not equal');
break;
}
}
Hope this is helpful.

Binary Tree is a BST - Why one works and the other doesn't

I ma trying to check if a given Binary Tree is a Binary Search Tree. I am using in order traversal to do so. The idea is while traversing the tree in in order fashion, at each node check if the node value is greater tha the value of the previous noe visited. If not then then it is not a BST.
The question I have is why he first two work and not the third one :
// This works - Implementation 1
--------------------------------
class PrevWrapper
{
int data = Integer.MIN_VALUE;
}
public boolean isBST()
{
return isBST(root, new PrevWrapper());
}
private boolean isBST(Node node, PrevWrapper previousElement)
{
if ( node == null )
{
return true;
}
if ( !isBST(node.left, previousElement) )
{
return false;
}
if ( previousElement.data > node.item )
{
return false;
}
previousElement.data = node.item;
return isBST(node.right, previousElement);
}
// This works - Implementation 2
--------------------------------
static int lastValue = Integer.MIN_VALUE;
static boolean isBST(Node root)
{
if ( root == null )
{
return true;
}
if ( ! isBST(root.left) )
{
return false;
}
if ( root.item < lastValue )
{
return false;
}
lastValue = root.item;
return isBST(root.right);
}
// This does not work - Implementation 3
--------------------------------
private boolean isBST(Node node, Integer previousElement)
{
if ( node == null )
{
return true;
}
if ( !isBST(node.left, previousElement) )
{
return false;
}
if ( previousElement > node.item )
{
return false;
}
previousElement = node.item;
return isBST(node.right, previousElement);
}
Please explain. Wh can't I pass an Integer on function call stake that will maintain state ? or is it something that I am doing wrong with the implementation.
Although Integer is a wrapper class for integer, it is immutable. So once set, any edits will only create new objects of the kind, just like for Strings. So although implementation 3 tries to change the value of previousElement in the following line and hopes it will pass through to other recursive calls, it doesn't happen because of the way the Integer class works.
previousElement = node.item;
However Implementation 1, where you create a wrapper for the integer, it will maintain state because the class is passed by reference in subsequent recursive calls.
In the latest implementation, this piece of code is not doing what you expect it to:
if ( previousElement > node.item )
{
return false;
}
previousElement here should have the value of the rightmost leaf node of the left subtree, but instead it has the value of the parent node.
If you pass an Integer as an argument to the next recursive call of isBST, it becomes a local variable of that method, and any assignment done to it will not be seen by the caller of the recursive method when it returns.
This behavior is caused by Java being a pass by value language. When you pass a reference type to a method, that method gets a local copy of that reference. It can only change the state of the instance referred by that reference via methods that change its state (assuming it's mutable). That's what you do in the version that has a PrevWrapper parameter.

Searching an ArrayList

I currently have 3 classes, a main class containing a GUI, in which i'm calling this method, a customer class containing the data, and a customerList class which gathers the data from the customer class, puts it into an array list, and also contains the search arraylist method.
I'm trying to implement a search method which can be called from my main class on an action event handler. I'm having a few problems though.
Whenever I run the method, the " System.out.println(customer.returnFamilyName());" line always displays the first familyname in my arraylist.
Don't hesitate to ask for more information, I'm not sure how well i've explained this.
Here is my method:
public void searchCustomer(String familyName) {
int index = 0;
boolean found = false;
customer customer;
while(index < CustomerList.size() && !found) {
customer = CustomerList.get(index);
if(customer.returnFamilyName().equalsIgnoreCase(familyName)) {
found = true;
break;
}
if(found == true) {
;
}
System.out.println(customer.returnFamilyName());
index++;
return;
}
}
It's not clear from your question what the intended behaivor actually is. Besides that, what is this ?
if (found == true);
Presumably you meant :
if (found) {
System.out.println...
}
But what if the same last name occurs twice in your list? Also why aren't using a Map instead of a List? Lookup will go from being O(n) to O(1)
Drop the ; in if (found == true); because that reads as: if this condition is true, do notihng and use braces always:
if (found == true) {
System.out.println(customer.returnFamilyName());
}
Also, include the increment inside the while loop, otherwise you are not really iterating anything.
This code seems to work because your first element happens to coincide with the searched element, try with a different one and you'll end up in a infinite loop.
Try with a version like this:
public void searchCustomer( String familyName ) {
for ( customer current : CustomerList ) {
if ( current.returnFamilyName().equalsIgnoreCase( familyName )) {
System.out.println( current.returnFamilyName() );
break;
}
}
}
Some additional remarks:
In Java clases should start with uppercase, so the class name should be declared as Customer instead of customer and variables start with lowercase, hence CustomerList should be customerList. Methods may avoid the return part and be named with a get
Also, search methods should better return the found value instead of printing it, so your final version could look like this:
public Customer searchCustomer( String familyName ) {
for ( Customer current : customerList ) {
if ( current.getFamilyName().equalsIgnoreCase( familyName ) ) {
return current;
}
}
return null;
}
You never increment index.
The code should be:
public void searchCustomer(String familyName) {
for (customer customer : CustomerList) {
if (customer.returnFamilyName().equalsIgnoreCase(familyName)) {
System.out.println(customer.returnFamilyName());
break;
}
}
}
Also, the 'customer' class should be called 'Customer' as class names should start with a capital, 'returnFamilyName' should be 'getFamilyName' as accessor methods by convention are named 'get' + the field name and 'CustomerList' should be 'customerList' as field names are supposed to start with a lowercase letter.
I would suggest try this:
System.out.println(customer.returnFamilyName());
index++;
if(found == true) { return;}
Don't forget to increment the while loop or it has the potential to run indefinitely.
You can elect to use what is known as an "enhanced for-loop", which allows you to eschew the need to increment values over CustomerList entirely. You have an object customer, so we can use that as follows:
for (customer cus: CustomerList) {
if(cus.returnFamilyName().equalsIgnoreCase(familyName)) {
System.out.println(cus.returnFamilyName());
return;
}
}
If you elect to stick with your original code (which is fine), then observe the changes in your code below.
while(index < CustomerList.size()) {
customer = CustomerList.get(index);
if (customer.returnFamilyName().equalsIgnoreCase(familyName)) {
System.out.println(customer.returnFamilyName());
break;
} else {
index++;
}
}

Search an attribute inside a Vector on Java

I've a Vector of objects, and have to search inside for a random attribute of those objects (For example, a Plane class, a Vector containing Plane; and I've to search sometimes for destination, and others to pilotName).
I know I can traverse the Vector using an Iterator, but I've got stuck at how do I change the comparison made between a String and the attribute on the object. I thought of using switch, but a another opinion would be cool.
Update 1:
The code I've written is something like this (Java n00b alert!):
public int search(String whatSearch, String query){
int place = -1;
boolean found = false;
for ( Iterator<Plane> iteraPlane = this.planes.iterator(); iteraPlane.hasNext() && found == false; ) {
Plane temp = (Plane) iteraPlane.next();
/* Here is where I have to search for one of many attributes (delimited by whatSearch */
}
return place;
}
Seems I've to stick to linear search (and that's a price I've able to pay). Anyway, I was thinking if Java had something like variable variable name (ouch!)
I assume that your problem is that you want to have a method that searches for a result based on some property of the collection type. Java is weak on this because it is best expressed in a language which has closures. What you need is something like:
public interface Predicate<T> {
public boolean evaluate(T t);
}
And then your search method looks like:
public static <T> T findFirst(List<T> l, Predicate<T> p) { //use List, not Vector
for (T t : l) { if (p.evaluate(t)) return t; }
return null;
}
Then anyone can use this general-purpose search method. For example, to search for an number in a vector of Integers:
List<Integer> is = ...
findFirst(is, new Predicate<Integer> {
public boolean evaluate(Integer i) { return i % 2 == 0; }
});
But you could implement the predicate in any way you want; for any arbitrary search
Use Collections.binarySearch and provide a Comparator.
EDIT: This assumes that the Vector is sorted. Otherwise, one has to do a linear search.
the equals() method is the best option. For these iterations you could do something like this:
for (Plane plane: planes) {
if ("JFK".equals(plane.getDestination())) {
// do your work in here;
}
}
or you could override the equals() method within Plane to see if the String passed in matches your destination (or pilot). this will allow you to use the indexOf(Object) and indexOf(Object, index) methods on Vector to return you the index(es) of the object(s). Once you have that, you could use Vector.get(index) to return to Object for you.
in Plane.java:
public boolean equals(Object o) {
return o.equals(getDestination()) ||
o.equals(getPilot()) ||
super.equals(o);
}
there is more work to be done with this option, as you will need to override hashCode() as well (see documentation).
See #oxbow_lakes above -- I think what you want isn't to pass a String as whatSearch, it's to pass a little snippet of code that knows how to get the property you're interested in. For a less general version:
public static interface PlaneMatcher {
boolean matches(Plane plane, String query);
}
public int search(PlaneMatcher matcher, String query){
int place = -1;
boolean found = false;
for ( Iterator<Plane> iteraPlane = this.planes.iterator(); iteraPlane.hasNext() && found == false; ) {
Plane temp = (Plane) iteraPlane.next();
if (matcher.matches(temp, query) {
found = true;
}
place++;
}
return place;
}
...
// example
int pilotNameIndex = search(new PlaneMatcher() {
boolean matches(Plane plane, String query) {
// note: assumes query non-null; you probably want to check that earlier
return query.equals(plane.getPilotName());
}
}, "Orville Wright");
(By the way, if it's the index you're interested in rather than the Plane itself, I wouldn't bother with an Iterator -- just use an old-fashioned for (int i = 0; i < planes.size(); i++) loop, and when you have a match, return i.)
Now, the tricky bit here is if what you have to search for is really identified by arbitrary strings at run-time. If that's the case, I can suggest two alternatives:
Don't store these values as object fields -- plane.pilotName, plane.destination -- at all. Just have a Map<String, String> (or better yet, a Map<Field, String> where Field is an Enum of all the valid fields) called something like plane.metadata.
Store them as object fields, but prepopulate a map from the field names to PlaneMatcher instances as described above.
For instance:
private static final Map<String, PlaneMatcher> MATCHERS = Collections.unmodifiableMap(new HashMap<String, PlaneMatcher>() {{
put("pilotName", new PlaneMatcher() {
boolean matches(Plane plane, String query) {
return query.equals(plane.getPilotName());
});
...
put("destination", new PlaneMatcher() {
boolean matches(Plane plane, String query) {
return query.equals(plane.getDestination());
});
}}
...
public int search(String whatSearch, String query){
PlaneMatcher matcher = MATCHERS.get(whatSearch);
int place = -1;
boolean found = false;
for ( Iterator<Plane> iteraPlane = this.planes.iterator(); iteraPlane.hasNext() && found == false; ) {
Plane temp = (Plane) iteraPlane.next();
if (matcher.matches(temp, query) {
found = true;
}
place++;
}
return place;
}
Oh, and you might be tempted to use reflection. Don't. :)
A simple way is to pass a comparison function to your search routine. Or, if you need more speed, use generics.

Categories