LoginSignup
0
2

More than 5 years have passed since last update.

【paiza】出題解答用の自分用ユーティリティを作った【Java】

Last updated at Posted at 2017-09-02

■PaizaUtilityのJava版を作りました。

以前公開した 【paiza】出題解答用の自分用ユーティリティを作った【C#】 のJava版です。

Javaは xxx4j と言う命名が一般的らしいので、PaizaUtil4Jと名付けました。
(log4jとか、launch4jとか、twitter4jとかもそうですね。)

改訂メモ:

  • 【version1】C#版をベースにJava版を実装。
  • 【version2】DebugIOプロキシの#readLineのバグ修正
  • 【version3】逐次的文字列リテラル代用の為、ファイル入力に実装変更。

【version1, 2】基本機能だけ取り敢えずJavaに移植しました。

機能性や使い方はC#版と同じなので、今回は省略します。

(*'▽') 説明が必要な人は、以前書いた記事の方を参照してね。

PaizaUtility.java

public class PaizaUtility
{
    public interface ITestIO
    {
        String readLine();

        void writeLine(String line);
    }

    public static class ConsoleProxy implements ITestIO
    {
        private final Scanner in = new Scanner( System.in );

        @Override
        public String readLine()
        {
            return in.nextLine();
        }

        @Override
        public void writeLine(String line)
        {
            System.out.println( line );
        }
    }

    static ITestIO io;

    // static ctor
    static {
        io = new ConsoleProxy();
    }

    public static Iterable<String> readArgs()
    {
        String s = io.readLine();
        int n = Integer.valueOf( s );

        return readArgs( n );
    }
    public static Iterable<String> readArgs(final int n)
    {
        List<String> args = new ArrayList<String>();

        for ( int i = 0; i < n; i++ )
        {
            String arg = io.readLine();

            args.add( arg );
        }

        return args;
    }

    public interface IFunction<TResult, TParameter>
    {
        TResult invoke( TParameter parameter );
    }
    public static Iterable<String> readArgs( IFunction<Integer, String> parseHeaderRecord ) {
        String header = io.readLine();
        int n = parseHeaderRecord.invoke( header ).intValue();

        return readArgs( n );
    }


    // static class.
    private PaizaUtility() { }
}
Do.java(paiza出題の解答ロジックを実装するところ)

public class Do
{
    public static void answer()
    {
//      // IFunction デリゲートをラムダで書くとこんなコードになる。
//      Iterable<String> args = PaizaUtility.readArgs(
//              s -> Integer.parseInt( s )
//      );
        Iterable<String> args = PaizaUtility.readArgs();

        for ( String arg : args )
        {
            PaizaUtility.io.writeLine( arg );
        }
    }
}
Program.java(プログラムのメインエントリポイント)

public class Program
{
    public static void main( String[] args )
    {
        PaizaUtility.io = new DebugIO();

        Do.answer();
    }
}

で、肝心のDebugIOクラスの実装がまだ固まってないんですよね。

◇現状でのDebugIOクラスの仮実装

Program.DebugIO
    private static class DebugIO implements ITestIO
    {
        // java には C# みたいな逐次的文字列リテラル記法が無いからダルい、どーすりゃいいんだこれ。
        private final String[] source = {
                "2",
                "hello",
                "world",
        };

        private int index = 0;

        @Override
        public String readLine()
        {
            return index < source.length ? source[index++] : null;
        }

        @Override
        public void writeLine(String line)
        {
            System.out.println( line );
        }
    }

◇DebugIOクラスで困った事。

C#では 逐次的文字列リテラル という構文仕様があるんですが、Javaにはそれ相当の機能が無いんですよね。
このせいで、C#版だとpaizaの出題パラメータをそのままWeb画面からコピペで使えたのが、Java版だと同じ手が使えない。
さて、どうしたものか。
(ファイルを置いといてパス通してFileReadと言うのが手っ取り早い逃げ道だと思うけど、出来ればファイル使わずにコードベースでやりたいんだけど・・・無理かな)

◇あんまり関係ないけど

コードスタイルがC#ライクでごめんね!!
ぼくはもともとJavaじゃなくC#出身だし、言語的にもJavaよりC#のが好きなんだ!!

◇Java版の問題点

static class 問題。

C#ではstatic classを作れるけど、Javaではstatic classを作れない。

Javaではstatic classを作れないので、外側の(Javaで言えばエンクロージング側の)クラスにstaticキーワードを付けていない。
このせいで、具体的にはPaizaUtilityとDoの2クラスにstaticキーワードを付けてないので、このままコピペしたらコンパイルエラーになる。

強引にこれを解決するとしたら、問題の2クラスを更にダミーのエンクロージングクラスで包んでやって、inner staticメンバに落としてやればいいんだけど、、、なんだかなぁ、、、。

◇バグってました><

Scannerクラスの使い方を間違っていたようで、普通にバグっててpaizaで使えませんでした。
(正確には、使えないケースがあった)

ConsoleProxy(修正前)

        @Override
        public String readLine()
        {
            return in.next();
        }
ConsoleProxy(修正後)

        @Override
        public String readLine()
        {
            return in.nextLine();
        }

なんてこったい(´・ω・`)

Javaで標準IOなんてそうそうやらないから、paiza公式の 値取得・出力サンプルコード をそのまま実装したらハメられました。
よく確認しなかった自分が悪いんですけどね、、、。

参考情報:
似たような所でハマッてる人がいて参考になりました。

JavaのScannerとか.nextLine()の挙動をよく分かってなかった話

【version3】逐次的文字列リテラル対応(ファイル入力化)

DebugIO(コンストラクタのみ抜粋)

        public DebugIO()
        {
            super();
            this.source = readDataSource();
        }
        private static String[] readDataSource()
        {
            // 取り敢えず相対パスでテキストファイルから読み込む事にする。
            Path path = Paths.get( "dat/datasource.txt" );

            try
            {
                return Files.lines( path ).toArray( String[]::new );
            }
            catch ( IOException ex )
            {
                // 絶対有り得ないケースだから何でも良いんだけど取り敢えず空にしとく。
                ex.printStackTrace();
                return new String[]{};
            }
        }
dat/datasource.txt
3
hoge
moge
piyo
実行結果
hoge
moge
piyo

■ソリューション一式はこちら

ソリューション一式はGitHubに置いてあります。
今後、コメント追加したり、機能改良したり、色々弄ってく予定。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2