Merge branch 'master' of https://gitbox.apache.org/repos/asf/commons-csv
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a770e57..77b545b 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -39,6 +39,7 @@
   </properties>

   <body>

     <release version="1.9" date="2020-MM-DD" description="Feature and bug fix release (Java 8)">

+      <!-- FIX -->

       <action                 type="add" dev="ggregory" due-to="dota17">Add test cases for CSVRecord with get(Enum) and toString. #54.</action>

       <action                 type="update" dev="ggregory" due-to="Amey Jadiye">Replace FindBugs with SpotBugs #56.</action>

       <action                 type="update" dev="ggregory" due-to="Chen">Javadoc typo in CSVFormat let's -> lets #57.</action>

@@ -57,6 +58,8 @@
       <action issue="CSV-267" type="fix" dev="ggregory" due-to="Arturo Bernal">Minor improvements #126, #127.</action>

       <action issue="CSV-123" type="fix" dev="ggregory" due-to="Emmanuel Bourg, Benedikt Ritter, shivakrishnaah, Gary Gregory">Add possibility to use ResultSet header meta data as CSV header #11.</action>

       <!-- ADD -->

+      <action issue="CSV-275" type="add" dev="ggregory" due-to="Michael Wyraz, Gary Gregory">Make CSVRecord#toList() public.</action>

+      <action                 type="add" dev="ggregory" due-to="Gary Gregory">Add CSVRecord#toStream().</action>

       <!-- UPDATE -->

       <action                 type="update" dev="ggregory" due-to="Gary Gregory">Update org.junit.jupiter:junit-jupiter from 5.6.0 to 5.7.0, #84 #109</action>

       <action                 type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Apache Commons Lang 3.9 to 3.12.0.</action>

diff --git a/src/main/java/org/apache/commons/csv/CSVRecord.java b/src/main/java/org/apache/commons/csv/CSVRecord.java
index fcc038e..ced1a9a 100644
--- a/src/main/java/org/apache/commons/csv/CSVRecord.java
+++ b/src/main/java/org/apache/commons/csv/CSVRecord.java
@@ -24,6 +24,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.stream.Stream;
 import java.util.Objects;
 
 /**
@@ -291,11 +292,10 @@
     /**
      * Converts the values to a List.
      *
-     * TODO: Maybe make this public?
-     *
      * @return a new List
+     * @since 1.9.0
      */
