改行を含まないデータTSVファイルの読込み

改行を含まないデータCSVファイルの読込み - Oboe吹きプログラマの黙示録
を書いたのなら、
TSV の場合も同様に書ける。
まず、Csvtolist はカンマ区切りなので、これをタブ区切りで処理する Tsvtolist を用意する。
Csvtolist から変更箇所は1箇所だけである

Tsvtolist

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;

public interface Tsvtolist extends Serializable{

    public static Function<String, List<String>> of(){
        return Tsvtolist::create;
    }
    
    public static List<String> create(String str){
        char DELIMITER = '\t';
        char CARRIAGE_RETURN = '\r';
        char NEWLINE = '\n';
        char DOUBLE_QUOTE = '"';
        if (str==null || str.length()==0){
            return Collections.emptyList();
        }
        List<String> tokens = new ArrayList<String>();
        StringBuilder tokenBuf = new StringBuilder();
        boolean insideDoubleQuote = false;
        boolean isDoubleQuoteEscapeActive = false;
        StringBuilder wspBuf = new StringBuilder();
        for(int ii=0; ii < str.length(); ii++){
            final char ch = str.charAt(ii);
            if (ch==CARRIAGE_RETURN || ch==NEWLINE){
                if (insideDoubleQuote){
                    tokenBuf.append(ch);
                }else{
                    throw new RuntimeException("unquoted " 
                                               + (ch=='\n' ? "newline" : "carriage return") 
                                               + " found at position #" + (ii+1));
                }
            }else if(ch==DOUBLE_QUOTE){
                if (insideDoubleQuote){
                    if (isDoubleQuoteEscapeActive){
                        tokenBuf.append(ch);
                        isDoubleQuoteEscapeActive = false;
                    }else if(((ii+1) < str.length()) && str.charAt(ii+1)==DOUBLE_QUOTE){
                        isDoubleQuoteEscapeActive = true;
                    }else{
                        insideDoubleQuote = false;
                    }
                }else{
                    insideDoubleQuote = true;
                    if (wspBuf.length() != 0){
                        if (tokenBuf.length() != 0){
                            tokenBuf.append(wspBuf);
                        }
                        wspBuf.delete(0, wspBuf.length());
                    }
                }
            }else{
                if (insideDoubleQuote){
                    tokenBuf.append(ch);
                }else{
                    if (ch==DELIMITER){
                        tokens.add(tokenBuf.toString());
                        tokenBuf.delete(0, tokenBuf.length());
                        wspBuf.delete(0, wspBuf.length());
                    }else if(Character.isWhitespace(ch)){
                         wspBuf.append(ch);
                    }else{
                        if (wspBuf.length() != 0){
                            if (tokenBuf.length() != 0){
                                tokenBuf.append(wspBuf);
                            }
                            wspBuf.delete(0, wspBuf.length());
                        }
                        tokenBuf.append(ch);
                    }
                }
            }
        }
        if (insideDoubleQuote){
            throw new RuntimeException("terminating double quote not found");
        }
        tokens.add(tokenBuf.toString());
        return tokens;
    }
}

データに改行を含まない前提なので、ファイル読込みの処理を組み込んだ interface class は、
TsvReadProcess

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;

public interface TsvReadProcess{
    public void inspectLine(int lineno, List<String> list) throws FingersplitException;
    public Charset getCharset();
    
    public static TsvReadProcess of(Charset charset, BiFunction<Integer, List<String>, String> inspector) {
        return new TsvReadProcess() {
            @Override
            public void inspectLine(int lineno, List<String> list) throws FingersplitException {
                String res = inspector.apply(lineno, list);
                if (res != null && !res.isBlank()){
                    throw new FingersplitException(lineno, res);
                }
            }
            @Override
            public Charset getCharset(){
                return charset;
            }
        };
    }

    public default void execute(ThrowableSupplier<InputStream> getStreamer, 
                                BiConsumer<Integer, Map<String, String>> bifunc) throws Exception {
        try(InputStream inst = getStreamer.get();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inst, getCharset()))){
            String line = BOMfunction.chop(reader.readLine());
            AtomicInteger ix = new AtomicInteger(0);
            List<String> hlist = Tsvtolist.create(line);
            inspectLine(1, hlist);
            int rownum = hlist.size();
            Map<Integer, String> hmap = hlist.stream()
            .collect(()->new HashMap<Integer, String>(),(r, t)->{
                r.put(ix.incrementAndGet(), t);
            },(r, t)->{});
            ix.set(1);
            int lc = 1;
            while((line = reader.readLine()) != null){
                Map<String, String> map = new HashMap<>();
                List<String> list = Tsvtolist.create(line);
                if (rownum != list.size()) {
                    throw new FingersplitException(lc, "header rows No match!");
                }
                inspectLine(ix.incrementAndGet(), list);
                hmap.entrySet().stream().forEach(e->{
                    map.put(e.getValue(), list.get(e.getKey()-1));
                });
                bifunc.accept(lc, map);
                lc++;
            }
        }catch(Exception e){
            throw e;
        }
    }
}

使用している BOMfunction や、FingersplitException は、
改行を含まないデータCSVファイルの読込み - Oboe吹きプログラマの黙示録
を参照

使用サンプル

try{
    TsvReadProcess process = TsvReadProcess.of(Charset.forName("MS932"), (i,list)->{
        // TODO  異常があれば、エラーメッセージを返す、正常なら、null またはブランク、空白を返す。
        return  null;
    });
    process.execute(()->getMyInputStream(), (i, map)->{
        System.out.println("i="+i+"  "+ map);
        
    });
}catch(FingersplitException e){
    System.err.println("catch! FingersplitException");
    System.err.println("catch! "+e.getMessage());
    e.printStackTrace();
}catch(Exception e){
    e.printStackTrace();
}

UTF-8 の TSV ファイルだったら、
Charset.forName("MS932") を指定しないで、
StandardCharsets.UTF_8 を与える