20190714のJavaに関する記事は16件です。

それは「else if」ではない「else」と「if」だ

 言語によっては elseif なんていうのもありますが、「else if」と言われているものは、elseのときに実行する処理がif~だという超小ネタです。

「if や else は必ず {} で囲め」というコーディング規約に書いているのに、そのコーディング規約の中でもelseやifを……

if (/*条件*/) {
  // 略
} else if (/*条件*/) {
  // 略
}

……みたいに書かれていたりすると「こいつ分かってないな」と思ってしまいます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ライブラリ作ってみました(JAVA編) 日時ライブラリ

自作ライブラリを作った経緯

 ソフトを開発するにあたって、自作のライブラリを使用しています。
理由は、勉強のためと言うこともあるし、自分で作った方が痒い所に手が届くということがあるからです。宜しければ、ご覧ください。

日時ライブラリ(github)

使い方

package main;

import java.text.ParseException;

import libTime.LibTime;

public class Main {

    public static void main(String[] args) throws ParseException {

        //時間ライブラリ
        LibTime libTime = new LibTime();

        //String format = "yyyy'年'MM'月'dd'日'";
        //String format = "yyyy年MM月dd日 E曜日";
        //String format = "yyyy年MM月dd日 E曜日";
        //String format = "a hh:mm:ss SSS";
        String format = "a hh:mm:ss SSS";

        //日時取得
        String date = libTime.getTime(format);

        //表示
        System.out.println(date);

        //////////////////////////////////////////////////////////////////////////////

        //日付フォーマットをlong値[ミリ秒]に変換
        long longDate = libTime.getMilliTime(format, date);

        //表示
        System.out.println(longDate);

        //////////////////////////////////////////////////////////////////////////////

        //long値[ミリ秒]を日付フォーマットに変換する
        date = libTime.getTime(format, longDate);

        //表示
        System.out.println(date);

        //////////////////////////////////////////////////////////////////////////////

        //UNIX時間取得
        int time = libTime.getUnixTime();

        //表示
        System.out.println(time);

        //////////////////////////////////////////////////////////////////////////////

        //
        format = "hh:mm:ss";

        //
        String dateFromStr = "12:00:00";
        String dateToStr   = "12:10:35";

        //時間差取得[ミリ秒]
        long timeDiff = libTime.getTimeDiff(format, dateFromStr, dateToStr);

        //表示
        System.out.println(timeDiff);

        //////////////////////////////////////////////////////////////////////////////

        //
        String dateStr    = "2019年01月31日";
        String formatFrom = "yyyy'年'MM'月'dd'日'";
        String formatTo   = "yyyy/MM/dd";

        //日付フォーマット変換
        date = libTime.transFormat(dateStr, formatFrom, formatTo);

        //表示
        System.out.println(date);

        //////////////////////////////////////////////////////////////////////////////

        //年齢
        int age = 0;

        //
        String birthday = "1995/01/31";

        //
        format = "yyyy/MM/dd";

        //年齢計算(時刻基準)
        age = libTime.getAgeByTime(birthday, format);

        //表示
        System.out.println(age);

        //年齢計算(日付基準)
        age = libTime.getAgeByDate(birthday, format);

        //表示
        System.out.println(age);
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ライブラリ作ってみました(JAVA編) 正規表現ライブラリ

自作ライブラリを作った経緯

 ソフトを開発するにあたって、自作のライブラリを使用しています。
理由は、勉強のためと言うこともあるし、自分で作った方が痒い所に手が届くということがあるからです。宜しければ、ご覧ください。

正規表現ライブラリ(github)

使い方

package main;

import java.util.List;

import libPattern.LibPattern;

public class Main {

    public static void main(String[] args) {

        //正規表現ライブラリ
        LibPattern libPattern = new LibPattern();


        //検索文字列
        String text = "test29234098test92095test409430test66587";

        //パターン
        String regex = "(([a-z]{1,})([0-9]{1,}))";

        //パターングループ番号(指定しない場合は0)
        int n = 3;  //0, 1, 2, 3

        //正規表現(単一グループ, 単一match)
        String s = libPattern.getPattern(text, regex, n);

        //表示
        System.out.println(s);

        //正規表現(単一グループ, 全match)
        List<String> listMat = libPattern.getPatternList(text, regex, n);

        //表示
        System.out.println(listMat);

        //正規表現(全グループ, 全match)
        List<List<String>> listGrpMat = libPattern.getPatternListAllGroup(text, regex);

        //表示
        System.out.println(listGrpMat);


        //////////////////////////////////////////////////////////////////////

        //
        text = "aselksjjlb ejlkaseliavl823ja\nlaeraselkjb\n"
                    + "あいうえ ;ぁけjrヵあいうえ;ぁえkjぁあああああ\n"
                    + "あいうえ";

        //
        regex      = "ASE";
        boolean blBigSmall = true;
        boolean blPattern  = false;

        //文字列検索
        long count = libPattern.searchText(text, regex, blBigSmall, blPattern);

        //表示
        System.out.println(blBigSmall + " " + blPattern + " " + " " + regex + " " + count);

        //
        regex      = "ase";
        blBigSmall = true;
        blPattern  = false;

        //文字列検索
        count = libPattern.searchText(text, regex, blBigSmall, blPattern);

        //表示
        System.out.println(blBigSmall + " " + blPattern + " " + " " + regex + " " + count);


        //
        regex      = "[A-Z]{5}";
        blBigSmall = true;
        blPattern  = true;
        String replacement = "X";

        //文字列置換
        s = libPattern.replaceText(text, regex, replacement, blBigSmall, blPattern);

        //表示
        System.out.println("----");
        System.out.println(blBigSmall + " " + blPattern + " " + " " + regex + " " + count);
        System.out.println(s);


        //
        regex      = "[A-Z]{5}";
        blBigSmall = false;
        blPattern  = true;
        replacement = "X";

        //文字列置換
        s = libPattern.replaceText(text, regex, replacement, blBigSmall, blPattern);

        //表示
        System.out.println("----");
        System.out.println(blBigSmall + " " + blPattern + " " + " " + regex + " " + count);
        System.out.println(s);

    }

}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ライブラリ作ってみました(JAVA編) GISライブラリ

自作ライブラリを作った経緯

 ソフトを開発するにあたって、自作のライブラリを使用しています。
理由は、勉強のためと言うこともあるし、自分で作った方が痒い所に手が届くということがあるからです。宜しければ、ご覧ください。

GISライブラリ

使い方

package main;

import java.util.Map;

import libGis.LibGis;

public class Main {

    public static void main(String[] args) {

        //GIS関連のライブラリ
        LibGis libGis = new LibGis();

        //初期化
        double longitude = 139.799861;
        double latitude  =  35.628674;

        //座標変換
        //  緯度経度 -> x[m], y[m]
        Map<String, Double> map = libGis.transMeter(longitude, latitude);

        //表示
        System.out.println(map);

        /////////////////////////////////////////////////////////////////////////

        //初期化
        double lat1 =  35.628674;
        double lng1 = 139.799861;
        double lat2 =  35.629677;
        double lng2 = 139.799491;

        //2点間の距離
        //  ヒュベニの公式
        //  http://yamadarake.jp/trdi/report000001.html
        double d = libGis.distanceHb(lat1, lng1, lat2, lng2);

        //表示
        System.out.println(d);

        /////////////////////////////////////////////////////////////////////////

        //2点間の距離
        //  球面三角法(a spherical trigonometry)
        d = libGis.distanceSt(lat1, lng1, lat2, lng2);

        //表示
        System.out.println(d);

        //方位計算(degree)
        //  notrh :0°
        //  range :0~360°
        double deg = libGis.directionDeg(lat1, lng1, lat2, lng2);

        //表示
        System.out.println(deg);
    }

}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ライブラリ作ってみました(JAVA編) ファイルライブラリ

自作ライブラリを作った経緯

 ソフトを開発するにあたって、自作のライブラリを使用しています。
理由は、勉強のためと言うこともあるし、自分で作った方が痒い所に手が届くということがあるからです。宜しければ、ご覧ください。

ファイルライブラリ(github)

使い方

package main;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import libFile.LibFile;

public class Main {

    public static void main(String[] args) throws IOException {

        //ファイルライブラリ
        LibFile libFile = new LibFile();


        //カレントディレクトリ取得
        String path = libFile.getCurrentDir();

        String  q;
        Boolean bl;

        //フォルダ作成
        bl = libFile.mkDir(path);

        //ファイル一覧取得
        List<File> listFile = new ArrayList<File>();

        //ファイル一覧取得
        listFile = libFile.getF(path);

        //フォルダ一覧取得
        listFile = libFile.getD(path);

        //ファイル / フォルダ一覧取得
        listFile = libFile.getFD(path);

        //q 文字列(test, sample, txt, jpg, png)
        q  = "sample";

        //bl true    :文字列検索(test, sample)
        //   false   :拡張子検索(txt, jpg, png)
        bl = true;

        //ファイル一覧取得
        listFile = libFile.getF(path, q, bl);

        //フォルダ一覧取得
        listFile = libFile.getD(path, q);

        //ファイル, フォルダ一覧取得
        listFile = libFile.getFD(path, q);

        //
        String encoding = "utf-8";

        //ファイル読み込み(一括)
        String text = libFile.readFileString(path, encoding);

        //ファイル読み込み(行別)
        List<String> listLine = libFile.readFileList(path, encoding);

        //bl true 追記, false 上書き
        bl = true;

        //
        text = "aaaa\nbbbb";

        //ファイル書き込み(String)
        libFile.writeFile(path, encoding, text, bl);

        //登録
        listLine.add("aaaa");
        listLine.add("bbbb");

        //ファイル書き込み(List)
        libFile.writeFile(path, encoding, listLine, bl);

        //登録
        String[] aryLine = {"aaaa", "bbbb"};

        //ファイル書き込み(配列)
        libFile.writeFile(path, encoding, aryLine, bl);

        //ファイル削除
        libFile.deleteFile(path);

        //初期化
        File file = new File("./sample.txt");

        //ファイル削除
        libFile.deleteFile(file);

        //ファイル一括削除
        libFile.deleteFile(listFile);

        //拡張子取得
        String prefix = libFile.getExtension(path);
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ライブラリ作ってみました(JAVA編) データベースライブラリ

自作ライブラリを作った経緯

 ソフトを開発するにあたって、自作のライブラリを使用しています。
理由は、勉強のためと言うこともあるし、自分で作った方が痒い所に手が届くということがあるからです。宜しければ、ご覧ください。

データベースライブラリ(github)

使い方

クラス呼び出し

        //dbタイプ
        String dbType = "sqlServer";  //今のところ、sql serverのみ

        //Dbパラメータ
        Map<String, String> mapDb = new HashMap<String, String>();

        //値取得
        mapDb.put("serverName"   , "localhost");
        mapDb.put("port"         , "1433");
        mapDb.put("databaseName" , "sampleDB");
        mapDb.put("user"         , "sa");
        mapDb.put("password"     , "pass");

        //データベースオブジェクト
        LibDatabase libDatabase = new LibDatabase(dbType, mapDb);

        //DB接続確認
        if(!libDatabase.getConnectCheck())System.out.println("接続エラー:外部jar確認");

テーブル作成

        //初期化
        String table = "sampleTable";

        //初期化
        Map<String, String> mapTable = new HashMap<String, String>();

        //パラメータ追加
        mapTable.put("userId"  , "int"        );  //id
        mapTable.put("name"    , "varchar(99)");  //名前
        mapTable.put("kana"    , "varchar(99)");  //カナ
        mapTable.put("birthday", "datetime"   );  //生年月日
        mapTable.put("@pKey"   , "userId"     );  //主キー

        //クエリ実行
        bl = libDatabase.executeCreateTable(table, mapTable);

        //表示
        System.out.println(bl + " " + table);

テーブル削除

        //初期化
        String table = "sampleTable";

        //クエリ
        String sql = "IF OBJECT_ID('dbo." + table + "') IS NOT NULL DROP TABLE IF EXISTS " + table;

        //クエリ実行
        boolean bl = libDatabase.execute(sql);

        //表示
        System.out.println(bl + " " + sql);

インデックス設定

        //初期化
        String table = "sampleTable";

        //クエリ
        sql = "CREATE NONCLUSTERED INDEX IdxUserId ON " + table + "(userId);";

        //クエリ実行
        bl = libDatabase.execute(sql);

        //表示
        System.out.println(bl + " " + sql);

データ登録

        //初期化
        String table = "sampleTable";

        //初期化
        Map<String, Object> mapParam = new HashMap<String, Object>();

        //登録
        //  NS:String
        //  S :String
        //  I :Integer
        //  L :Long
        //  F :Float
        //  D :Double
        //  B :Byte
        //  A :Bytes
        mapParam.put("I@userId"  , 1);
        mapParam.put("S@name"    , "佐々木太郎");
        mapParam.put("S@kana"    , "ささきたろう");
        mapParam.put("S@birthday", "1995/01/13");

        //クエリ実行
        int n = libDatabase.executeInsert(table, mapParam);

        //表示
        System.out.println(n);

データ登録(一括)

        //初期化
        String table = "sampleTable";

        //フィールド
        List<String> listField = new ArrayList<String>();

        //
        listField.add("I@userId"  );
        listField.add("S@name"    );
        listField.add("S@kana"    );
        listField.add("S@birthday");

        //パラメータセット
        List<List<Object>> listParamSet = new ArrayList<List<Object>>();

        //パラメータ
        List<Object> listParam = new ArrayList<Object>();   //新規メモリ

        //パラメータ登録
        listParam.add(2);
        listParam.add("田中次郎");
        listParam.add("たなかじろう");
        listParam.add("1997/03/04");

        //追加
        listParamSet.add(listParam);

        //パラメータ
        List<Object> listParam_2 = new ArrayList<Object>();   //新規メモリ

        //パラメータ登録
        listParam_2.add(3);
        listParam_2.add("鈴木花子");
        listParam_2.add("すずきはなこ");
        listParam_2.add("1992/08/15");

        //追加
        listParamSet.add(listParam_2);

        //クエリ実行
        n = libDatabase.executeInsertList(table, listField, listParamSet);

        //表示
        System.out.println(n);

データ更新

        //初期化
        String table = "sampleTable";

        //初期化
        Map<String, Object> mapValue = new HashMap<String, Object>();
        Map<String, Object> mapKey   = new HashMap<String, Object>();

        //登録
        mapValue.put("S@name", "たっきー");
        mapValue.put("S@kana", "タッキー");

        //登録
        mapKey.put("I@userId", 1);

        //クエリ実行
        n = libDatabase.executeUpdate(table, mapValue, mapKey);

        //表示
        System.out.println(n);

コミット、ロールバック

        //コミット設定
        libDatabase.setCommit();

        //クエリ

        //コミット
        libDatabase.commit();

        //ロールバック
        //libDatabase.rollback();

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

キラッとプリ☆チャンコーデ管理アプリを更新してみた!

以前、書いたこちらの記事(キラッとプリ☆チャンのコーデ管理アプリを作ってみた話)から更新しました。

更新した部分

リストの読み込み部分をSQLiteのデータベースにマルナゲ!

前のは、いちいちソースに書いてたので、これをSQLiteで作成しておいたデータベースを取得して、アプリのリストビューで見れるように。

     private class ListShowClickListener implements View.OnClickListener {

        @Override
        public void onClick(View view) {
            // データベースヘルパーオブジェクトを作成
            DatabaseHelper helper = new DatabaseHelper(PrichanJewel1.this);
            // データベース接続オブジェクトを作成
            try (SQLiteDatabase db = helper.getWritableDatabase()) {
                String sql = "select * from prij1corde order by _id";
                Cursor cursor = db.rawQuery(sql, null);
                String[] column = {"card_name", "card_own"};
                int[] cardList = {android.R.id.text1, android.R.id.text2};
                SimpleCursorAdapter adapter = new SimpleCursorAdapter
                        (PrichanJewel1.this, android.R.layout.simple_expandable_list_item_2,
                                cursor, column, cardList, 0);
                lvJprichan.setAdapter(adapter);
            }
        }
    }

これで、SQLiteに既に作られたデータベースにアクセスして、リストを取得して、リストビューに表示することができるようになりました。
更新の場合も同じような感じで出来ました。

        public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
            // 長押しされた位置を取得
            Cursor item = (Cursor)lvJprichan.getItemAtPosition(position);
            // 取得した位置にあるリスト名を取得(ここではカード名を取得する)
            String card_name = item.getString(item.getColumnIndex("card_name"));
            // データベースヘルパーオブジェクトを作成
            DatabaseHelper helper = new DatabaseHelper(PrichanJewel1.this);
            // データベース接続オブジェクトを作成
            try (SQLiteDatabase db = helper.getWritableDatabase()) {
                String upSql = "update prij1corde set card_own = '所持済' where card_name = '" + card_name + "'";
                SQLiteStatement stmt = db.compileStatement(upSql);
                stmt.executeUpdateDelete();
            }
            Toast.makeText(PrichanJewel1.this,
                    "登録完了!",Toast.LENGTH_SHORT).show();
            return true;
        }

なお、データベースヘルパーは
男子大学生の考えること:自前のSQLiteDatabaseファイルをassetsからandroidで使えるようにする
で、紹介されているソースコードほぼそのまま使っています。
リスト取得はこちらの記事が参考になりました。

sqliteで取得した値をListViewに表示する簡単な例

どうしてそう出来たの?

なかなかいいアイデアが閃かず、半ばヤケクソでJavaとPostgreSQLで同じような仕組みのを作ったことで、ひらめいたわけです。
「データベース組み込んだらできるんじゃね?」
と。
やったことが全く無かったので、色々調べて半信半疑でやってみたら、うまく行ってしまったのでこういうことになったわけです。

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Listとゆかいなクラスたち

はじめに

前の記事でコメントを頂いたのでちょっと書いてみようという気になったことを書いてみます。
Java の List 関連のクラスについて、普段仕事をしている中で他人のソースコードを見ていると、意識している人は少ないのかなぁ・・・と思っていることについてです。

List 配下のクラスと当記事の記載対象

List インタフェースを実装したクラスにはここの「既知のすべての実装クラス」に記載されている通り、いろいろなものがあります。
その中でも比較的有名(?)な以下3クラスについて書いてみようと思います。
・ArrayList
・LinkedList
・Arrays$ArrayList
(これら以外については私は使ったことないのでよく知らない)

ArrayList

initialCapacity

ArrayList はみなさんよく使うクラスなのでご存知だと思いますが、initialCapacity を意識したことはありますか?
ArrayList のインスタンスを生成するときに一番見る書き方はこれでしょう。

Capacity.java
List<?> list = new ArrayList<>()

一方で、こんな形でインスタンス生成できることはご存知でしょうか?

Capacity.java
List<?> list = new ArrayList<>(100)

コンストラクタの引数に int の 100 を指定しています。この100が initialCapacity です。ArrayList に初期設定する要素数を指定しています。引数を指定しなかった場合はどうなるのか?ArrayList のソースを見てみましょう。

ArrayList.class(一部を抜粋:コンストラクタ1)
    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};


    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

何やら空の配列を elementData に格納しています。これだけだとよくわからないですね。次に add() メソッドの中身を見てみます。

ArrayList.class(一部を抜粋:add周辺)
    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

add() 直後に ensureCapacityInternal() メソッドを呼び出しています。ensureCapacityInternal() の中では minCapacity を設定した上で ensureExplicitCapacity() メソッドを呼び出しています。コンストラクタで initialCapacity を設定しなかった場合、先に見たとおり elementData には DEFAULTCAPACITY_EMPTY_ELEMENTDATA(空の配列)が設定されているので if文の条件を満たし、「minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity)」が行われます。結果、minCapacity に 10 (DEFAULT_CAPACITY) が設定され、それを ensureExplicitCapacity() に渡しています。
ensureExplicitCapacity() は配列の容量を確保しに行くメソッドです。つまり ArrayList のコンストラクタに引数を設定しなかった場合、ArrayList に格納される要素は要素数10個の配列で管理されることになります。
じゃあ、initialCapacity を指定した方のコンストラクタはどうなっているのか?

ArrayList.class(一部を抜粋3)
    /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

0以外の整数を指定した場合は空の配列ではなく、指定した要素数分の配列を生成しています。add()したときの挙動は、ensureCapacityInternal() メソッドのif文の中を通らないだけで基本的には同じです。

initialCapacity を指定する意味は?

initialCapacity を指定することに何の意味があるのでしょうか?それは initialCapacity で指定した数を超えた要素を追加した際の挙動を見るとわかります。
実装部分はこれです(ensureCapacityInternal() の続き)。

ArrayList.java(抜粋)
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

ensureExplicitCapacity() メソッドの中で、条件を満たした場合に grow() メソッドを呼び出しています。grow() メソッドのint newCapacity = oldCapacity + (oldCapacity >> 1);のところがポイントで、要素を追加したことで initialCapacity で確保した要素数を超えた場合は容量を1.5倍しています(端数切捨て)。
※">>"はシフト演算です。こちら参照
では、initialCapacity に10を設定した ArrayList に対して、ループしながら1個ずつ、合計100個の要素を追加した場合、elementData の要素数はどのように変化していくのでしょうか?

初期値:10
11個目の要素を追加:10*1.5=15
16個目の要素を追加:15*1.5=22
23個目の要素を追加:22*1.5=33
34個目の要素を追加:33*1.5=49
50個目の要素を追加:49*1.5=73
74個目の要素を追加:73*1.5=109
ここでやっと100個の要素を追加することができました。

initialCapacity の設定による性能の違い

この動きって、何かオーバーヘッド発生しそうですよね?どれほどのものなのでしょうか?
10万件のデータをループしながらadd()したときの実行時間を実測してみました。
実測に使ったプログラムはこれです。

DefaultListSize.java
import java.util.ArrayList;
import java.util.List;

public class DefaultListSize {
    private static final int CNT = 100000;
    public static void main(String... args) {
        // initialCapacity 指定なし
        List<Integer> defaultList = new ArrayList<>();

        long startDefautl = System.currentTimeMillis();
        for (int i = 0; i < CNT; i++) {
            defaultList.add(i);
        }
        long endDefautl = System.currentTimeMillis();
        System.out.println("実行時間(ミリ秒):" + (endDefautl - startDefautl));

        // initialCapacity 指定
        List<Integer> list = new ArrayList<>(CNT);
        long start = System.currentTimeMillis();
        for (int i = 0; i < CNT; i++) {
            list.add(i);
        }
        long end = System.currentTimeMillis();
        System.out.println("実行時間(ミリ秒):" + (end - start));
    }
}
実行結果
実行時間(ミリ秒):4
実行時間(ミリ秒):1

initialCapacity を指定しなかった場合は4ミリ秒で、10万を指定した場合は1ミリ秒でした。
因みに1千万を指定した場合、731ミリ秒と258ミリ秒でした。
PCのスペックも関係するので秒数に関しては何とも言えないですが、initialCapacity を指定することで余計な処理がなくなり、その分高速になるということがわかります。
大量データを扱うことがわかっているのであればちゃんと指定したほうが良さそうですね。

LinkedList

特徴

次は LinkedList です。LinkedList は、要素の追加・削除は得意ですが、ランダムアクセスが苦手という特徴があります。ランダムアクセスというのはソースコードレベルで言うとlist.get(i)のことです。
この特徴の原因は要素管理の仕方にあります。i番目の要素にi-1番目とi+1番目へのリンクを張るという形で管理されています。要素を取得する際は先頭または末尾からリンクをたどり、削除する場合はリンクを付け替えるだけです。

image.png

image.png

ArrayList と比較することで違いが明確になると思います。
ArrayList は index を使用して直接要素を取得することができるのでランダムアクセスが得意です。

image.png

逆に削除する場合は配列を再構築する必要があるためオーバーヘッドがかかります。

image.png

ランダムアクセスの挙動の違い

この特徴が原因で、ランダムアクセス時の挙動が ArrayList と LinkedList で異なったものになります。
ArrayList の場合、list.get(i) でランダムアクセスしたとしても、要素を即座に取得することができるため、即時応答することができます。
こんなイメージです。

image.png

LinkedList の場合、先頭の要素から順番にたどっていかないと目的の要素を取得することができません。list.get(4)と書いたとしたら1→2→3→4の順にたどってやっと目的の要素にたどり着きます。
こんなイメージです。

image.png

LinkedList は逆順に走査することも可能なので、上記の例でlist.get(7)としたらきっと10→9→8→7の順にたどってくれます。

大量データをループした時の性能は?

ここまでだと「ふーん。で?」だと思います。じゃあ、大量データをループさせてlist.get(i)したらどうでしょうか?
具体的に言うと、以下のようなクラスがあったとして、このメソッドを呼び出す際の引数に大量データを保有する LinkedList を渡されたらどうなるかわかりますか?
ループしながら list.get(i) している点がポイントです。

ListSizeLoop.java
class ListSizeLoop {
    public void listSizeLoop(List<String> list) {
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

こんな記事を見つけました。まさにこれです。こういう事が起こりえます。
軽い気持ちでLinkedListを使ったら休出する羽目になった話

どうすればいいの?

先の記事にもありましたが、list.size() でループするのではなく、拡張for(又は Iterator)を使いましょう。
Listに対して(正確にいうと、Iterable インタフェースを implements しているクラスに対して)拡張forを使うと内部的に Iterator が展開されるようになっています。
Iterator はデザインパターンの一つで、順次処理に特化したインタフェースです。これだけでランダムアクセスを回避できます。
list.size() を使ってループするとこういう事が起こり得るので、明確な理由がない限りは拡張forを使うようにしましょう。

Arrays$ArrayList

Arrays$ArrayList は固定長の List

最後は Arrays$ArrayList です。
ArrayList という名前がついていますが、よく知られているjava.util.ArrayListとは別物です。java.util.Arrays クラスの中に ArrayList という名前のインナークラスが存在しており、List インタフェースを implements しています("$"はインナークラスであることを示すJavaの予約語です)。
これは配列を List に変換したり、インスタンス生成時にあらかじめ要素を指定する場合に便利な List で、固定長を前提にしています。
使い方としては以下のようなイメージになります。

ArraysAsList.java
import java.util.Arrays;
import java.util.List;

public class ArraysAsList {
    public static void main(String... args) {
        String[] strList = new String[3];
        strList[0] = "a";
        strList[1] = "b";
        strList[2] = "c";
        // 配列をListに変換
        List<String> list1 = Arrays.asList(strList);
        for (String str : list1) {
            System.out.println(str);
        }

        // 始めから要素を保有したListを生成
        List<String> list2 = Arrays.asList("d", "e", "f");
        for (String str : list2) {
            System.out.println(str);
        }
    }
}

add() するとどうなるのか?

先ほど固定長を前提にしていると書きましたが、add()するとどうなるのでしょうか?

ArraysAsList2.java
import java.util.Arrays;
import java.util.List;

public class ArraysAsList2 {
    public static void main(String... args) {
        // インスタンス生成後にadd()メソッド呼び出し
        List<String> list = Arrays.asList("d", "e", "f");
        list.add("a");
        for (String str : list) {
            System.out.println(str);
        }
    }
}
実行結果
Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)
    at ArraysAsList2.main(ArraysAsList2.java:8)

UnsupportedOperationException が発生しました。ちょっと Arrays$ArrayList を見てみましょうか。

Arrays.java
public class Arrays {
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

