20190522のJavaに関する記事は14件です。

【Java】Progateで取り上げられていないJavaの基本まとめ~その2~

リスト(ArrayList)

Progateでは配列については取り上げられているが、リストについては触れられていない。
配列とリストは似ているが何が違うのか?

配列の特徴

・最初から要素数が固定されており、メモリを確保する
・用意した要素数が連続した領域にメモリとして確保される
・インデックスを利用してメモリアドレスを直接指定できるため、アクセスが速い
・途中で要素の挿入や追加といったことは、元にあった要素をずらす必要があり大変

リストの特徴

ーリストは配列によく似ており、値の集合を扱うために利用する。
 ただし、リストは要素が追加された順番を保持し、重複した要素もそのまま保持することが可能。
・要素数を可変できる
・前後にポインタが付与されポインタで接続されながら空いているメモリ領域に要素が格納されていく
・要素にアクセスするには先頭からポインタをたどる必要があり時間を要する
・途中で要素の挿入、追加といったことは、ポインタの接続を変えるだけなので速い

リストの書き方

ArrayList<> リスト名 = new ArrayList<>();

例えば、

ArrayList<String> strList = new ArrayList<String>();

とするとstrListにStringの要素を格納できる。
リストの要素は参照型である必要があるため、Stringを要素に持つことはできても
intのような基本データ型を要素に持つリストは作成できない。

リストの例①

リストの追加

public static void main(String[] args) {

  // Stringの要素を格納するためのリストを用意
  List<String> strList1 = new ArrayList<String>();

  strList1.add("広島");
  strList1.add("東京");
  strList1.add("横浜");

  // 追加した順にリストに入る
  System.out.println(strList1);
}

実行結果

["広島", "東京", "横浜"]

リストの例②

要素の更新

public static void main(String[] args) {

  // Stringの要素を格納するためのリストを用意
  List<String> strList2 = new ArrayList<String>(3);

  strList2.add("近鉄");
  strList2.add("オリックス");
  strList2.add("西武");

  // 追加した順にリストに入る
  System.out.println("更新前" + strList2);

  // 1番目の要素を"楽天"に上書きする
  strList2.set(1, "楽天");

  // 上書き後のリスト("近鉄"→"楽天"になっている)
  System.out.println("更新後" + strList2);
}

実行結果

更新前[近鉄、オリックス、西武]
更新後[楽天、オリックス、西武]

リストの例③

リストの値の取得

リストから値を取得するには.getメソッドを使う。

public static void main(String[] args) {

  // Stringの要素を格納するためのリストを用意
  List<String> strList3 = new ArrayList<String>(3);

  strList3.add("中日");
  strList3.add("阪神");
  strList3.add("読売");

  // リストから2番目の値を取得して表示 
  System.out.println(strList3.get(2));
 }

実行結果

阪神

こんな感じ。

余談

初心者向けの辞書的ポジの参考書として個人的に位置付けた、
こちらの本にはリストについては一切記載がありませんでした。
https://www.amazon.co.jp/%E6%96%B0%E3%83%BB%E6%98%8E%E8%A7%A3Java%E5%85%A5%E9%96%80-%E6%9F%B4%E7%94%B0-%E6%9C%9B%E6%B4%8B-ebook/dp/B01HYSUY92
Progateにもあえて収録しておらず、こうした初心者向け書籍も触れていないくらいなので
実務的には使える必要があることを知っていつつも学習初段階で無理して知らなくても良い知識かもしれない。

私自身初学者で、自身の学習メモとして記事を書いていますので、
間違っているところがたくさんあると思われますので、お気付きの点があればガンガン指摘してください。
よろしくお願いします。

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

ABC - 126 - A&B&C

AtCoder ABC 126 A&B&C

AtCoder - 126

A - Changing a Character

  • 慣れでこんな書き方したけど、改めて見直すと読みづらい???
    private void solveA() {
        int n = nextInt();
        int k = nextInt() - 1;
        StringBuilder builder = new StringBuilder(next());

        out.println(builder.replace(k, k + 1, builder.substring(k, k + 1).toLowerCase()).toString());
    }
  • うーーん。いまいち。。。
    private void solveA() {
        int n = nextInt();
        int k = nextInt();
        String[] wk = next().split("");
        wk[k - 1] = wk[k - 1].toLowerCase();

        String res = Arrays.stream(wk).collect(Collectors.joining(""));

        out.println(res);
    }

B - YYMM or MMYY

    private void solveB() {
        int wk = nextInt();

        int front = wk / 100;
        int back = wk % 100;

        if ((0 < front && front <= 12) && (back <= 0 || back > 12)) {
            out.println("MMYY");
        } else if ((0 < back && back <= 12) && (front <= 0 || front > 12)) {
            out.println("YYMM");
        } else if ((0 < front && front <= 12) && (0 < back && back <= 12)) {
            out.println("AMBIGUOUS");
        } else {
            out.println("NA");
        }

    }

C - Dice and Coin

  • 端数処理面倒なのでBigDecimalを利用

例1:
3面ダイスを振るので

1が出た場合、4回連続でコインの表がでる必要がある
1がでたら: $1×2×2×2×2 = 16$
確率: $ \frac{1}{3} × (\frac{1}{2})^4 $

2が出た場合、3回連続でコインの表がでる必要がある
2がでたら: $2×2×2×2 = 16$
確率: $ \frac{1}{3} × (\frac{1}{2})^3 $

3が出た場合、2回連続でコインの表がでる必要がある
3がでたら: $3×2×2 = 12$
確率: $ \frac{1}{3} × (\frac{1}{2})^2 $

総計(1が出た場合+2が出た場合+3が出た場合)としては以下
$ \frac{1}{3} × (\frac{1}{2})^4 + \frac{1}{3} × (\frac{1}{2})^3 +\frac{1}{3} × (\frac{1}{2})^2 = \frac{7}{48} $

