diff --git a/lib/src/main/java/de/siegmar/fastcsv/reader/CsvRecord.java b/lib/src/main/java/de/siegmar/fastcsv/reader/CsvRecord.java index 8d6d6a78..75e71255 100644 --- a/lib/src/main/java/de/siegmar/fastcsv/reader/CsvRecord.java +++ b/lib/src/main/java/de/siegmar/fastcsv/reader/CsvRecord.java @@ -6,7 +6,14 @@ import java.util.StringJoiner; /** - * Index based CSV-record. + * Represents an immutable CSV record with unnamed (indexed) fields. + *
+ * The field values are never {@code null}. Empty fields are represented as empty strings. + *
+ * CSV records are created by {@link CsvReader} or {@link IndexedCsvReader}. + * + * @see CsvReader + * @see IndexedCsvReader */ @SuppressWarnings("PMD.ArrayIsStoredDirectly") public class CsvRecord { @@ -56,18 +63,34 @@ public class CsvRecord { } /** - * Returns the starting line number (starting with 1). On multi-line records this is the starting - * line number. - * Empty lines could be skipped via {@link CsvReader.CsvReaderBuilder#skipEmptyLines(boolean)}. + * Provides the line number at which this record originated, starting from 1. + *
+ * This information is particularly valuable in scenarios involving CSV files containing empty lines as well as + * multi-line or commented records, where the record number may deviate from the line number. + *
+ * Example: + *
+ * 1 foo,bar + * 2 foo,"multi + * 3 line bar" + * 4 (empty, potentially skipped) + * 5 #commented record (potentially skipped) + * 6 "latest + * 7 record" + *+ * The last record (containing the multi-line field "latest\nrecord") would have a starting line number of 6, + * no matter if empty lines or commented records are skipped or not. + *
+ * A starting offset of 1 is used to be consistent with the line numbers shown of most text editors.
*
- * @return the starting line number
+ * @return the starting line number of this record, starting from 1
*/
public long getStartingLineNumber() {
return startingLineNumber;
}
/**
- * Gets a field value by its index (starting with 0).
+ * Retrieves the value of a field based on its index, with indexing starting from 0.
*
* @param index index of the field to return
* @return field value, never {@code null}
@@ -78,7 +101,7 @@ public String getField(final int index) {
}
/**
- * Gets all fields of this record as an unmodifiable list.
+ * Retrieves all fields of this record as an unmodifiable list.
*
* @return all fields of this record, never {@code null}
*/
@@ -87,7 +110,7 @@ public List
+ * The field values are never {@code null}. Empty fields are represented as empty strings.
+ *
+ * Named CSV records are created by {@link NamedCsvReader}.
+ *
+ * @see NamedCsvReader
+ * @see CsvReader
*/
@SuppressWarnings("PMD.ArrayIsStoredDirectly")
public final class NamedCsvRecord extends CsvRecord {
@@ -26,9 +33,13 @@ public final class NamedCsvRecord extends CsvRecord {
}
/**
- * Gets a field value by its name (first occurrence if duplicates exists).
+ * Retrieves the value of a field by its case-sensitive name, considering the first occurrence in case of
+ * duplicates.
+ *
+ * This method is equivalent to {@code findField(name).orElseThrow(NoSuchElementException::new)} although a
+ * more explanatory exception message is provided.
*
- * @param name field name
+ * @param name case-sensitive name of the field to be retrieved
* @return field value, never {@code null}
* @throws NoSuchElementException if this record has no such field
* @throws NullPointerException if name is {@code null}
@@ -37,17 +48,23 @@ public final class NamedCsvRecord extends CsvRecord {
*/
public String getField(final String name) {
final int fieldPos = findHeader(name);
+
+ // Check if the field position is valid
if (fieldPos == -1) {
throw new NoSuchElementException(MessageFormat.format(
"Header does not contain a field ''{0}''. Valid names are: {1}", name, Arrays.toString(header)));
- } else if (fieldPos >= fields.length) {
+ }
+ if (fieldPos >= fields.length) {
throw new NoSuchElementException(MessageFormat.format(
"Field ''{0}'' is on position {1}, but current record only contains {2} fields",
name, fieldPos + 1, fields.length));
}
+
+ // Return the value of the field
return fields[fieldPos];
}
+ // Finds the position of the first occurrence of the given header name (case-sensitive); returns -1 if not found
private int findHeader(final String name) {
for (int i = 0; i < header.length; i++) {
final String h = header[i];
@@ -60,25 +77,33 @@ private int findHeader(final String name) {
}
/**
- * Finds a field value by its name (first occurrence if duplicates exists).
+ * Retrieves the value of a field by its case-sensitive name, considering the first occurrence in case of
+ * duplicates.
+ *
+ * This method is equivalent to {@code findFields(name).stream().findFirst()} but more performant.
*
- * @param name field name
- * @return the field value ({@link Optional#empty()} if record doesn't contain that field), never {@code null}
+ * @param name case-sensitive name of the field to be retrieved
+ * @return An {@code Optional} containing the value of the field if found,
+ * or an empty {@code Optional} if the field is not present. Never returns {@code null}.
* @throws NullPointerException if name is {@code null}
* @see #findFields(String)
*/
public Optional
- * The map will contain only entries for fields that have a key and a value –
- * no map entry will have a {@code null} key or value.
+ * The constructed map will only contain entries for fields that have a key and a value. No map entry will have a
+ * {@code null} key or value.
+ *
+ * If you need to collect all fields with the same name (duplicate header), use {@link #getFieldsAsMapList()}.
*
* @return an ordered map of header names and field values of this record, never {@code null}
+ * @see #getFieldsAsMapList()
*/
public Map
+ * The constructed map will only contain entries for fields that have a key and a value. No map entry will have a
+ * {@code null} key or value.
*
- * The map will contain only entries for fields that have a key and a value –
- * no map entry will have a {@code null} key or value.
+ * If you don't have to handle duplicate headers, you may simply use {@link #getFieldsAsMap()}.
*
* @return an unordered map of header names and field values of this record, never {@code null}
+ * @see #getFieldsAsMap()
*/
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
public Map