    /**
     * @serial include
     */
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        @Override
        public int size() {
            return a.length;
        }

        @Override
        public Object[] toArray() {
            return a.clone();
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }

        @Override
        public E get(int index) {
            return a[index];
        }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

        @Override
        public int indexOf(Object o) {
            E[] a = this.a;
            if (o == null) {
                for (int i = 0; i < a.length; i++)
                    if (a[i] == null)
                        return i;
            } else {
                for (int i = 0; i < a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

        @Override
        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }

        @Override
        public Spliterator<E> spliterator() {
            return Spliterators.spliterator(a, Spliterator.ORDERED);
        }

        @Override
        public void forEach(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            for (E e : a) {
                action.accept(e);
            }
        }

        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            Objects.requireNonNull(operator);
            E[] a = this.a;
            for (int i = 0; i < a.length; i++) {
                a[i] = operator.apply(a[i]);
            }
        }

        @Override
        public void sort(Comparator<? super E> c) {
            Arrays.sort(a, c);
        }
    }
}

add()メソッドが見当たりません。上位クラスでしょうか? AbstractList を extends しているのでちょっと見てみましょう。

AbstractList.java
    public boolean add(E e) {
        add(size(), e);
        return true;
    }

    /**
     * {@inheritDoc}
     *
     * <p>This implementation always throws an
     * {@code UnsupportedOperationException}.
     *
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @throws IllegalArgumentException      {@inheritDoc}
     * @throws IndexOutOfBoundsException     {@inheritDoc}
     */
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

これですね。問答無用で UnsupportedOperationException を throw しています。
AbstractList は他にも ArrayList や Vector、AbstractSequentialList でも extends しています。LinkedList は AbstractSequentialList を extends しているので間接的に AbstractList の配下にいます。
文字で書いてもよくわからないと思いますが、以下の図を見れば AbstractList 配下であることがわかると思います。

image.png

java.util.ArrayList との違い(実装面)

Arrays$ArrayList 以外で AbstractList を extends しているクラスの例の一つとして、ちょっと ArrayList を覗いてみましょう。

ArrayList.java(add部分を抜粋)
    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

add() メソッドをオーバーライドしてますね。java.util.ArrayList は AbstractList の add() をオーバーライドしているから UnsupportedOperationException は発生せず、実装された処理が行われます。Arrays$ArrayList は add() メソッドをオーバーライドしていないため、UnsupportedOperationException が発生します。同じ ArrayList という名前がついているのに全然違いますね・・・。
AbstractList は List インタフェースを一部 implements しているものです。必要最低限の実装をすることで具象クラスとして実装が必要な部分を減らしているのですが、set(), add(), remove() に関してはオーバーライドしないと UnsupportedOperationException を throw するようになっています。
Arrays$ArayList は add() だけではなく remove() もオーバーライドしていないため、同じことが起きます。set() はオーバーライドしているので、このメソッドを呼び出すことで既存の要素を別のものに入れ替えることができます。

配列を可変長の List に変換したい場合

add() と remove() が呼び出せないので Arrays$ArayList は固定長となっています。もし配列を可変長の List に変換したい場合は以下のようにしましょう。

ArraysAsList3.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ArraysAsList3 {
    public static void main(String... args) {
        String[] strList = new String[3];
        strList[0] = "a";
        strList[1] = "b";
        strList[2] = "c";
        // ArrayListのコンストラクタを経由して配列をListに変換
        List<String> list = new ArrayList<>(Arrays.asList(strList));
        for (String str : list) {
            System.out.println(str);
        }
    }
}

List<String> list = new ArrayList<>(Arrays.asList(strList));という記述で、配列 → Arrays$ArrayList → ArrayList の順に変換しています。
ArrayList のコンストラクタには、先に紹介した initialCapacity と別にもう一つ、Collection を受け取るコンストラクタが存在します。このコンストラクタを使うことで、java.util.ArrayList に変換することができます。
AbstractList は AbstractCollection を extends しており、AbstractCollection は Collection を implements しているため、このコンストラクタの引数に Arrays$ArrayList を渡すことができます。
これもさっきの図を見たほうがわかりやすいと思います。

image.png

Collection を受け取る ArrayList のコンストラクタの実装は以下のようになっています。

ArrayList(コンストラクタを一部抜粋)
    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

私がまだ Java を使いはじめて間もない頃、Arrays$ArrayList を java.util.ArrayList と同じものだと勘違いしていてかなり混乱したことがあったので記載させて頂きました。

終わりに

List について思いついたことをつらつらと書いた感じになってしまいました。「あ、そうだったんだ!?」という気付きが一つでもあったら幸いです。
以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Androidアプリ作成でつまづいた点

こんにちは、ハイノです。

初めてAndroidアプリ開発を行っているのでつまづいた点を備忘録として投稿します。
今回の投稿では、つまづいた点を随時更新形式で列挙していくものです。
解決策はまた、見つけた場合に別記事で投稿する形にしたいと考えています。

Androidアプリ開発初心者がつまづくポイントは同じところが多いと予想していますので、
同じく初めてAndroidアプリ開発を行うという方にも私がつまづいた点を共有できれば
と考えています。
また、「ここでつまづいたときの解決策はこんなのがあるよ」ってコメントを頂けると
非常にありがたいです。
では、以下につまづきポイントを列挙していきます。

つまづきポイント

1.xmlでlayoutを作成しているときにGUIの設定に頼って画面サイズに対応できないこと
2.TwitterAPIの通信方法
3.JSONのパース方法
4.Listener
5.Fragment

解決方法

随時更新

開発環境

Android Studio 3.4.1

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Androidアプリ作成でつまづいた点【随時更新】

こんにちは、ハイノです。

初めてAndroidアプリ開発を行っているのでつまづいた点を備忘録として投稿します。
今回の投稿では、つまづいた点を随時更新形式で列挙していくものです。
解決策はまた、見つけた場合に別記事で投稿する形にしたいと考えています。

Androidアプリ開発初心者がつまづくポイントは同じところが多いと予想していますので、
同じく初めてAndroidアプリ開発を行うという方にも私がつまづいた点を共有できれば
と考えています。
また、「ここでつまづいたときの解決策はこんなのがあるよ」ってコメントを頂けると
非常にありがたいです。
では、以下につまづきポイントを列挙していきます。

つまづきポイント

1.xmlでlayoutを作成しているときにGUIの設定に頼って画面サイズに対応できないこと
2.TwitterAPIの通信方法
3.JSONのパース方法
4.Listener
5.Fragment

解決方法

随時更新

開発環境

Android Studio 3.4.1

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC - 133- A&B&C&D

AtCoder ABC 133 A&B&C&D

AtCoder - 133

A - T or T

