I'm coding a little class hierarchy printing tool for easy show hierarchies of java classes.This is my current code:import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.PrintStream;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.List;import java.util.TreeMap;import javax.swing.JDialog;import jdk.nashorn.internal.runtime.PropertyMap; // since Java 8, just for testingimport com.sun.javafx.collections.TrackableObservableList;public class PrintClassHierarchy {    private static final String PADDING =         ;    private static final String PADDING_WITH_COLUMN =    |    ;    private static final String PADDING_WITH_ENTRY =    |--- ;    private static final String BASE_CLASS = Object.class.getName();    private TreeMap<String, List<String>> entries;    private boolean[] moreToCome;    public static void main(final String[] args) {        new PrintClassHierarchy().printHierarchy(            PrintStream.class,            FileOutputStream.class,            FileInputStream.class,            TrackableObservableList.class,            PropertyMap.class,            JDialog.class        );    }    public void printHierarchy(final Class<?>... clazzes) {        // clean values        entries = new TreeMap<>();        moreToCome = new boolean[99];        // get all entries of tree        traverseClasses(clazzes);        // print collected entries as ASCII tree        printHierarchy(BASE_CLASS, 0);    }    private void printHierarchy(final String node, final int level) {        for (int i = 1; i < level; i++) {            System.out.print(moreToCome[i - 1] ? PADDING_WITH_COLUMN : PADDING);        }        if (level > 0) {            System.out.print(PADDING_WITH_ENTRY);        }        System.out.println(node);        if (entries.containsKey(node)) {            final List<String> list = entries.get(node);            for (int i = 0; i < list.size(); i++) {                moreToCome[level] = (i < list.size() - 1);                printHierarchy(list.get(i), level + 1);            }        }    }    private void traverseClasses(final Class<?>... clazzes) {        Arrays.asList(clazzes).forEach(c -> traverseClasses(c, 0));    }    private void traverseClasses(final Class<?> clazz, final int level) {        final Class<?> superClazz = clazz.getSuperclass();        if (superClazz == null) {            return;        }        final String name = clazz.getName();        final String superName = superClazz.getName();        if (entries.containsKey(superName)) {            final List<String> list = entries.get(superName);            if (!list.contains(name)) {                list.add(name);                Collections.sort(list); // SortedList            }        } else {            entries.put(superName, new ArrayList<String>(Arrays.asList(name)));        }        traverseClasses(superClazz, level + 1);    }}This prints out:java.lang.Object   |--- java.awt.Component   |       |--- java.awt.Container   |               |--- java.awt.Window   |                       |--- java.awt.Dialog   |                               |--- javax.swing.JDialog   |--- java.io.InputStream   |       |--- java.io.FileInputStream   |--- java.io.OutputStream   |       |--- java.io.FileOutputStream   |       |--- java.io.FilterOutputStream   |               |--- java.io.PrintStream   |--- java.util.AbstractCollection   |       |--- java.util.AbstractList   |               |--- javafx.collections.ObservableListBase   |                       |--- javafx.collections.ModifiableObservableListBase   |                               |--- com.sun.javafx.collections.ObservableListWrapper   |                                       |--- com.sun.javafx.collections.TrackableObservableList   |--- jdk.nashorn.internal.runtime.PropertyMapThis output is already valid. I want to know, if this is a good approach to do the task, or if there is another (better) way to do this?I'm not sure, if the entries and moreToCome global variables are the way to go.Or if you have general improvements, please let me know!Edit 1:I reworked the code to find out the maximum level in hierarchy to discover how big the boolean array has to be. Also I reworked the method calls and put the traverseClasses into the constructor as recommended. Furthermore I renamed some variables to more descriptive names and added some comments. moreToCome is now moreClassesInHierarchy.Second approach:import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.PrintStream;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.List;import java.util.TreeMap;import javax.swing.JDialog;import jdk.nashorn.internal.runtime.PropertyMap; // since Java 8, just for testingimport com.sun.javafx.collections.TrackableObservableList;public class PrintClassHierarchy {    private static final String PADDING =         ;    private static final String PADDING_WITH_COLUMN =    |    ;    private static final String PADDING_WITH_ENTRY =    |--- ;    private static final String BASE_CLASS = Object.class.getName();    private final TreeMap<String, List<String>> subClazzEntries;    private final boolean[] moreClassesInHierarchy;    private int maxLevel = 0;    public static void main(final String[] args) {        new PrintClassHierarchy(            PrintStream.class,            FileOutputStream.class,            FileInputStream.class,            TrackableObservableList.class,            PropertyMap.class,            JDialog.class        ).printHierarchy();    }    public PrintClassHierarchy(final Class<?>... clazzes) {        subClazzEntries = new TreeMap<>();        // get all entries of tree        traverseClasses(clazzes);        // initialize array with size of maximum class hierarchy level        moreClassesInHierarchy = new boolean[maxLevel];    }    public void printHierarchy() {        // print collected entries as ASCII tree        printHierarchy(BASE_CLASS, 0);    }    private void printHierarchy(final String clazzName, final int level) {        for (int i = 1; i < level; i++) {            // The flag moreToCome holds an identifier, if there is another class            // on the specific value, that comes beneath the current class.            // So print either '|' or ' '.            System.out.print(moreClassesInHierarchy[i - 1] ? PADDING_WITH_COLUMN : PADDING);        }        if (level > 0) {            System.out.print(PADDING_WITH_ENTRY);        }        System.out.println(clazzName);        if (subClazzEntries.containsKey(clazzName)) {            final List<String> list = subClazzEntries.get(clazzName);            for (int i = 0; i < list.size(); i++) {                // if there is another class that comes beneath the next class,                // flag this level                moreClassesInHierarchy[level] = (i < list.size() - 1);                printHierarchy(list.get(i), level + 1);            }        }    }    private void traverseClasses(final Class<?>... clazzes) {        // do the traverseClasses on each provided class (possible since Java 8)        Arrays.asList(clazzes).forEach(c -> traverseClasses(c, 0));    }    private void traverseClasses(final Class<?> clazz, final int level) {        final Class<?> superClazz = clazz.getSuperclass();        if (level > maxLevel) {            // discover maximum level            maxLevel = level;        }        if (superClazz == null) {            // we arrived java.lang.Object            return;        }        final String name = clazz.getName();        final String superName = superClazz.getName();        if (subClazzEntries.containsKey(superName)) {            final List<String> list = subClazzEntries.get(superName);            if (!list.contains(name)) {                list.add(name);                Collections.sort(list); // SortedList            }        } else {            subClazzEntries.put(superName, new ArrayList<String>(Arrays.asList(name)));        }        traverseClasses(superClazz, level + 1);    }}Edit 2:Now I implemented the Stack solution from Uri Agassi in my code.This is much more cleaner, since I don't have to care about the Stack size and the current level. It just fits the requirement!Furthermore I got rid of the TreeMap since I don't really need a sorted map. Therefore Map (HashMap) remains.Third approach:import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.PrintStream;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Stack;import javax.swing.JDialog;import jdk.nashorn.internal.runtime.PropertyMap; // since Java 8, just for testingimport com.sun.javafx.collections.TrackableObservableList;public class PrintClassHierarchy {    private static final String PADDING =         ;    private static final String PADDING_WITH_COLUMN =    |    ;    private static final String PADDING_WITH_ENTRY =    |--- ;    private static final String BASE_CLASS = Object.class.getName();    private final Map<String, List<String>> subClazzEntries = new HashMap<>();    public static void main(final String[] args) {        new PrintClassHierarchy(            PrintStream.class,            FileOutputStream.class,            FileInputStream.class,            TrackableObservableList.class,            PropertyMap.class,            JDialog.class        ).printHierarchy();    }    public PrintClassHierarchy(final Class<?>... clazzes) {        // get all entries of tree        traverseClasses(clazzes);    }    public void printHierarchy() {        // print collected entries as ASCII tree        printHierarchy(BASE_CLASS, new Stack<Boolean>());    }    private void printHierarchy(final String clazzName, final Stack<Boolean> moreClassesInHierarchy) {        if (!moreClassesInHierarchy.empty()) {            for (final Boolean hasColumn : moreClassesInHierarchy.subList(0, moreClassesInHierarchy.size() - 1)) {                System.out.print(hasColumn.booleanValue() ? PADDING_WITH_COLUMN : PADDING);            }        }        if (!moreClassesInHierarchy.empty()) {            System.out.print(PADDING_WITH_ENTRY);        }        System.out.println(clazzName);        if (subClazzEntries.containsKey(clazzName)) {            final List<String> list = subClazzEntries.get(clazzName);            for (int i = 0; i < list.size(); i++) {                // if there is another class that comes beneath the next class, flag this level                moreClassesInHierarchy.push(new Boolean(i < list.size() - 1));                printHierarchy(list.get(i), moreClassesInHierarchy);                moreClassesInHierarchy.removeElementAt(moreClassesInHierarchy.size() - 1);            }        }    }    private void traverseClasses(final Class<?>... clazzes) {        // do the traverseClasses on each provided class (possible since Java 8)        Arrays.asList(clazzes).forEach(c -> traverseClasses(c, 0));    }    private void traverseClasses(final Class<?> clazz, final int level) {        final Class<?> superClazz = clazz.getSuperclass();        if (superClazz == null) {            // we arrived java.lang.Object            return;        }        final String name = clazz.getName();        final String superName = superClazz.getName();        if (subClazzEntries.containsKey(superName)) {            final List<String> list = subClazzEntries.get(superName);            if (!list.contains(name)) {                list.add(name);                Collections.sort(list); // SortedList            }        } else {            subClazzEntries.put(superName, new ArrayList<String>(Arrays.asList(name)));        }        traverseClasses(superClazz, level + 1);    }}
Class for printing class hierarchy as text
java;classes;tree;inheritance