user840718 user840718 - 12 days ago 7
Java Question

How to deal with recursion in toString Java method?

My program is structured as follows: a class that represents an atomic concept which is essentially a String and another class that is made of a list of general concepts. Both classes extends the class Concept that is an abstract class, this means that in the list I could have both atomic concepts and intersection of concepts arbitrary nested.
Each concept, atomic or composed, is printed out by toString method.
Roughly speaking, this is based on this context-free grammar:

C : atom | (C and)+ C


Where C is the abstract class Concept, atom is AtomicConcept and (C and)+ C is Intersection.

This is the AtomicConcept class:

public class AtomicConcept extends Concept{

private String atomicConceptName;

public AtomicConcept(String c) {
this.atomicConceptName = c;
}

@Override
public String toString() {
return atomicConceptName;
}


}

This is che ConceptIntersection class:

import java.util.List;

public class ConceptIntersection extends Concept{

private List<Concept> list;

public ConceptIntersection(List<Concept> l) throws Exception {
if(l.size()>1)
{
this.list = l;
}
else
{
throw new Exception("Intersection needs at least two concepts!");
}
}

public String toString()
{
return Utils.conceptIntersection + Utils.lparen + Utils.splitConcepts(list) + Utils.rparen;

}

}


As you can see in toString function, I also created a method called splitConcepts that takes in input a list of general concepts and returns one string made of each concept separated by comma.

public static String splitConcepts(List<Concept> list)
{
String result = "";
for (Concept item : list) {
System.out.println(item);
result += item.toString() + comma;

}
result = result.substring(0, result.length() - 1);
return result;
}


Where is the problem?
I have trouble with this function because when I call a nested intersection in another one, this function never ends!

One example:

public static void main(String[] args) throws DLRException {
// TODO Auto-generated method stub

AtomicConcept atom = new AtomicConcept("one");
AtomicConcept at = new AtomicConcept("two");
List<Concept> list = new LinkedList<Concept>();
list.add(at);
list.add(atom);
DLRConceptIntersection intersection = new DLRConceptIntersection(list);
System.out.println(intersection); // works fine
list.add(intersection);
DLRConceptIntersection intersection2 = new DLRConceptIntersection(list);
System.out.println(intersection2); //loop never ends!
}


Is a correct approach to fix this problem?

Answer

You have a circular reference :

DLRConceptIntersection intersection = new DLRConceptIntersection(list);
list.add(intersection);

This causes the intersection's List to contain a reference to the same instance referred by intersection, which is why toString() run into infinite recursion.

I'm assuming you didn't intend intersection and intersection2 to share the same List.

You can avoid it if you create a copy of the List in the DLRConceptIntersection constructor:

public ConceptIntersection(List<Concept> l) throws Exception {
    if(l.size()>1) {
        this.list = new ArrayList<>(l);
    } else {
        throw new Exception("Intersection needs at least two concepts!");
    }
}