くくって式を簡略化(実装時に端数処理を考えるのが面倒なので、割り算は最後に持っていく)
$ ((\frac{1}{2})^4 + (\frac{1}{2})^3 + (\frac{1}{2})^2) × \frac{1}{3} = \frac{7}{48} $

  • まとめると
    • コインの表を何回出すのかをそれぞれ計算して合算
      • 1が出た時、何回2倍すればよいのか
      • 2が出た時、何回2倍すればよいのか
      • 3が出た時、何回2倍すればよいのか
      • 以下、ダイスの面だけループ
    • 最後に、ダイスの面の数で割る
    • 小数点以下桁数は11桁くらいできっとけば大丈夫
    private void solveC() {
        int n = nextInt();
        int k = nextInt();

        BigDecimal res = new BigDecimal("0");
        for (int i = 1; i <= n; i++) {
            int pow = recursiveC(i, k);
            /*
             * コインの裏表は1/2なので0.5のn乗
             * ダイス面がiの時、0.5^pow
             */
            BigDecimal powB = new BigDecimal("0.5").pow(pow);
            //足しておく
            res = res.add(powB);
        }

        //最後、一括でダイス面で割る
        out.println(res.divide(new BigDecimal(n), 11, RoundingMode.HALF_UP));
    }

    /**
     * 何回×2したらnを超えるのかを返す
     * @param i
     * @param n
     * @return
     */
    private int recursiveC(int i, int n) {
        if (i >= n) {
            return 0;
        }
        return recursiveC(i * 2, n) + 1;
    }

D - Even Relation(BFS版)

参考サイト

