Enumerator now extends AutoCloseable. This will improve resource management when an Enumerable or Enumerator wraps a resource such as a file or database connection.
diff --git a/src/main/java/net/hydromatic/lambda/streams/MapStream.java b/src/main/java/net/hydromatic/lambda/streams/MapStream.java
index 690c8e3..867baa1 100644
--- a/src/main/java/net/hydromatic/lambda/streams/MapStream.java
+++ b/src/main/java/net/hydromatic/lambda/streams/MapStream.java
@@ -146,6 +146,10 @@
                 public void reset() {
                   enumerator.reset();
                 }
+
+                public void close() {
+                  enumerator.close();
+                }
               };
           return new Iterable<BiValue<K, V>>() {
             public Iterator<BiValue<K, V>> iterator() {
diff --git a/src/main/java/net/hydromatic/linq4j/CartesianProductEnumerator.java b/src/main/java/net/hydromatic/linq4j/CartesianProductEnumerator.java
index 74056fd..3734b5d 100644
--- a/src/main/java/net/hydromatic/linq4j/CartesianProductEnumerator.java
+++ b/src/main/java/net/hydromatic/linq4j/CartesianProductEnumerator.java
@@ -80,6 +80,26 @@
   public void reset() {
     first = true;
   }
+
+  public void close() {
+    // If there is one or more exceptions, carry on and close all enumerators,
+    // then throw the first.
+    Throwable rte = null;
+    for (Enumerator<T> enumerator : enumerators) {
+      try {
+        enumerator.close();
+      } catch (Throwable e) {
+        rte = e;
+      }
+    }
+    if (rte != null) {
+      if (rte instanceof Error) {
+        throw (Error) rte;
+      } else {
+        throw (RuntimeException) rte;
+      }
+    }
+  }
 }
 
 // End CartesianProductEnumerator.java
diff --git a/src/main/java/net/hydromatic/linq4j/EnumerableDefaults.java b/src/main/java/net/hydromatic/linq4j/EnumerableDefaults.java
index 976d99d..41bf134 100644
--- a/src/main/java/net/hydromatic/linq4j/EnumerableDefaults.java
+++ b/src/main/java/net/hydromatic/linq4j/EnumerableDefaults.java
@@ -25,7 +25,7 @@
 import static net.hydromatic.linq4j.function.Functions.adapt;
 
 /**
- * @author jhyde
+ * Default implementations of methods in the {@link Enumerable} interface.
  */
 public abstract class EnumerableDefaults {
 
@@ -648,6 +648,9 @@
           public void reset() {
             entries.reset();
           }
+
+          public void close() {
+          }
         };
       }
     };
@@ -785,6 +788,7 @@
                   || !outerEnumerable.any()) {
                 productEnumerator = Linq4j.emptyEnumerator();
               } else {
+                //noinspection unchecked
                 productEnumerator = Linq4j.product(
                     Arrays.asList(
                         (Enumerator<Object>) (Enumerator)
@@ -798,6 +802,9 @@
           public void reset() {
             entries.reset();
           }
+
+          public void close() {
+          }
         };
       }
     };
@@ -1227,6 +1234,10 @@
           public void reset() {
             enumerator.reset();
           }
+
+          public void close() {
+            enumerator.close();
+          }
         };
       }
     };
@@ -1261,6 +1272,10 @@
           public void reset() {
             enumerator.reset();
           }
+
+          public void close() {
+            enumerator.close();
+          }
         };
       }
     };
@@ -1301,6 +1316,11 @@
             sourceEnumerator.reset();
             resultEnumerator = Linq4j.emptyEnumerator();
           }
+
+          public void close() {
+            sourceEnumerator.close();
+            resultEnumerator.close();
+          }
         };
       }
     };
@@ -1853,6 +1873,10 @@
           public void reset() {
             enumerator.reset();
           }
+
+          public void close() {
+            enumerator.close();
+          }
         };
       }
     };
@@ -1890,6 +1914,10 @@
             enumerator.reset();
             n = -1;
           }
+
+          public void close() {
+            enumerator.close();
+          }
         };
       }
     };
@@ -1958,6 +1986,10 @@
       done = false;
       n = -1;
     }
+
+    public void close() {
+      enumerator.close();
+    }
   }
 
   static class SkipWhileEnumerator<TSource> implements Enumerator<TSource> {
@@ -1997,6 +2029,10 @@
       started = false;
       n = -1;
     }
