public class BinaryTree<E> {
    
    // Data members/fields...just the root is needed
    protected Node<E> root;
   
    // Constructor(s)
    public BinaryTree() {
    root = null;
    } // BinaryTree()
   
    protected BinaryTree(Node<E> node) {
    this.root = node;
    } // BinaryTree(node)
   
    public BinaryTree(E data, BinaryTree<E> leftTree, BinaryTree<E> rightTree) {
    root = new Node<E>(data);
    if (leftTree != null) {
    root.left = leftTree.root;
    } else {
    root.left = null;
    }
   
    if (rightTree != null) {
    root.right = rightTree.root;
    } else {
    root.right = null;
    }
    } // BinaryTree(d, l, r)
   
    // Methods: Accessors
   
    public E getData() throws BinaryTreeException {
    if (root != null) {
    return root.data;
    } else {
    throw new BinaryTreeException("Trying to access data from empty tree.");
    }
    }
   
    public boolean isEmpty() {
    return root == null;
    }
   
    public BinaryTree<E> getLeftSubtree() {
    if (root != null && root.left != null) {
    return new BinaryTree<E>(root.left);
    } else {
    return new BinaryTree<E>(null);
    }
    } // getLeftSubtree()
   
    public BinaryTree<E> getRightSubtree() {
    if (root != null && root.right != null) {
    return new BinaryTree<E>(root.right);
    } else {
    return new BinaryTree<E>(null);
    }
    } // getRightSubtree()
   
    public boolean isLeaf() {
    return root == null || (root.left == null && root.right == null);
    } // isLeaf()
   
    public String toString() {
    StringBuilder sb = new StringBuilder();
    preOrderTraverse(root, 1, sb);
    return sb.toString();
    } // toString()
   
    // Traversals
    private void preOrderTraverse(Node<E> node, int depth, StringBuilder sb) {
    for (int i = 1; i < depth; i ++) {
    sb.append("  ");
    }
   
    if (node == null) {
    //sb.append("null\n");
    sb.append("");
    } else {
    sb.append(node.toString());
    sb.append("\n");
    preOrderTraverse(node.left, depth+1, sb);
    preOrderTraverse(node.right, depth+1, sb);
    } // preOrderTraverse()
    }
   
    // ===========================================================
    // Needs an inner class of nodes
    protected static class Node<E> {
    protected E data;
    protected Node<E> left, right;
 // Constructor
    public Node(E data) {
    this.data = data;
    left = right = null;
    }
 // Methods
    public String toString() {
    return data.toString();
    }
    } // Node<E> inner class
   
    @SuppressWarnings("serial")
    private static class BinaryTreeException extends Exception {
    BinaryTreeException(String message) {
    super(message);
    }
    } // end of inner class BinaryTreeException
} // BinaryTree<E> class