AtCoder ABC 126 D - Even Relation (400 点)

  • 上記けんちょんさんの参考サイトにはDFSでの解法が載っています。そちらを参考にしました。
    • 自分でもDFSで解いたのがあるが、けんちょんさんのサイトの方が分かりやすいので自分のは載せない
  • 総当たりするでもなく、1つ根を決めてそこからの距離の偶奇で塗り分ける(説明観ないとわからんかったが)
  • 多分、ダイクストラでもいけるんじゃないか???今度試そう。
    private void solveD() {
        int n = nextInt();

        int[] u = new int[n - 1];
        int[] v = new int[n - 1];
        int[] w = new int[n - 1];

        /*
         * 辺のMapを作成
         */
        Map<Integer, List<Edge>> wk = new TreeMap<Integer, List<Edge>>();

        for (int i = 0; i < n - 1; i++) {
            Edge e = null;
            List<Edge> tmp = null;

            u[i] = nextInt() - 1;
            v[i] = nextInt() - 1;
            w[i] = nextInt();
            /*
             * コストは偶奇以外不要なのでmodしたけど別にしなくてもよかったよね。。。
             */
            int cost = w[i] % 2;
            e = new Edge();
            e.from = u[i];
            e.to = v[i];
            e.cost = cost;
            tmp = wk.getOrDefault(e.from, new ArrayList<Edge>());
            tmp.add(e);
            wk.put(e.from, tmp);

            e = new Edge();
            e.from = v[i];
            e.to = u[i];
            e.cost = cost;
            tmp = wk.getOrDefault(e.from, new ArrayList<Edge>());
            tmp.add(e);
            wk.put(e.from, tmp);
        }
        /*
         * BFS用のQueue
         */
        Deque<Edge> ek = new ArrayDeque<Edge>();
        /*
         * tree探索するための最初のqueの選択
         * なんでもよいわけではなくて、子が一つのものを選択
         * 頂点がN個で辺がN-1個なので、必ずこの条件にあてはまるものがいる。
         * while()の中で最初のqueueだけは自分の行き先を全て見ていないので。
         * まぁ、while()に入る前に位置0のedgeを全てqueueに入れておけば良いだけな気はしている。
         */
        for (List<Edge> edges : wk.values()) {
            if (edges.size() == 1) {
                ek.addLast(edges.get(0));
                break;
            }
        }
        //      ek.addLast(wk.get(0).get(0));
        int[] res = new int[n];
        //色の格納用
        res[0] = 0;
        while (!ek.isEmpty()) {
            Edge e = ek.removeLast();
            /*
             * costの偶奇で塗る色を決定
             */
            if (e.cost % 2 == 0) {
                //偶数ならfromもtoも同じ色
                res[e.to] = res[e.from];
            } else {
                //奇数ならfromと違う色にtoを塗る必要がある
                res[e.to] = 1 - res[e.from];
            }
            //toに子がいるのかの探索
            List<Edge> edges = wk.get(e.to);
            for (Edge edge : edges) {
                /*
                 * 親↔子が循環しないように
                 */
                if (e.from == edge.to) {
                    continue;
                }
                /*
                 * 探索対象なのでQueueにadd
                 */
                ek.addLast(edge);
            }
        }

        for (int resN : res) {
            out.println(resN);
        }

    }

    /**
     * 辺を表すためのinnerクラス
     */
    private static class Edge {
        private int from;
        private int to;
        private int cost;
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC - 126 - A&B&C&D

AtCoder ABC 126 A&B&C&D

AtCoder - 126

A - Changing a Character

  • 慣れでこんな書き方したけど、改めて見直すと読みづらい???
    private void solveA() {
        int n = nextInt();
        int k = nextInt() - 1;
        StringBuilder builder = new StringBuilder(next());

        out.println(builder.replace(k, k + 1, builder.substring(k, k + 1).toLowerCase()).toString());
    }
  • うーーん。いまいち。。。
    private void solveA() {
        int n = nextInt();
        int k = nextInt();
        String[] wk = next().split("");
        wk[k - 1] = wk[k - 1].toLowerCase();

        String res = Arrays.stream(wk).collect(Collectors.joining(""));

        out.println(res);
    }

B - YYMM or MMYY

    private void solveB() {
        int wk = nextInt();

        int front = wk / 100;
        int back = wk % 100;

        if ((0 < front && front <= 12) && (back <= 0 || back > 12)) {
            out.println("MMYY");
        } else if ((0 < back && back <= 12) && (front <= 0 || front > 12)) {
            out.println("YYMM");
        } else if ((0 < front && front <= 12) && (0 < back && back <= 12)) {
            out.println("AMBIGUOUS");
        } else {
            out.println("NA");
        }

    }

C - Dice and Coin

  • 端数処理面倒なのでBigDecimalを利用

例1:
3面ダイスを振るので

1が出た場合、4回連続でコインの表がでる必要がある
1がでたら: $1×2×2×2×2 = 16$
確率: $ \frac{1}{3} × (\frac{1}{2})^4 $

2が出た場合、3回連続でコインの表がでる必要がある
2がでたら: $2×2×2×2 = 16$
確率: $ \frac{1}{3} × (\frac{1}{2})^3 $

3が出た場合、2回連続でコインの表がでる必要がある
3がでたら: $3×2×2 = 12$
確率: $ \frac{1}{3} × (\frac{1}{2})^2 $

総計(1が出た場合+2が出た場合+3が出た場合)としては以下
$ \frac{1}{3} × (\frac{1}{2})^4 + \frac{1}{3} × (\frac{1}{2})^3 +\frac{1}{3} × (\frac{1}{2})^2 = \frac{7}{48} $

くくって式を簡略化(実装時に端数処理を考えるのが面倒なので、割り算は最後に持っていく)
$ ((\frac{1}{2})^4 + (\frac{1}{2})^3 + (\frac{1}{2})^2) × \frac{1}{3} = \frac{7}{48} $

  • まとめると
    • コインの表を何回出すのかをそれぞれ計算して合算
      • 1が出た時、何回2倍すればよいのか
      • 2が出た時、何回2倍すればよいのか
      • 3が出た時、何回2倍すればよいのか
      • 以下、ダイスの面だけループ
    • 最後に、ダイスの面の数で割る
    • 小数点以下桁数は11桁くらいできっとけば大丈夫
    private void solveC() {
        int n = nextInt();
        int k = nextInt();

        BigDecimal res = new BigDecimal("0");
        for (int i = 1; i <= n; i++) {
            int pow = recursiveC(i, k);
            /*
             * コインの裏表は1/2なので0.5のn乗
             * ダイス面がiの時、0.5^pow
             */
            BigDecimal powB = new BigDecimal("0.5").pow(pow);
            //足しておく
            res = res.add(powB);
        }

        //最後、一括でダイス面で割る
        out.println(res.divide(new BigDecimal(n), 11, RoundingMode.HALF_UP));
    }

    /**
     * 何回×2したらnを超えるのかを返す
     * @param i
     * @param n
     * @return
     */
    private int recursiveC(int i, int n) {
        if (i >= n) {
            return 0;
        }
        return recursiveC(i * 2, n) + 1;
    }

D - Even Relation(BFS版)

参考サイト

AtCoder ABC 126 D - Even Relation (400 点)

  • 上記けんちょんさんの参考サイトにはDFSでの解法が載っています。そちらを参考にしました。
    • 自分でもDFSで解いたのがあるが、けんちょんさんのサイトの方が分かりやすいので自分のは載せない
  • 総当たりするでもなく、1つ根を決めてそこからの距離の偶奇で塗り分ける(説明観ないとわからんかったが)
  • 多分、ダイクストラでもいけるんじゃないか???今度試そう。
    private void solveD() {
        int n = nextInt();

        int[] u = new int[n - 1];
        int[] v = new int[n - 1];
        int[] w = new int[n - 1];

        /*
         * 辺のMapを作成
         */
        Map<Integer, List<Edge>> wk = new TreeMap<Integer, List<Edge>>();

        for (int i = 0; i < n - 1; i++) {
            Edge e = null;
            List<Edge> tmp = null;

            u[i] = nextInt() - 1;
            v[i] = nextInt() - 1;
            w[i] = nextInt();
            /*
             * コストは偶奇以外不要なのでmodしたけど別にしなくてもよかったよね。。。
             */
            int cost = w[i] % 2;
            e = new Edge();
            e.from = u[i];
            e.to = v[i];
            e.cost = cost;
            tmp = wk.getOrDefault(e.from, new ArrayList<Edge>());
            tmp.add(e);
            wk.put(e.from, tmp);

            e = new Edge();
            e.from = v[i];
            e.to = u[i];
            e.cost = cost;
            tmp = wk.getOrDefault(e.from, new ArrayList<Edge>());
            tmp.add(e);
            wk.put(e.from, tmp);
        }
        /*
         * BFS用のQueue
         */
        Deque<Edge> ek = new ArrayDeque<Edge>();
        /*
         * tree探索するための最初のqueの選択
         * なんでもよいわけではなくて、子が一つのものを選択
         * 頂点がN個で辺がN-1個なので、必ずこの条件にあてはまるものがいる。
         * while()の中で最初のqueueだけは自分の行き先を全て見ていないので。
         * まぁ、while()に入る前に位置0のedgeを全てqueueに入れておけば良いだけな気はしている。
         */
        for (List<Edge> edges : wk.values()) {
            if (edges.size() == 1) {
                ek.addLast(edges.get(0));
                break;
            }
        }
        //      ek.addLast(wk.get(0).get(0));
        int[] res = new int[n];
        //色の格納用
        res[0] = 0;
        while (!ek.isEmpty()) {
            Edge e = ek.removeLast();
            /*
             * costの偶奇で塗る色を決定
             */
            if (e.cost % 2 == 0) {
                //偶数ならfromもtoも同じ色
                res[e.to] = res[e.from];
            } else {
                //奇数ならfromと違う色にtoを塗る必要がある
                res[e.to] = 1 - res[e.from];
            }
            //toに子がいるのかの探索
            List<Edge> edges = wk.get(e.to);
            for (Edge edge : edges) {
                /*
                 * 親↔子が循環しないように
                 */
                if (e.from == edge.to) {
                    continue;
                }
                /*
                 * 探索対象なのでQueueにadd
                 */
                ek.addLast(edge);
            }
        }

        for (int resN : res) {
            out.println(resN);
        }

    }

    /**
     * 辺を表すためのinnerクラス
     */
    private static class Edge {
        private int from;
        private int to;
        private int cost;
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

text as bitmap And New Line

テキストをBitmapにするやつがあるけど、改行とかどうするの?って時に。
あとはfeelingでなんとかして!

TextToBitmap.java
    public static Bitmap textAsBitmap(String text , float textSize , int textColor){
        Typeface font = getTypeface(); // Get Your Typeface
        Paint paint = new Paint();
        paint.setTextSize(textSize);
        paint.setTypeface(font);
        paint.setColor(textColor);
        paint.setTextAlign(Paint.Align.LEFT);
        float baseline = -paint.ascent();
        int width,height;
        String message = "";
        String[] splitList = text.split("\n"); // new Line!!
        if(splitList.length != 0){
            for (String s : splitList) {
                if (message.length() < s.length()) {
                    message = s;
                }
            }
            width = (int)(paint.measureText(message)+0.5f); // round
            height = (int)((baseline * splitList.length)+paint.descent()+0.5f);
        } else {
            width = (int)(paint.measureText(text)+0.5f); // round
            height = (int)(baseline+paint.descent()+0.5f);
        }
        Bitmap image = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(image);
        if(splitList.length != 0){
            for(int i = 0 ; i < splitList.length ; i++ ){
                canvas.drawText(splitList[i], 0, baseline * (i+1), paint);
            }
        } else {
            canvas.drawText(text, 0, baseline, paint);
        }
        return image;
    }

元ネタ
https://stackoverflow.com/questions/8799290/convert-string-text-to-bitmap

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

そういえばしれっと匿名クラス登場してたじゃんか

応プロでそういや登場してましたね。

button.addActionListener(
  new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent event){
      /* ここにボタンが押されたときの処理を記述 */
    }
  }
);