+
+    public void close() {
+      enumerator.close();
+    }
   }
 
   static class CastingEnumerator<T> implements Enumerator<T> {
@@ -2019,6 +2055,10 @@
     public void reset() {
       enumerator.reset();
     }
+
+    public void close() {
+      enumerator.close();
+    }
   }
 
   private static class Wrapped<T> {
diff --git a/src/main/java/net/hydromatic/linq4j/Enumerator.java b/src/main/java/net/hydromatic/linq4j/Enumerator.java
index f8b82c1..c9b8ce5 100644
--- a/src/main/java/net/hydromatic/linq4j/Enumerator.java
+++ b/src/main/java/net/hydromatic/linq4j/Enumerator.java
@@ -27,7 +27,7 @@
  *
  * @param <T> element type
  */
-public interface Enumerator<T> {
+public interface Enumerator<T> extends AutoCloseable {
   /**
    * Gets the current element in the collection.
    *
@@ -117,6 +117,14 @@
    * {@link #current()}.</p>
    */
   void reset();
+
+  /**
+   * Closes this enumerable and releases resources.
+   *
+   * <p>This method is idempotent. Calling it multiple times has the same effect
+   * as calling it once.</p>
+   */
+  void close();
 }
 
 // End Enumerator.java
diff --git a/src/main/java/net/hydromatic/linq4j/Linq4j.java b/src/main/java/net/hydromatic/linq4j/Linq4j.java
index efc4de4..965d5e8 100644
--- a/src/main/java/net/hydromatic/linq4j/Linq4j.java
+++ b/src/main/java/net/hydromatic/linq4j/Linq4j.java
@@ -47,6 +47,9 @@
 
         public void reset() {
         }
+
+        public void close() {
+        }
       };
 
   public static final Enumerable<?> EMPTY_ENUMERABLE =
@@ -372,6 +375,20 @@
       iterator = iterable.iterator();
       current = (T) DUMMY;
     }
+
+    public void close() {
+      final Iterator<T> iterator = this.iterator;
+      this.iterator = null;
+      if (iterator instanceof AutoCloseable) {
+        try {
+          ((AutoCloseable) iterator).close();
+        } catch (RuntimeException e) {
+          throw e;
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    }
   }
 
   static class CompositeEnumerable<E> extends AbstractEnumerable<E> {
@@ -383,6 +400,7 @@
 
     public Enumerator<E> enumerator() {
       return new Enumerator<E>() {
+        // Never null.
         Enumerator<E> current = emptyEnumerator();
 
         public E current() {
@@ -394,7 +412,9 @@
             if (current.moveNext()) {
               return true;
             }
+            current.close();
             if (!enumerableEnumerator.moveNext()) {
+              current = emptyEnumerator();
               return false;
             }
             current = enumerableEnumerator.current().enumerator();
@@ -405,6 +425,11 @@
           enumerableEnumerator.reset();
           current = emptyEnumerator();
         }
+
+        public void close() {
+          current.close();
+          current = emptyEnumerator();
+        }
       };
     }
   }
diff --git a/src/main/java/net/hydromatic/linq4j/LookupImpl.java b/src/main/java/net/hydromatic/linq4j/LookupImpl.java
index f83b054..9be21d6 100644
--- a/src/main/java/net/hydromatic/linq4j/LookupImpl.java
+++ b/src/main/java/net/hydromatic/linq4j/LookupImpl.java
@@ -55,6 +55,10 @@
       public void reset() {
         enumerator.reset();
       }
+
+      public void close() {
+        enumerator.close();
+      }
     };
   }
 
@@ -182,6 +186,10 @@
           public void reset() {
             groupingEnumerator.reset();
           }
+
+          public void close() {
+            groupingEnumerator.close();
+          }
         };
       }
     };
@@ -208,7 +216,9 @@
               if (enumerator.moveNext()) {
                 return true;
               }
+              enumerator.close();
               if (!listEnumerator.moveNext()) {
+                enumerator = Linq4j.emptyEnumerator();
                 return false;
               }
               enumerator = listEnumerator.current().enumerator();
@@ -219,6 +229,10 @@
             listEnumerator.reset();
             enumerator = Linq4j.emptyEnumerator();
           }
+
+          public void close() {
+            enumerator.close();
+          }
         };
       }
     };