-    private List<String> toList() {
+    public List<String> toList() {
         return Arrays.asList(values);
     }
 
@@ -309,6 +309,16 @@
     }
 
     /**
+     * Returns a sequential ordered stream whose elements are the values.
+     *
+     * @return the new stream.
+     * @since 1.9.0
+     */
+    public Stream<String> toStream() {
+        return Arrays.stream(values);
+    }
+
+    /**
      * Returns a string representation of the contents of this record. The result is constructed by comment, mapping,
      * recordNumber and by passing the internal values array to {@link Arrays#toString(Object[])}.
      *
diff --git a/src/test/java/org/apache/commons/csv/CSVRecordTest.java b/src/test/java/org/apache/commons/csv/CSVRecordTest.java
index 1f93c24..4f655f2 100644
--- a/src/test/java/org/apache/commons/csv/CSVRecordTest.java
+++ b/src/test/java/org/apache/commons/csv/CSVRecordTest.java
@@ -34,6 +34,7 @@
 import java.util.Map;
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.commons.lang3.StringUtils;
 import org.junit.jupiter.api.BeforeEach;
@@ -81,6 +82,14 @@
     }
 
     @Test
+    public void testCSVRecordNULLValues() throws IOException {
+        final CSVParser parser = CSVParser.parse("A,B\r\nONE,TWO", CSVFormat.DEFAULT.withHeader());
+        final CSVRecord csvRecord = new CSVRecord(parser, null, null, 0L, 0L);
+        assertEquals(0, csvRecord.size());
+        assertThrows(IllegalArgumentException.class, () -> csvRecord.get("B"));
+    }
+
+    @Test
     public void testGetInt() {
         assertEquals(values[0], record.get(0));
         assertEquals(values[1], record.get(1));
@@ -88,6 +97,11 @@
     }
 
     @Test
+    public void testGetNullEnum() {
+        assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get((Enum<?>) null));
+    }
+
+    @Test
     public void testGetString() {
         assertEquals(values[0], recordWithHeader.get("first"));
         assertEquals(values[1], recordWithHeader.get("second"));
@@ -111,11 +125,6 @@
     }
 
     @Test
-    public void testGetNullEnum() {
-        assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get((Enum<?>) null));
-    }
-
-    @Test
     public void testGetUnmappedName() {
         assertThrows(IllegalArgumentException.class, () -> assertNull(recordWithHeader.get("fourth")));
     }
@@ -131,6 +140,13 @@
     }
 
     @Test
+    public void testGetWithEnum() {
+        assertEquals(recordWithHeader.get("first"), recordWithHeader.get(EnumHeader.FIRST));
+        assertEquals(recordWithHeader.get("second"), recordWithHeader.get(EnumHeader.SECOND));
+        assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get(EnumFixture.UNKNOWN_COLUMN));
+    }
+
+    @Test
     public void testIsConsistent() {
         assertTrue(record.isConsistent());
         assertTrue(recordWithHeader.isConsistent());
@@ -249,6 +265,15 @@
     }
 
     @Test
+    public void testToList() {
+        int i = 0;
+        for (final String value : record.toList()) {
+            assertEquals(values[i], value);
+            i++;
+        }
+    }
+
+    @Test
     public void testToMap() {
         final Map<String, String> map = this.recordWithHeader.toMap();
         this.validateMap(map, true);
@@ -272,6 +297,23 @@
         }
     }
 
+    @Test
+    public void testToStream() {
+        final AtomicInteger i = new AtomicInteger();
+        record.toStream().forEach(value -> {
+            assertEquals(values[i.get()], value);
+            i.incrementAndGet();
+        });
+    }
+
+    @Test
+    public void testToString() {
+        assertNotNull(recordWithHeader.toString());
+        assertTrue(recordWithHeader.toString().contains("comment="));
+        assertTrue(recordWithHeader.toString().contains("recordNumber="));
+        assertTrue(recordWithHeader.toString().contains("values="));
+    }
+
     private void validateMap(final Map<String, String> map, final boolean allowsNulls) {
         assertTrue(map.containsKey("first"));
         assertTrue(map.containsKey("second"));
@@ -285,27 +327,4 @@
         assertEquals("C", map.get("third"));
         assertEquals(null, map.get("fourth"));
     }
-
-    @Test
-    public void testToString() {
-        assertNotNull(recordWithHeader.toString());
-        assertTrue(recordWithHeader.toString().contains("comment="));
-        assertTrue(recordWithHeader.toString().contains("recordNumber="));
-        assertTrue(recordWithHeader.toString().contains("values="));
-    }
-
-    @Test
-    public void testGetWithEnum() {
-        assertEquals(recordWithHeader.get("first"), recordWithHeader.get(EnumHeader.FIRST));
-        assertEquals(recordWithHeader.get("second"), recordWithHeader.get(EnumHeader.SECOND));
-        assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get(EnumFixture.UNKNOWN_COLUMN));
-    }
-
-    @Test
-    public void testCSVRecordNULLValues() throws IOException {
-        final CSVParser parser = CSVParser.parse("A,B\r\nONE,TWO", CSVFormat.DEFAULT.withHeader());
-        final CSVRecord csvRecord = new CSVRecord(parser, null, null, 0L, 0L);
-        assertEquals(0, csvRecord.size());
-        assertThrows(IllegalArgumentException.class, () -> csvRecord.get("B"));
-    }
 }