これについて。

匿名クラス

匿名クラスって言って、その場でさっくりクラスを作成できる書き方がある。

例えば、こんなインタフェースを設計してみる。

SampleInterface.java
interface SampleInterface{
    public void sampleMethod();
}

じゃ、コレの匿名クラスを生成してみる。

SampleInterface sample = new SampleInterface(){
    @Override
    public void sampleMethod(){
        System.out.println("Hello :-) ");
    }
}

sample.sampleMethod();
// >>> Hello :-) 

こんなして使える。

やってることとしては

ExampleClass.java
class ExampleClass implements SampleInterface{
    @Override
    public void sampleMethod(){
        System.out.println("Hello :-) ");
    }
}
SampleInterface sample = new ExampleClass();
sample.sampleMethod();
// >>> Hello :-) 

これと同じ。
わざわざ別ファイルでインターフェースを実装したクラスを作る手間が省ける。

何に使う?

これを使うと、他のクラスに処理そのものをブチ込める。

SampleClass.java
class SampleClass{
    private SampleInterface sampleInterface;

    public SampleClass(SampleInterface sampleInterface){
        this.sampleInterface = sampleInterface;
    }

    public void callInterfaceMethod(){
        sampleInterface.sampleMethod();
    }
}
SampleClass sample = new SampleClass(
    new SampleInterface(){
        @Override
        public void sampleMethod(){
            System.out.println("Hellooooooo!!!! :-) ");
        }
    }
);

sample.callInterfaceMethod()
// >>> Hellooooooo!!!! :-)

こんな感じ。

Javaを使ったフレームワークなんかだとしょっちゅう見かける。
ボタンの処理をしているクラスを変更することなく自分のしたい処理を差し込めるから、フレームワークの便利な処理をそのままにできるってこと。
Androidでもボタン押したときにやる処理なんかはこのパターンだし。


以上、リスナーパターンってやつのお話でした。

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

ABC - 007 - A&B&C

AtCoder ABC 007 A&B&C

AtCoder - 007

過去の問題ってとっても教育的なものがあって好きかも。
C問題とか。

A - 植木算

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

        out.println(n - 1);
    }

B - 辞書式順序

  • 辞書順だけ考慮すればいいのなら、常に"a"いれればいいよね
    • 入力が"a"の場合、辞書順で"a"より小さいものはないので-1を出力
    private void solveB() {
        String wk = next();

        if (wk.equals("a")) {
            out.println(-1);
        } else {
            out.println("a");
        }
    }

C - 幅優先探索

  • 幅優先探索(BFS)の教育的な問題

参考サイト