    private void solveA() {
        int n = nextInt();
        int a = nextInt();
        int b = nextInt();

        out.println(n * a > b ? b : n * a);
    }

B - Good Distance

  • $(i < j)$ の条件を忘れないように
    private void solveB() {
        int n = nextInt();
        int d = nextInt();
        int[][] wk = Stream.generate(() -> IntStream.range(0, d).map(i -> nextInt()).toArray()).limit(n)
                .toArray(int[][]::new);

        int res = 0;
        for (int i = 0; i < n; i++) {
            //i < jに注意
            for (int j = i + 1; j < n; j++) {
                long tmp = 0;
                for (int k = 0; k < d; k++) {
                    tmp += Math.pow(wk[i][k] - wk[j][k], 2);
                }
                long tmpRes = (long) Math.sqrt(tmp);
                if (Math.pow(tmpRes, 2) == tmp) {
                    res++;
                }
            }
        }

        out.println(res);
    }

C - Remainder Minimization 2019

  • 最大(r)を減らせばなんとかなる?
    • mod 2019 なので、数値は0 - 2018を繰り返す
      • lを起点として0-2018を繰り返す
      • $lからr$まで全て試すのではなく、$lからmin(l+(2019*2),r)$の小さい方までを試せばよい
        • $0,1,2・・・2018,0,1,2,・・・2018$ まで試せれば最小値である0,0の組み合わせを選択できる
    • 二つの数値の理想的な最小は0,0の組み合わせ
      • r-lが2019*2より大きい場合
      • r-lが2019*2より小さい場合はその限りではない
    private void solveC() {
        final int CONST_MOD = 2019;
        int l = nextInt();
        int r = nextInt();
        /*
         * とりあえず最大を減らさないと何もできない。
         * l+2019かrかどちらか小さいほうを最大値として採用(MODなので)
         * l+2019で1周期。ただ、これだと最小値が1回しか出てこない。
         * +(2019*2)2周しておけば1が2回出てくる。
         *
         */
        int wkR = Math.min(l + (CONST_MOD * 2), r);
        int res = 2020;
        for (int i = l; i <= wkR; i++) {
            for (int j = i + 1; j <= wkR; j++) {
                res = Math.min(((i % CONST_MOD) * (j % CONST_MOD)) % CONST_MOD, res);
            }
        }

        out.println(res);
    }

D - Rain Flows into Dams

