diff --git a/src/main/java/org/apache/commons/csv/CSVParser.java b/src/main/java/org/apache/commons/csv/CSVParser.java index 471a43c1..98b797ca 100644 --- a/src/main/java/org/apache/commons/csv/CSVParser.java +++ b/src/main/java/org/apache/commons/csv/CSVParser.java @@ -504,44 +504,56 @@ public final class CSVParser implements Iterable, Closeable { headerRecord = formatHeader; } - // build the name to index mappings - if (headerRecord != null) { - // Track an occurrence of a null, empty or blank header. - boolean observedMissing = false; - for (int i = 0; i < headerRecord.length; i++) { - final String header = headerRecord[i]; - final boolean blankHeader = CSVFormat.isBlank(header); - if (blankHeader && !format.getAllowMissingColumnNames()) { - throw new IllegalArgumentException( - "A header name is missing in " + Arrays.toString(headerRecord)); - } - - final boolean containsHeader = blankHeader ? observedMissing : hdrMap.containsKey(header); - final DuplicateHeaderMode headerMode = format.getDuplicateHeaderMode(); - final boolean duplicatesAllowed = headerMode == DuplicateHeaderMode.ALLOW_ALL; - final boolean emptyDuplicatesAllowed = headerMode == DuplicateHeaderMode.ALLOW_EMPTY; - - if (containsHeader && !duplicatesAllowed && !(blankHeader && emptyDuplicatesAllowed)) { - throw new IllegalArgumentException( - String.format( - "The header contains a duplicate name: \"%s\" in %s. If this is valid then use CSVFormat.Builder.setDuplicateHeaderMode().", - header, Arrays.toString(headerRecord))); - } - observedMissing |= blankHeader; - if (header != null) { - hdrMap.put(header, Integer.valueOf(i)); // N.B. Explicit (un)boxing is intentional - if (headerNames == null) { - headerNames = new ArrayList<>(headerRecord.length); - } - headerNames.add(header); - } - } - } + headerNames = getHeaderNames(headerRecord, hdrMap); } // Make header names Collection immutable return new Headers(hdrMap, headerNames == null ? Collections.emptyList() : Collections.unmodifiableList(headerNames)); } + /** + * Build the name to index mappings + * + * @param headerRecord the record as an array of values, or {@code null} if the end of the stream has been reached + * @param headerMap the header column positions (0-based) + * @return header names in column order, or {@code null} if {@code headerRecord} is {@code null}. + */ + private List getHeaderNames(final String[] headerRecord, final Map headerMap) { + List headerNames = null; + if (headerRecord != null) { + // Track an occurrence of a null, empty or blank header. + boolean observedMissing = false; + for (int i = 0; i < headerRecord.length; i++) { + final String header = headerRecord[i]; + final boolean blankHeader = CSVFormat.isBlank(header); + if (blankHeader && !format.getAllowMissingColumnNames()) { + throw new IllegalArgumentException( + "A header name is missing in " + Arrays.toString(headerRecord)); + } + + final boolean containsHeader = blankHeader ? observedMissing : headerMap.containsKey(header); + final DuplicateHeaderMode headerMode = format.getDuplicateHeaderMode(); + final boolean duplicatesAllowed = headerMode == DuplicateHeaderMode.ALLOW_ALL; + final boolean emptyDuplicatesAllowed = headerMode == DuplicateHeaderMode.ALLOW_EMPTY; + + if (containsHeader && !duplicatesAllowed && !(blankHeader && emptyDuplicatesAllowed)) { + throw new IllegalArgumentException( + String.format( + "The header contains a duplicate name: \"%s\" in %s. If this is valid then use CSVFormat.Builder.setDuplicateHeaderMode().", + header, Arrays.toString(headerRecord))); + } + observedMissing |= blankHeader; + if (header != null) { + headerMap.put(header, Integer.valueOf(i)); // N.B. Explicit (un)boxing is intentional + if (headerNames == null) { + headerNames = new ArrayList<>(headerRecord.length); + } + headerNames.add(header); + } + } + } + return headerNames; + } + /** * Gets the current line number in the input stream. *