参考サイトを一通り読むのが一番

    private void solveC2() {
        int r = nextInt();
        int c = nextInt();
        int sX = nextInt() - 1;
        int sY = nextInt() - 1;
        int gX = nextInt() - 1;
        int gY = nextInt() - 1;

        char[][] map = new char[r][c];
        for (int i = 0; i < r; i++) {
            map[i] = next().toCharArray();
        }
        Deque<Cordinate> que = new ArrayDeque<Cordinate>();
        Cordinate start = new Cordinate();
        start.x = sX;
        start.y = sY;
        start.step = 0;
        /*
         * Queu(LIFO)として使うのでaddLast()
         */
        que.addLast(start);
        boolean[][] memo = new boolean[r][c];
        memo[sX][sY] = true;
        int res = bfs(map, que, r, c, gX, gY, memo);

        out.println(res);
    }

    private static class Cordinate {
        private int x;
        private int y;
        private int step;
    }

    private static final int[] vX = { 1, 0, 0, -1 };
    private static final int[] vY = { 0, 1, -1, 0 };

    private int bfs(char[][] map, Deque<Cordinate> que, int r, int c, int gX, int gY, boolean[][] memo) {

        while (!que.isEmpty()) {
            /*
             * Queu(LIFO)として使うのでremoveFirst()
             */
            Cordinate curr = que.removeFirst();
            if (curr != null) {
                if (curr.x == gX && curr.y == gY) {
                    return curr.step;
                }
                for (int i = 0; i < 4; i++) {
                    int wkX = curr.x + vX[i];
                    int wkY = curr.y + vY[i];
                    int step = curr.step + 1;
                    if (wkX >= 0 && wkX < r && wkY >= 0 && wkY < c && map[wkX][wkY] != '#' && !memo[wkX][wkY]) {
                        Cordinate newC = new Cordinate();
                        newC.x = wkX;
                        newC.y = wkY;
                        newC.step = step;
                        /*
                         * Queu(LIFO)として使うのでaddLast()
                         */
                        que.addLast(newC);
                        memo[wkX][wkY] = true;
                    }
                }
            }
        }
        return -1;
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WebViewとネイティブのメリットデメリット

App内で動作する簡易ブラウザ(WebView)と通信からUIまでアプリ内で完結するネイティブアプリのメリットデメリットをまとめてみました。

■WebViewのメリット・デメリット

メリット

  • コストが安い
    Web上にコンテンツがあり、それを流用したい場合、新規で開発することなく同じコンテンツを表示できます。

  • アプリストアへの申請・審査の不要
    ネイティブアプリの申請や審査が不要になります。
    ※ただし、部分的なWebView表示の場合ネイティブと変わらないので審査は必要です。

  • アプリアップデートの不要
    アプリの保守をする必要がないため、アプリ自体のアップデートがありません。
    ※仕様が変更された時は、アプリの動作を変更する可能性があるため、一概ではないです。

デメリット

  • 課金ができない
    Apple Store審査ガイドラインの規約違反になり、リジェクトされる恐れがあります。
    ※Webブラウザでの課金は可能(リンクをブラウザへ飛ばす必要あり)
    引用:Apple Store審査ガイドライン:3.1.1 App内課金

  • レスポンシブ対応
    画面解像度に応じたUI設計の対応が必要。
    Webの表示をそのまま、アプリに適応させると表示崩れが起こる可能性がある。

  • 脆弱性

    1. 自社以外の外部アクセス

      URL直打ちで、自社ではないサイトにアクセスできる場合、悪用される恐れがある。
      外部アクセスできるサイトに制限を設ける必要がある。

    2. 端末内のファイルストリームにアクセスできる

      「file://」で始まるURI(※URLではない)でアクセスすることで、端末内部のファイルにアクセスすることができる。
      アクセスログからユーザー情報が漏洩されてしまう。

    3. iOSは、Cookieを保存しない

      アプリが終了するとCookieが消えるので、永続化する必要がある

    4. XSSの恐れ

      攻撃スクリプトを入力できてしまう。
      サニタイジング(無害化)する必要がある。

  • 通信エラー場合の表示
    通信エラー場合のWebView画面を表示する前に、レスポンスチェックを行い、ネイティブの別画面を表示させる。
    WebViewは通信した結果の表示なので、真っ白になったり、URLエラーになったりしてUI的に作りが悪い。

  • 環境によっては表示が遅い
    Web通信が伴うため、通信環境によっては表示が遅い場合があります。

  • 導線が不可能
    WebViewの誘導はできない。
    alt

■ネイティブ画面のメリット・デメリット

メリット

  • Webではできない画面設計・操作設計ができる
    アプリ内のUIを使用するため、自由に画面設計を行うことが可能

  • 導線設計が可能
    アプリに誘導できる

  • セキュリティ
    URL直打ちではないため、外部のサイトへアクセスさせることはないです。

デメリット

  • コストが高い
    iOS / Androidの開発者が必要
    開発言語が異なるため、それぞれの開発者が必要

  • アプリストアへの申請・審査
    ネイティブアプリの申請や審査が必要です。

  • アプリアップデートが必要
    保守でアプリ修正があった場合は、アップデートが必要

  • 課金
    App内課金を(30%)手数料(30%)が発生する

引用

https://appbu.jp/webapps-nativeapps
https://ja.developer.box.com/docs/android-security-guidelines
https://appkitbox.com/knowledge/android/20130819-84
https://teratail.com/questions/100872
https://mexess.blog/2018/08/03/post-304/
https://qiita.com/noboru_i/items/240ffcb2036f3b5cbc3b
https://qiita.com/noboru_i/items/bc39d95638e9e55437fa#cookie%E3%81%AE%E8%A8%AD%E5%AE%9A
https://qiita.com/i_nak/items/be0fac91bdc68aa165db
https://backapp.co.jp/blog/11594/
https://support.ebis.ne.jp/search_service/15033/

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

best programming courses and tutorials

When it comes to learning a new skill, e-learning sources are preferred more than any physical institute these days. The basic reason is that they are full of convenience and have greater accessibility. Also, some of them are available for free and provides certifications too, so why should anyone visit and pay a whole lot of fees to these institutes.
Though having a degree or certification in a proper format enhances the credibility of your profile or resume. But again not everyone could sit into long lectures and learn a skill. People need flexibility in accordance with time and accessibility. So a huge number of people love to learn through e-learning websites. As we cannot ignore the fact that the online presence of the world is insanely huge and growing day by day.
So as question is best Programming and design tutorial or courses? so what i suggest that at least once Check out the best Programming and design tutorial or courses  recommended by programming community. http://letsfindcourse.com
So as many student want to learn Programming and design  and want certification but unable to find best course or tutorial. So Programming and design tutorials???????
help student to find the best Programming and design online tutorial, with detailed information(certification) and it will be easy for student to find course.
http://letsfindcourse.com/python

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

【個人メモ】Javaで簡潔にディープコピーを行う

Javaで簡潔にディープコピーを行う
http://koturn.hatenablog.com/entry/2017/01/23/050000

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

java scannerの使い方を勘違いしていた話(メモ)

目次

  • 実行環境
  • 発生した問題、エラーメッセージ
  • 勘違いしていた内容
  • 解決後のコード
  • コードの解説
  • まとめ

実行環境

Java version : 12.0.1
コード記述 : テキストエディタ(Atom)
使用OS : windows(文字コードの問題なだけでMacでも作動しました)
問題の経緯 : Java初級者が学習した内容で何かをつくれないかと思い、自分でコードを組んでみたところ、エラーが発生

発生した問題、エラーメッセージ

発声した問題としては、Scannerクラスを用いて、特定の入力キー以外が入力された場合(今回の場合は1か2の入力を求めていました)、再入力するだけのプログラムです。
まず最初に機能だけで考えて組んでみた。

errorFile.java
Scanner sc = new Scanner().nextInt();
while(sc){
  switch(sc){
    case 1:
    // 処理1
    break;
    case 2:
    // 処理2
    break;
    default:
    // 処理3
    break;
  }
}

お分かりかと思いますが、当然作動しません。この時点でいろいろと、本当にいろいろと理解を間違えてしまっていることがわかります。
とりあえずよくわからなくても動かしてみて、間違っていたらその都度調べたり、エラー解決した方が楽しい!などと思って浅い理解で組んでしまったためのこの結果です。

勘違いしていた内容

この時点で、自分が考えていた原因について説明します。単純に入力エラーの解決方法だけを見たいという方はコードの解説までとんでください。ここは蛇足になるかと思います。

この時点で勘違いをしていた内容については主に以下の内容
〇 while()の()内をループ条件だと思っていた
→実際はbooleanで()内の条件がfalseになるまでループ

〇 ScannerクラスをScanner 変数名 = new Scanner().nextInt()で一つの形だと思っていた
→実際はインスタンス化と入力した要素の取得は別々の機能
つまり、new Scanner()と.nextInt()はわけることが可能
そもそもこの文だとScannerでint型を取得することになり、余計なエラーが・・・

〇 例外処理を理解していない
→このままでは数字入力しか対応しておらず、文字列で入力された場合、例外が発生し、うまく実行ができない
一応解決後には例外処理の記入もしてありますが、正直例外処理に関してはまだまだ試行不足

解決後のコード

ここまで勘違いしていた内容を、偉大なる先人の方々の質問や資料、書籍などを用いて解決したあとの、比較的きれいになったコードがこちらです。

SolutionFile.java
int all = 0;
  while(all == 0){
    try{
      Scanner sc = new Scanner(System.in);
      switch(sc.nextInt()){
        case 1:
          // 処理1
          all +=1;
          break;
        case 2:
          // 処理2
          all +=1;
          break;
        default:
          // 処理3
          break;
      }
    }catch(Exception e){
      // 処理4
    } 
  }

いかがでしょうか?少なくとも最低限自分の意図に沿った動作はするようになりました。可読性やどこから出てきたint all、catchの例外処理などはちゃんとわかってる?といわれるようなコードを書いていますが、動けばOK!とするならこれで納得します。しましょう。

コードの解説

ここでは一応完成したコード(SolutionFile.java)をかみ砕いた解説になります。

まずはそれぞれのスコープ範囲を一覧すると
(ここでは範囲の開始から終わりまでを挟んで表記しています)

while // 1
  try // 2
    Scanner // 3
    switch // 4
      case 1:
      case 2:
      default:
    switch
  try 
  catch
  catch
while

こんな感じ
while > try == catch > switch > case == default
ですね

// 1
whileのを抜けない限り、try~catchまでの処理が延々と繰り返されることになります。
今回の条件では最初に初期値0のallを宣言して「allが0以外になるまで」を条件にしています。
つまりallの値が加減算などされるなどすればループが終了するんですね。

// 2
次にエラーが起きる可能性のある処理ですね。エラーが発生する可能性と、エラーが発生しない通常処理したい内容をtryで囲んで例外をcatchで囲んでいます。そして下記で解説していますが、catchはwhileの中でのループ分で、ループを抜けることをしていないため、catch内の処理が実行されたあとは、またwhileの初めに処理が戻ります。

ちなみに、
本来エラーが起きるというだけに絞ればScannerの入力だけになると思うんですが、試しにswitchだけを移動してみましたが、エラーが発生しました。
以下はswitchを移動してみたコード

Changefile.java
int all = 0;
  while(all == 0){
    try{
      Scanner sc = new Scanner(System.in);
    }catch(Exception e){
      // 処理4
    } 
      switch(sc.nextInt()){
        case 1:
          // 処理1
          all +=1;
          break;
        case 2:
          // 処理2
          all +=1;
          break;
        default:
          // 処理3
          continue;
      }
  }

エラー: シンボルを見つけられません
switch(sc.nextInt()){
               ^
  シンボル:   変数 sc

scの要素の取得をswitch内でしていることが理由だと考えられます。

// 3
ここでは入力だけしてもらう形ですね。今回のコードでは欄外に記述していますが、
import java.util.Scanner;
を最初に宣言しているため、この記述になっています。
何度も宣言するわけではないので、import宣言せずにここだけ
Scanner sc = new java.util.Scanner(System.in);
としても問題なさそうですね。

// 4
ここでは入力してもらった内容を取得して、その取得した内容によって処理を変えています。
if文でも条件式は可能ですが、自分での読みやすさと、コードの意味の読みやすさからswitch文を選択しています。
nextInt()
のため、数字入力を求めているわけですね。
case 1:
case 2:
では、それぞれの処理に加えてwhileのループを抜けるために
all += 1
とすることでallの値を1加算しています。
結果的に all = 1 となり、ループの条件である「allが0以外になるまで」という条件を満たすことによって条件がfalseになって、ループを抜けます。

そしてdefault、つまり1か2以外の数字が入力された場合はallの値を変えないことでループ条件をfalseにせずに処理をwhileの最初まで戻しています。

つまり1か2が入力されるまで何度も入力してもらうよ!別の数字か文字列を入力すると延々ループするよ!という処理なわけです。

まとめ

自分が実装したかった機能は
 1か2以外が入力された時、もう一度入力を求める
という機能です。

勘違いしていた点は
 whileの条件、Scannerの構成、例外処理

そして勘違いを正して解決しました、というのが今回の記事の内容です。
しかし動作するようになったものの、まだまだ無駄が多いコードですので、無駄を削る、例外処理の試行、他人から読みやすいコードなのか、という問題点がありますので、今後も試行を重ねていきたいと思います。以上、ありがとうございました。

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

Effective Java 第3版 第2章オブジェクトの生成と消滅 まとめ

Java中級者以上の必須本である、Effective Java 第3版に Kindle版が出たので、まとめる。
「第1章 はじめに」は、主に用語の説明なので飛ばす。

項目1 コンストラクタの代わりにstaticファクトリメソッドを検討する

  • staticファクトリメソッドとは、Boolean.valueOf(boolean b)みたいなやつ。
[Good]staticファクトリメソッド例
public static Boolean valueOf(boolean b) {
  return b ? Boolean.True : Boolean.False
}
  • staticファクトリメソッドのメリット
    • コンストラクタとは異なり、名前を持つ。
      • コンストラクタは名前が無い為、パラメータで機能を判断するのは難しい。
    • コンストラクタとは異なり、その呼び出しごとに新たなオブジェクトを生成する必要がない。
      • 不必要に重複したオブジェクトの生成を避けられる。
    • コンストラクタとは異なり、メソッドの戻り値型の任意のサブタイプのオブジェクトを返せる。
    • 返されるオブジェクトのクラスは、入力パラメータの値に応じて呼び出しごとに変えられる。
    • 返されるオブジェクトのクラスは、そのstaticファクトリメソッドを含むクラスが書かれた時点で存在する必要がない。
  • staticファクトリメソッドの制約
    • publicあるいはprotectedのコンストラクタを持たないクラスのサブクラスは作れない
      • 例えば、コレクションフレームワーク内のユーティリティ実装クラスのどれかのサブクラスを作ることはできない。
        • 継承ではなく、コンポジションを使うべき。
    • プログラマがstaticファクトリメソッドを見つけるのが難しい。
  • staticファクトリメソッドの命名規則
    • from
    • of
    • valueOf
    • instance or getInstance
    • create or newInstance
    • getType
    • newType
    • type

項目2 多くのコンストラクタパラメータに直面したときにはビルダーを検討する

[Good]ビルダークラス例
public class NutritionFacts {
    private final int savingSize;
    private final int savings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // 必須
        private final int savingSize;
        private final int savings;

        // オプション デフォルト値
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int savingSize, int savings) {
            this.savingSize = savingSize;
            this.savings = savings;
        }

        public Builder calories(int val) {
            calories = val;
            return this;
        }

        public Builder fat(int val) {
            fat = val;
            return this;
        }

        public Builder sodium(int val) {
            sodium = val;
            return this;
        }

        public Builder carbohydrate(int val) {
            carbohydrate = val;
            return this;
        }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }

    }

    private NutritionFacts(Builder builder) {
        savingSize = builder.savingSize;
        savings = builder.savings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}