  • 連立方程式を立てて解いた
    • ダムの送料を計算して、どこか一つの山の雨を求める
    • どこか一つの山が決まれば他も決めることができる
    • 山の数は奇数なので、1 -> 3 -> 5 -> 7 -> 9 ・・・と増える
      • 常に二つずつ山が増えるので、式は次のように+-を繰り返す
        • 山A = ダム1 - ダム2 + ダム3 - ダム4 + ダム5 - + - + - + ・・・

例:2

ダム 3 8 7 5 5
a B C D E
2 4 12 2 8
      ダム1 = A/2 + B/2  ->  ダム1*2 = A + B  ->  B =  ダム1*2 - A
      ダム2 = B/2 + C/2  ->  ダム2*2 = B + C  ->  C =  ダム2*2 - B
      ダム3 = C/2 + D/2  ->  ダム3*2 = C + D  ->  D =  ダム3*2 - C
      ダム4 = D/2 + E/2  ->  ダム4*2 = D + E  ->  E =  ダム4*2 - D
      ダム5 = E/2 + A/2  ->  ダム5*2 = E + A  ->  A =  ダム5*2 - E

      上の式を変形してまず山Aを求める
      A = ダム1 - ダム2 + ダム3 - ダム4 + ダム5

      Aが決まれば山B以降は決まる
      B = ダム1*2 - A
      C = ダム2*2 - B
      D = ダム3*2 - C
      E = ダム4*2 - D
    private void solveD() {
        int n = nextInt();
        int[] wk = IntStream.range(0, n).map(i -> nextInt()).toArray();

        long a = 0;

                //偶数番目のダムは+、奇数番目のダムは-
        for (int i = 0; i < wk.length; i++) {
            if (i % 2 == 0) {
                a += wk[i];
            } else {
                a -= wk[i];
            }
        }
        long[] mountain = new long[n];
        mountain[0] = a;
        //最後のヤマは山Aのことなので除外
        for (int i = 0; i < mountain.length - 1; i++) {
            mountain[i + 1] = wk[i] * 2 - mountain[i];
        }
        StringBuilder builder = new StringBuilder();
        for (long l : mountain) {
            builder.append(l + " ");
        }
        out.println(builder.toString().trim());
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

天使が舞い降りる ・・・IBMとクラウドと 2019/07 中盤

最近の話題

AzureがAWSを追い越したってことです。
Azureの話を認識したのは去年のはじめくらいでした。
駅の画像で大企業がAzure使ってるのをみて・・・おおって思ったね。
AWSの凋落がここから始まるという人もいるけれど・・・そうでもないことを祈ります。
JavaとかPythonとかやるんだったらAWSの方が使いやすいような気がしてるんで・・・

クラウドに期待すること

プログラマー目線で見れば一人の人間がやれる範囲が増えるんじゃないかと思います。
自由度が上がるんじゃないかと思うね。

IBM Developer Dojo

IBMさんが意欲的な取り組みをしているらしいです。以下 connpassでの説明

IBM Developer Dojo は毎週水曜日をベースに開発者向けイベントを開催しています。 人気のコンテンツを集め、約8週間でクラウドの基礎から応用まで学べるコースになっています。
イベント情報を順次追加していきますので、皆様のご参加をお待ちしております。
https://ibm-developer.connpass.com/

すごい人がアメリカ?から来るらしい。

https://ibm-developer.connpass.com/event/139025/
Linuxカーネル開発者やLinux Foundation COOが来るらしいし
https://ibm-developer.connpass.com/event/138242/
DockerとKubernetesのメンテナーかつKnativeのオファリングマネージャーが解説 !
だそうです。
どちらも7月19日と7月23日で知らせも急に来たので本当に驚いたし、もうちょっと前に知らせてくれたら
休みをそちらに振り分けることもできたのにすごい残念。
英語に触れる貴重な機会だしね。
なんか事情があって大物たちが来ているのかと思うのも楽しいかも・・・・

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC - 132- A&B&C&D

AtCoder ABC 132 A&B&C&D

AtCoder - 132

Dのcombinationのバグが取れないのでD以降は後回し。

A - Fifty-Fifty

  • 文字をカウントしたら必ず二つないといけない
    private void solveA() {
        String[] a = next().split("");

        Map<String, Long> memo = Arrays.stream(a).collect(Collectors.groupingBy(s -> s, Collectors.counting()));

        for (long elm : memo.values()) {
            if (elm != 2) {
                out.println("No");
                return;
            }
        }
        out.println("Yes");
    }

B - Ordinary Number

  • $p_{i−1}, p_i, p_{i+1}$ の 3 つの数の中で、$p_i$ が 2 番目に小さい
    • 上記を満たせばよいので、$p_{i−1}< p_i< p_{i+1}$ または $p_{i+1} < p_i< p_{i−1}$ を確認する。
    private void solveB() {
        int n = nextInt();
        int[] p = IntStream.range(0, n).map(i -> nextInt()).toArray();

        int res = 0;
        for (int i = 0; i < p.length - 2; i++) {
            if ((p[i] < p[i + 1] && p[i + 1] < p[i + 2]) || (p[i + 2] < p[i + 1] && p[i + 1] < p[i])) {
                res++;
            }
        }

        out.println(res);
    }

C - Divide the Problems

  • ソートして
  • ARC用とABC用の問題の境目の数を抜き出す
  • 境目の数の差が選択可能な数
    private void solveC() {
        int n = nextInt();
        int[] d = IntStream.range(0, n).map(i -> nextInt()).sorted().toArray();

        out.println(d[n / 2] - d[n / 2 - 1]);
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC - 132- A&B&C

AtCoder ABC 132 A&B&C

AtCoder - 132

Dのcombinationのバグが取れないのでD以降は後回し。

A - Fifty-Fifty

  • 文字をカウントしたら必ず二つないといけない
    private void solveA() {
        String[] a = next().split("");

        Map<String, Long> memo = Arrays.stream(a).collect(Collectors.groupingBy(s -> s, Collectors.counting()));

        for (long elm : memo.values()) {
            if (elm != 2) {
                out.println("No");
                return;
            }
        }
        out.println("Yes");
    }

B - Ordinary Number

  • $p_{i−1}, p_i, p_{i+1}$ の 3 つの数の中で、$p_i$ が 2 番目に小さい
    • 上記を満たせばよいので、$p_{i−1}< p_i< p_{i+1}$ または $p_{i+1} < p_i< p_{i−1}$ を確認する。
    private void solveB() {
        int n = nextInt();
        int[] p = IntStream.range(0, n).map(i -> nextInt()).toArray();

        int res = 0;
        for (int i = 0; i < p.length - 2; i++) {
            if ((p[i] < p[i + 1] && p[i + 1] < p[i + 2]) || (p[i + 2] < p[i + 1] && p[i + 1] < p[i])) {
                res++;
            }
        }

        out.println(res);
    }

C - Divide the Problems

  • ソートして
  • ARC用とABC用の問題の境目の数を抜き出す
  • 境目の数の差が選択可能な数
    private void solveC() {
        int n = nextInt();
        int[] d = IntStream.range(0, n).map(i -> nextInt()).sorted().toArray();

        out.println(d[n / 2] - d[n / 2 - 1]);
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ナンプレ解答アプリ「ナンプレ自動解答」(Android版)とその実装機能の紹介

よちよちサンデープログラミングトップへ

はじめに

「ナンプレ自動解答」(Android版)は、ナンプレ(数独)の問題を写真に撮ると、その問題を自動的に解き、答えを示すアプリです。
そのため、例えばナンプレの懸賞本の大量の問題を解く時間を短縮したり、解答が載っていない問題の答えを確認したり、あるいは自作した問題が正しく答えを導き出せるものであるかどうかを確認したりするのに使えます。
ナンプレ自動解答画面

本記事では、ナンプレ自動解答で実装している各機能をTipsとして解説します。

  • アプリのダウンロードは、こちら
  • プロジェクトソースの入手は、こちら
  • iOS版「ナンプレ自動解答」の解説記事は、こちら

開発・実行環境

ナンプレ自動解答は、以下の環境で開発・実行しています。

  • 開発環境 : macOS、Android Studio(3.3~3.4)、Java
  • 実行環境 : Android 5.0以上

アプリの構成の概要

ナンプレ自動解答は、2つの画面を持ちます。1つは、ナンプレの問題(9x9のマス目や各マスの数字)を表示し、数字を編集するため操作を受け付ける独自ビューと、機能を呼び出す複数のボタンと、広告(AdMob)が表示されます。もう1つは、ナンプレの問題を写真に撮るためのCamera2 APIを使ったカメラ画面です。
本アプリでは、カメラで撮影した写真から、ナンプレの問題(9x9のマス目)を切り出し、さらにその各マスの数字を認識し、解答処理を行う対象データとして取り込みますが、マス目の切り出しにはOpenCVを使い、数字の認識にはOCRライブラリ(tess-two)を使っています。

実装している機能

本アプリを実現するために、以下の機能を実装しており、それぞれTipsとして解説していきます。
※リンクをクリックするとTips解説記事に飛びます。リンクされていない項目は、記事を鋭意作成中です。

  • AdMobを組み込む(AdMob SDK)
  • 広告を表示する(AdMob SDK)
  • OpenCVライブラリを組み込む
  • 写真から、四角形領域を切り出す(OpenCV)
  • OCRライブラリを組み込む(tess-two)
  • OCR機能で文字を認識する(tess-two)
  • アセットに格納しているデータをファイルに書き出す
  • 独自ビューを生成する(FrameLayout、View)
  • 独自ビューに描画する(View)
  • 画面レイアウト決定後に、ビューを再描画する(FrameLayout)
  • 独自カメラ機能を実装する(Camera2)
  • ユーザからカメラの利用許可を得る
  • 画面(アクティビティ)間でデータをやり取りする(Intent)
  • 画像(Bitmap)をファイルに保存する(FileOutputStream)
  • 画像(Bitmap)の一部を切り出す
  • 非同期処理(別スレッド処理)をする(AsyncTaskLoader)
  • 処理待ちのインジケータ(くるくる)を表示する・消す(ProgressBar)
  • アプリのバージョン番号を取得する(PackageManager)
  • メニューを表示する(Menu)
  • ボタンの形状をカスタマイズする(Button)
  • 多言語対応する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SQL Error [08001]: Public Key Retrieval is not allowedの対処法 [JDBC:MySQL]

ローカル環境
・データベース:MySQL 8.0.16
・言語:Java
・JDBCドライバ:mysql-connector-java-8.0.16
・DB参照ツール:DBeaver

DB接続しようとしたら、複数のエラーが発生

JavaからDB接続しようとしたところ、突如繋がらなくなった。
eclipseのコンソールでは下記のエラー記述が。

com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet successfully received from the server was 25 milliseconds ago. 
The last packet sent successfully to the server was 28 milliseconds ago.

DBeaverからも接続を試みると、下記のエラー記述が。

SQL Error [08001]: Public Key Retrieval is not allowed

検索をかけて下記の記事を見て解決できました。
https://stackoverflow.com/questions/50379839/connection-java-mysql-public-key-retrieval-is-not-allowed

JDBCドライバのプロパティ「allowPublicKeyRetrieval」をtrue、「useSSL」をfalseにする

DBeaver:
1. 「データベースナビゲータ」の該当接続を右クリックし、「編集 Connection」を押す。
2. 「接続設定」 > 「ドライバのプロパティ」を選択。
3. 「allowPublicKeyRetrieval」をtrueに変更。
4. 「useSSL」をfalseに変更。(ちなみに自分は元々falseになっていたので対応不要だった)
5. 「OK」を押す。

Javaコード:
1. データベース接続文字列に「allowPublicKeyRetrieval=true&useSSL=false」を追加。
<記入例>

sample.java
String database = "jdbc:mysql://localhost:3306/sample_db?allowPublicKeyRetrieval=true&useSSL=false";
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む