Coverage Report - org.apache.commons.io.LineIterator
 
Classes in this File Line Coverage Branch Coverage Complexity
LineIterator
91%
41/45
94%
17/18
3,625
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.io;
 18  
 
 19  
 import java.io.BufferedReader;
 20  
 import java.io.Closeable;
 21  
 import java.io.IOException;
 22  
 import java.io.Reader;
 23  
 import java.util.Iterator;
 24  
 import java.util.NoSuchElementException;
 25  
 
 26  
 /**
 27  
  * An Iterator over the lines in a <code>Reader</code>.
 28  
  * <p>
 29  
  * <code>LineIterator</code> holds a reference to an open <code>Reader</code>.
 30  
  * When you have finished with the iterator you should close the reader
 31  
  * to free internal resources. This can be done by closing the reader directly,
 32  
  * or by calling the {@link #close()} or {@link #closeQuietly(LineIterator)}
 33  
  * method on the iterator.
 34  
  * <p>
 35  
  * The recommended usage pattern is:
 36  
  * <pre>
 37  
  * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
 38  
  * try {
 39  
  *   while (it.hasNext()) {
 40  
  *     String line = it.nextLine();
 41  
  *     // do something with line
 42  
  *   }
 43  
  * } finally {
 44  
  *   it.close();
 45  
  * }
 46  
  * </pre>
 47  
  *
 48  
  * @since 1.2
 49  
  */
 50  0
 public class LineIterator implements Iterator<String>, Closeable {
 51  
 
 52  
     // N.B. This class deliberately does not implement Iterable, see https://issues.apache.org/jira/browse/IO-181
 53  
 
 54  
     /** The reader that is being read. */
 55  
     private final BufferedReader bufferedReader;
 56  
     /** The current line. */
 57  
     private String cachedLine;
 58  
     /** A flag indicating if the iterator has been fully read. */
 59  28
     private boolean finished = false;
 60  
 
 61  
     /**
 62  
      * Constructs an iterator of the lines for a <code>Reader</code>.
 63  
      *
 64  
      * @param reader the <code>Reader</code> to read from, not null
 65  
      * @throws IllegalArgumentException if the reader is null
 66  
      */
 67  28
     public LineIterator(final Reader reader) throws IllegalArgumentException {
 68  28
         if (reader == null) {
 69  2
             throw new IllegalArgumentException("Reader must not be null");
 70  
         }
 71  26
         if (reader instanceof BufferedReader) {
 72  4
             bufferedReader = (BufferedReader) reader;
 73  
         } else {
 74  22
             bufferedReader = new BufferedReader(reader);
 75  
         }
 76  26
     }
 77  
 
 78  
     //-----------------------------------------------------------------------
 79  
     /**
 80  
      * Indicates whether the <code>Reader</code> has more lines.
 81  
      * If there is an <code>IOException</code> then {@link #close()} will
 82  
      * be called on this instance.
 83  
      *
 84  
      * @return {@code true} if the Reader has more lines
 85  
      * @throws IllegalStateException if an IO exception occurs
 86  
      */
 87  
     @Override
 88  
     public boolean hasNext() {
 89  170
         if (cachedLine != null) {
 90  42
             return true;
 91  128
         } else if (finished) {
 92  34
             return false;
 93  
         } else {
 94  
             try {
 95  
                 while (true) {
 96  106
                     final String line = bufferedReader.readLine();
 97  104
                     if (line == null) {
 98  22
                         finished = true;
 99  22
                         return false;
 100  82
                     } else if (isValidLine(line)) {
 101  70
                         cachedLine = line;
 102  70
                         return true;
 103  
                     }
 104  12
                 }
 105  2
             } catch(final IOException ioe) {
 106  
                 try {
 107  2
                     close();
 108  0
                 } catch (final IOException e) {
 109  0
                     ioe.addSuppressed(e);
 110  2
                 }
 111  2
                 throw new IllegalStateException(ioe);
 112  
             }
 113  
         }
 114  
     }
 115  
 
 116  
     /**
 117  
      * Overridable method to validate each line that is returned.
 118  
      * This implementation always returns true.
 119  
      * @param line  the line that is to be validated
 120  
      * @return true if valid, false to remove from the iterator
 121  
      */
 122  
     protected boolean isValidLine(final String line) {
 123  46
         return true;
 124  
     }
 125  
 
 126  
     /**
 127  
      * Returns the next line in the wrapped <code>Reader</code>.
 128  
      *
 129  
      * @return the next line from the input
 130  
      * @throws NoSuchElementException if there is no line to return
 131  
      */
 132  
     @Override
 133  
     public String next() {
 134  66
         return nextLine();
 135  
     }
 136  
 
 137  
     /**
 138  
      * Returns the next line in the wrapped <code>Reader</code>.
 139  
      *
 140  
      * @return the next line from the input
 141  
      * @throws NoSuchElementException if there is no line to return
 142  
      */
 143  
     public String nextLine() {
 144  100
         if (!hasNext()) {
 145  32
             throw new NoSuchElementException("No more lines");
 146  
         }
 147  68
         final String currentLine = cachedLine;
 148  68
         cachedLine = null;
 149  68
         return currentLine;
 150  
     }
 151  
 
 152  
     /**
 153  
      * Closes the underlying {@code Reader}.
 154  
      * This method is useful if you only want to process the first few
 155  
      * lines of a larger file. If you do not close the iterator
 156  
      * then the {@code Reader} remains open.
 157  
      * This method can safely be called multiple times.
 158  
      *
 159  
      * @throws IOException if closing the underlying {@code Reader} fails.
 160  
      */
 161  
     @Override
 162  
     public void close() throws IOException {
 163  30
         finished = true;
 164  30
         cachedLine = null;
 165  30
         if (this.bufferedReader != null) {
 166  30
             this.bufferedReader.close();
 167  
         }
 168  30
     }
 169  
 
 170  
     /**
 171  
      * Unsupported.
 172  
      *
 173  
      * @throws UnsupportedOperationException always
 174  
      */
 175  
     @Override
 176  
     public void remove() {
 177  12
         throw new UnsupportedOperationException("Remove unsupported on LineIterator");
 178  
     }
 179  
 
 180  
     //-----------------------------------------------------------------------
 181  
     /**
 182  
      * Closes a {@code LineIterator} quietly.
 183  
      *
 184  
      * @param iterator The iterator to close, or {@code null}.
 185  
      * @deprecated As of 2.6 removed without replacement. Please use the try-with-resources statement or handle
 186  
      * suppressed exceptions manually.
 187  
      * @see Throwable#addSuppressed(java.lang.Throwable)
 188  
      */
 189  
     @Deprecated
 190  
     public static void closeQuietly(final LineIterator iterator) {
 191  
         try {
 192  28
             if (iterator != null) {
 193  24
                 iterator.close();
 194  
             }
 195  0
         } catch(final IOException e) {
 196  
             // Suppressed.
 197  28
         }
 198  28
     }
 199  
 
 200  
 }