lombokの@Builder使用例

lombokを使った例
import lombok.Builder;
import lombok.NonNull;

@Builder
public class LombokNutritionFacts {

    // 必須
    @NonNull
    private final Integer savingSize;
    @NonNull
    private final Integer savings;

    // デフォルト値の設定
    @Builder.Default
    private final Integer calories = 0;
    @Builder.Default
    private final Integer fat = 0;
    @Builder.Default
    private final Integer sodium = 0;
    @Builder.Default
    private final Integer carbohydrate = 0;
}

項目3 privateのコンストラクタかenum型でシングルトン特性を強制する

[Good]enum型を用いたシングルトンクラス
// enum型を用いたシングルトンクラス
public enum Elvis {
    INSTANCE;

    public void leaveTheBilding() {
        System.out.println("Hello Elvis!");
    }
}

// 呼び出し例
public class Main {
    public static void main(String[] args){
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBilding();
    }
}

項目4 privateのコンストラクタでインスタンス化不可能を強制する

[Good]
// インスタンス化できないユーティリティクラス
public class UtilityClass {
    // インスタンス化できないように、privateでコンストラクタを作成する
    private UtilityClass() {
        throw new AssertionError();  // クラス内で呼ばれたらスローする
    }
    // 以下省略
}

項目5 資源を直接結び付けるよりも依存性注入を選ぶ

[Bad]
// 静的なユーティリティの不適切な使用。柔軟性に欠けてテストできない。
public class SpellCheckerStatic {
    private static final Lexicon dictionary = new MyDictionary();

    private SpellCheckerStatic() {
    }
    public static boolean isValid(String word) {
        // 省略
    }
    public static List<String> suggestions(String type) {
        // 省略
    }
}
[Good]
// 依存性注入は柔軟でありテストできる
public class SpellChecker {
    private final Lexicon dictionary;

    public SpellChecker(Lexicon dictionary) {
        this.dictionary = Objects.requireNonNull(dictionary);
    }
    public boolean isValid(String word) {
        // 省略
    }
    public List<String> suggestions(String type) {
        // 省略
    }
}

項目6 不必要なオブジェクトの生成を避ける

// これは不必要なオブジェクトの生成をするため、
String s = new String("bikini");
// こうするべきである
String s = "bikini";
  • コンストラクタよりもstaticファクトリメソッドを使うべきである。
  • ボクシングされた基本データ型よりも基本データ型を選び、意図しない自動ボクシングに注意すること。
public class RomanNumerals {
    private static final Pattern ROMAN = Pattern.compile(
            "^(?=.)M*(C[MD]|D?C{0,3})" +
                    "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

    // 【良い例】 オブジェクトを再利用した改善版
    static boolean isRomanNumerial(String s) {
        return ROMAN.matcher(s).matches();
    }

    // 【良くない例】 繰り返し使うとパフォーマンスが悪い
    static boolean isRomanNumerialBad(String s) {
        return s.matches("^(?=.)M*(C[MD]|D?C{0,3})" +
                "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
    }
}

項目7 使われなくなったオブジェクトの参照を取り除く

  • 使われなくなった参照にはnullを設定する。
  • オブジェクト参照にnullを設定することは、普通というよりむしろ例外であるべき。
  • 使われなくなった参照を排除する最善の方法は、その参照が含まれていた変数をスコープの外に出すことである。
public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    public Stack() {
        this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }
    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }
    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null;  // ■ 使われなくなった参照を取り除く ■
        return result;
    }
    // 大きくする必要があれば倍にする。最低でも1つの容量を確保する。
    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2 * size + 1);
        }
    }
}

項目8 ファイナライザとクリーナーを避ける

  • ファイナライザは、予測不可能で大抵は危険で一般的には必要がない。
  • Java9からのファイナライザの代替は、クリーナーで、ファイナライザよりも危険ではないが、それでも予想不可能で遅く、一般的には必要がない。
  • ファイナライザやクリーナーの代わりに、AutoClosableを実装させ、必要がなくなった時点でcloseメソッドを呼び出すことを要求する。大抵はcloseに、try-with-resourceを使う。

項目9 try-finallyよりもtry-with-resourcesを選ぶ

その名の通り。

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

Desktop : OpenCV Laplacian Filter

Goal

Test OpenCV laplacian filter.

OpenCV_LaplacianFilter.java
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class OpenCV_LaplacianFilter {
    static{System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    private JFrame frmjavaSwing;

    /**
        *  Launch the  application.
        */
    public static void main(String[] args){
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try{
                    OpenCV_LaplacianFilter window = new OpenCV_LaplacianFilter();
                    window.frmjavaSwing.setVisible(true);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
    }

    /**
        * Create the  application.
        */
    public OpenCV_LaplacianFilter(){
        final Mat src  = Imgcodecs.imread(
                "D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\baboon.jpg");

        BufferedImage image=matToBufferedImage(src);

        frmjavaSwing = new JFrame();
        frmjavaSwing.setTitle("opencv Laplacian API½m²ß1");
        frmjavaSwing.setBounds(100, 100, 560, 620);
        frmjavaSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmjavaSwing.getContentPane().setLayout(null);

        final JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setBounds(5, 60, image.getHeight()+10, image.getWidth()+10);
        lblNewLabel.setIcon(new ImageIcon(image));
        frmjavaSwing.getContentPane().add(lblNewLabel);

        JButton btnX = new JButton("Laplacian filter³B²z");
        btnX.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(src,1));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnX.setBounds(42, 10, 174, 23);
        frmjavaSwing.getContentPane().add(btnX);
    }

    public Mat Convolution(Mat source,int type){
        Mat destination=new Mat(source.rows(),source.cols(),source.type());
        Imgproc.Laplacian(source, destination, -1);
        return destination;

    }

    public BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int)matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for(int i=0; i<data.length; i=i+3) {
                    b = data[i];
                    data[i] = data[i+2];
                    data[i+2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }
}
Result

opencv_laplacian_filter.JPG

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

Desktop : OpenCV Prewitt Filter

Goal

Test opencv Prewitt filter.

OpenCV_Prewitt_Filter.java
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

public class OpenCV_Prewitt_Filter {

    static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}
    private JFrame frmjavaSwing;




    /**
        *  Lunch the application.
        */
    public static void main(String[] args){

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try{
                    OpenCV_Prewitt_Filter window = new OpenCV_Prewitt_Filter();
                    window.frmjavaSwing.setVisible(true);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public OpenCV_Prewitt_Filter() {
        init();
    }

    /**
        *  Init the contents of the frame.
        */
    private void init(){
        final Mat source = Imgcodecs.imread("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\baboon.jpg");

        BufferedImage image=matToBufferedImage(source);

        frmjavaSwing = new JFrame();
        frmjavaSwing.setTitle("Prewitt Filter練習");
        frmjavaSwing.setBounds(100, 100, 560, 620);
        frmjavaSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmjavaSwing.getContentPane().setLayout(null);

        final JLabel lblNewLabel = new JLabel("");
        lblNewLabel.setBounds(5, 60, image.getHeight()+10, image.getWidth()+10);
        lblNewLabel.setIcon(new ImageIcon(image));
        frmjavaSwing.getContentPane().add(lblNewLabel);

        JButton btnX = new JButton("水平處理");
        btnX.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,2));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnX.setBounds(42, 10, 114, 23);
        frmjavaSwing.getContentPane().add(btnX);

        JButton btnY = new JButton("垂直處理");
        btnY.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage newImage=matToBufferedImage(Convolution(source,1));
                lblNewLabel.setIcon(new ImageIcon(newImage));
            }
        });
        btnY.setBounds(211, 10, 102, 23);
        frmjavaSwing.getContentPane().add(btnY);
    }

    public Mat Convolution(Mat source,int type){
        Mat kernel =new Mat(3,3, CvType.CV_32F);
        if (type==1){

            kernel.put(0, 0, new float[]{-1,0,1});
            kernel.put(1, 0, new float[]{-1,0,1});
            kernel.put(2, 0, new float[]{-1,0,1});

        }else if (type==2){
            kernel.put(0, 0, new float[]{-1,-1,-1});
            kernel.put(1, 0, new float[]{0,0,0});
            kernel.put(2, 0, new float[]{1,1,1});
        }
        Mat destination=new Mat(source.rows(),source.cols(),source.type());
        Imgproc.filter2D(source, destination, -1, kernel);
        return destination;

    }

    public BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int)matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for(int i=0; i<data.length; i=i+3) {
                    b = data[i];
                    data[i] = data[i+2];
                    data[i+2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }

}
Result

opencv_prewitt_filter.JPG

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

リフレクションユーティリティを作る③

はじめに

今回はアノテーションを利用したリフレクションです。
フィールドにちょっとした属性を持たせたいけど、ビジネスロジックに書くのは嫌だなぁ、というときにフィールドアノテーションが便利です。

前回作ったやつ→オブジェクトのフィールドを適当な値で埋めるユーティリティ

今回作ったもの

今回はEntityオブジェクトをヨコ(CSVの1レコード)に変換するUtilメソッドを作りました。

  • Dataアノテーション
  • AnnotationUtilクラス
  • Userクラス
  • Mainクラス

AnnotationUtil

getHeaderメソッドでヘッダ行を出力します。
getDataメソッドでデータ行を出力します。

AnnotationUtil.java
package test1;
import java.lang.reflect.Field;

public class AnnotationUtil {
    /** カンマ */
    private static final String DELIMITER = ",";
    /** ダブルクォーテーション */
    private static final String QUOTE = "\"";

    /**
     * UserをCSV1行に変換する。<br>
     * Userが持つ@Dataが付与されたフィールドを、CSV1行にして返す。<br>
     * isHeader=trueの場合はtitleを指定されたCSV形式で返す。
     */
    public static String getUser(User obj, boolean isHeader, String delimiter, String quote) {
        Field[] fieldList = obj.getClass().getDeclaredFields();
        StringBuilder sb = new StringBuilder();

        for (Field f : fieldList) {
            f.setAccessible(true);
            Data annotation = f.getAnnotation(Data.class);
            if (annotation == null) {
                continue;
            }
            String value;
            try {
                if (isHeader) {
                    value = annotation.title(); // タイトル
                } else {
                    value = String.valueOf(f.get(obj)); // 値
                }
            } catch (IllegalArgumentException | IllegalAccessException e) {
                // throws宣言が面倒なので全部実行時例外にする
                throw new RuntimeException(e);
            }

            // 囲み文字に指定がある場合
            if (quote != null)
                sb.append(quote);
            // 値 or 項目名
            sb.append(value);
            // 囲み文字に指定がある場合
            if (quote != null)
                sb.append(quote);

            // 区切り文字
            sb.append(delimiter);
        }
        // 最後の区切り文字を削除
        sb.deleteCharAt(sb.length() - 1);

        return sb.toString();
    }

    public static String getHeader(User user) {
        return getUser(user, true, DELIMITER, QUOTE);
    }

    public static String getData(User user) {
        return getUser(user, false, DELIMITER, QUOTE);
    }
}

Data

このアノテーションをCSVデータとして出力するフィールドに付与します。
titleでヘッダ名を指定します。

Data.java
package test1;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Target(FIELD)
@Retention(RUNTIME)
public @interface Data {
    String title();
}

User

Entityクラス。出力したいフィールドにDataアノテーションを付与します。

User.java
package test1;

public class User {
    @Data(title = "社員ID")
    public Integer id;
    @Data(title = "名前")
    public String name;
    public String insertDate;
    public String insertUser;
    public String updateDate;
    public String updateUser;
}

Main

ユーティリティの動作確認用。

Main.java
package test1;

public class Main {
    public static void main(String[] args) {
        System.out.println("### Start ###");
        User user = new User();
        user.id = 101;
        user.name = "アルバート";
        user.insertDate = "20190501";
        user.insertUser = "クリス";
        user.updateDate = "20190512";
        user.updateUser = "ジル";

        System.out.println(AnnotationUtil.getHeader(user));
        System.out.println(AnnotationUtil.getData(user));
        System.out.println("### End ###");
    }

}

実行結果

### Start ###
"社員ID","名前"
"101","アルバート"
### End ###

タテからヨコに変換されてますね。
idとnameのみにDataをつけているのでちゃんとその2つだけ出力されていますね。

あとがき

最初、久しぶりにIDEを使用せずに実装してみたらなぜかField#getAnnotation()の戻り値がすべてNULLになった。IDE使用したらちゃんと動いたがなぜだろう??

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