20200729のJavaに関する記事は11件です。

タグ付きクラスよりクラス階層を選ぶ

タグ付きクラス

public class Figure {

    enum Shape {RECTANGLE, CIRCLE};

    final Shape shape;

    // shapeがRECTANGLEである場合にだけこれらのフィールドは使われる
    double length;
    double width;

    // shapeがCIRCLEである場合にだけこのフィールドは使われる
    double radius;

    // 円のコンストラクタ
    Figure(double radius) {
        shape = Shape.CIRCLE;
        this.radius = radius;
    }

    // 長方形のコンストラクタ
    Figure(double length, double width) {
        shape = Shape.RECTANGLE;
        this.length = length;
        this.width = width;
    }

    double area() {
        switch (shape) {
        case RECTANGLE:
            return length * width;
        case CIRCLE:
            return Math.PI * (radius * radius);
        default:
            throw new AssertionError(shape);
        }
    }

}

タグ付きクラスに対するクラス階層による書き換え

abstract class Figure {
    abstract double area();
}

class Circle extends Figure {
    final double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    @Override
    double area() {
        return Math.PI * (radius * radius);
    }
}

class Rectangle extends Figure {
    final double length;
    final double width;

    Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    double area() {
        return length * width;
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【StreamAPIとラムダ式】何でもできるスーパーマン登場!!

java経験者のOさんはこう言った…
Streamとラムダ式でなんでも1行で書くことができる…と。

もちろん、基礎ができた後にやるのを忘れずに

【Streamとラムダ式】サンプルコード

public class TestStarter {

    public static void main(String[] args){

        String[] s = {"1","2","3"};
        //中間操作はなんでもしてくれるスーパーマン かつ 1度に条件をなんでもかける
        Arrays.asList(s).stream().filter(i -> i.equals("1")).forEach(System.out::println);

    }
}

これは、

❶.fillerで「true,false」なら何でも条件を設定できる(メソッドも参照可)
❷.forEachはfor文をぶん回し全部出力してくれる
❸System.out::printlnってのもラムダ式の書き方

他にも.mapという配列の中身をいじくれるメソッドなんかもある。

【超ムズ】ラムダ式を活用したサンプルコードと問題

以前、この記事内で紹介しました。

配列でソートしたいけど、配列が全部文字列!?
https://qiita.com/Fallstag_Atsugi/items/88b1b4f3da75ae5ab191

StreamAPI

Stream1.png
Stream2.png
St3.png

答えは最後の章で!

ラムダ式

ラムダ1.png
ラムダ2.png

問題.png

答えは最後の章で!

各章の答え

StreamAPI
答え1.png

ラムダ式
new.png

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

【探索アルゴリズム】ハッシュ探索法

【探索アルゴリズム】ハッシュ探索法

・ハッシュ探索法は、データを探す探索アルゴリズムの1つ
・探索しやすいようにあらかじめ関数を用いてデータを格納しておく
・格納するのに使った関数を用いて、一発でデータを探索する

他の探索アルゴリズムとの違い

・これまでの線形探索法や二分探索法では、何のデータがどこの要素に入ってるかは全くわからない状態から探索を始める、というのが前提条件であった。
・ハッシュ探索法は、データの「中身」と格納先の「要素」をあらかじめ紐づけしておくおkとで、ごく短時間に探索できるように工夫したアルゴリズム。

import java.util.Arrays;

/**
 * ハッシュ探索法のアルゴリズム
 */
public class Algorithm {
    public static void main(String[] args) {
        int[] arrayD = {12, 25, 36, 20, 30, 8, 42};
        int[] arrayH = new int[11];
        Arrays.fill(arrayH, 0); //初期値として0をセットする

        System.out.println("今回扱うデータ" + Arrays.toString(arrayD));
        System.out.println("初期化された格納先の配列" + Arrays.toString(arrayH));

        int k;
        for (int i = 0; i < arrayD.length; i++) {  //iが7になったら格納処理は終了
            if (i < arrayD.length) {
                k = arrayD[i] % 11;
                while (arrayH[k] != 0) {
                    k = (k + 1) % 11;  //格納する配列先の要素数を超えた場合に最初[0]から格納先「0の値の場所」を探す
                }
                arrayH[k] = arrayD[i]; //格納先が「0」であれば値を代入する
                }
            }

        for (int result : arrayH) {  //arrayHのデータを先頭から順に出力
            System.out.print(result +",");
        }
    }
}
/*出力結果
今回扱うデータ[12, 25, 36, 20, 30, 8, 42]
初期化された格納先の配列[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
42,12,0,25,36,0,0,0,30,20,8,
*/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

*Android*ピンチイン・ピンチアウトを検知する

はじめに

こんにちは.今回は,Androidでピンチ操作を検知しようと思います.ピンチイン・ピンチアウトを判別する方法について解説します.

前提

開発環境は以下の通りです.
*Android Studio 4.0.1
*targetSdkVersion 28
*Google Nexus 5x

ピンチイン・ピンチアウトの判別

ピンチ操作の検知には,ScaleGestureDetectorを使用します.第一引数にContext,第二引数には,OnScaleGestureListenerインタフェースを実装したクラスのオブジェクトを指定します.今回は,匿名クラスを使用して,インタフェースを実装します.

this.scaleGestureDetector = new ScaleGestureDetector(this, new ScaleGestureDetector.OnScaleGestureListener() {
    // ピンチ操作中に繰り返し呼ばれる
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        return true;
    }
    // ピンチ操作を開始したときに呼ばれる
    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }
    //  ピンチ操作を終了したときに呼ばれる
    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
    }
});

次に,onTouchEventメソッドを用意し,onTouchEventメソッドが呼ばれた際に、ScaleGestureDetector.onTouchEventが呼ばれるようにすることで,ピンチ操作を検知することができます.

@Override
public boolean onTouchEvent(MotionEvent motionEvent){
    this.scaleGestureDetector.onTouchEvent(motionEvent);
    return true;

ピンチ操作を検知できたら,次にピンチイン・ピンチアウトを判別します.ピンチ操作では,画面に2本の指を触れています.指間の距離を測定するメソッドとしてgetCurrentSpan()が用意されているので,それを使用します.指間の距離の変化を利用することで,ピンチイン・ピンチアウトを判別することができます.ピンチイン・ピンチアウトの誤判定を防ぐために,閾値として指間の距離xを指定し,x以上変化した場合にピンチイン・ピンチアウトの判定を行います.

@Override
public boolean onScale(ScaleGestureDetector detector) {          
    distance_current = detector.getCurrentSpan();
    return true;
}

ピンチ操作中の指間の距離の正確性

ピンチ操作中の指間の距離を取得するにはgetCurrentSpan()を使用します.取得した指間の距離は,スマートフォンの画面の対角線の長さより小さいはずです.誤った距離を取得してしまった場合に取り除くために,スマートフォンの対角線の長さと比較して,それより小さいもののみを指間の距離とします.ここでは,Navigation bar を除いた画面の領域から,対角線の長さを求めます.画面の対角線の長さを取得するには以下のようにします.

WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
Point size = new Point();
Display disp = wm.getDefaultDisplay();
disp.getSize(size);
screen_width = this.size.x;
screen_height = this.size.y;
//対角線の長さを求める
int screen_diagonal = (int) Math.sqrt((int)(Math.pow(screen_width, 2)) + (int)(Math.pow(screen_height, 2)));

サンプルコード

AndroidManifest.xml
?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.myapplication3;

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.WindowManager;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private ScaleGestureDetector scaleGestureDetector;
    private long time_elapsed;
    private long time_start;
    private long time_current;
    private float distance_current;
    private float distance_start;
    private Boolean flg_pinch_out;
    private Boolean flg_pinch_in;
    private WindowManager wm;
    private Display disp;
    private Point size;
    private int screen_width;
    private int screen_height;
    //画面の対角線の長さ
    private int screen_diagonal;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        this.size = new Point();
        this.disp = wm.getDefaultDisplay();
        this.disp.getSize(size);
        screen_width = this.size.x;
        screen_height = this.size.y;
        //対角線の長さを求める
        screen_diagonal = (int) Math.sqrt((int)(Math.pow(screen_width, 2)) + (int)(Math.pow(screen_height, 2)));
        this.scaleGestureDetector = new ScaleGestureDetector(this, new ScaleGestureDetector.OnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                time_current = detector.getEventTime();
                time_elapsed = time_current - time_start;
                if (time_elapsed >= 0.5){
                    distance_current = detector.getCurrentSpan();
                    if (distance_start == 0){
                        distance_start = distance_current;
                    }
                    flg_pinch_out = (distance_current - distance_start) > 300;
                    flg_pinch_in = (distance_start - distance_current) > 300;
                    if (flg_pinch_out){
                        Toast.makeText(getApplicationContext(), "Pinch out", Toast.LENGTH_LONG).show();
                        time_start = time_current;
                        distance_start = distance_current;
                    }
                    else if (flg_pinch_in){
                        Toast.makeText(getApplicationContext(), "Pinch in", Toast.LENGTH_LONG).show();
                        time_start = time_current;
                        distance_start = distance_current;
                    }
                    else {
                        //pass
                    }
                }
                return true;
            }


            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                distance_start = detector.getEventTime();
                if (distance_start > screen_diagonal){
                    distance_start = 0;
                }
                time_start = detector.getEventTime();
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent motionEvent){
        this.scaleGestureDetector.onTouchEvent(motionEvent);
        return true;
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【総集編】7月ふりかえり.md

はじめに

今月のふりかえりです。
月1で振り返り
今後は何を勉強するかを決めます。


7月 1週目

2020/07/01 【統計学】ふつうのエンジニアが統計学の勉強を始めてみた

2020/07/05 【統計学】ふつうのエンジニアが統計学の勉強を始めてみた- part2


7月 2週目

2020/07/08 【キニナル話】jexcel使ってみた.xlsx

2020/07/12 JavaとJavaScript 間違えられやすい問題

2020/07/15 【UiPath】 UiPathを使いはじめての所感やメモ


7月 3週目

2020/07/19 【勉強】エンジニアの学び方を考える

2020/07/22 C#のノート


7月 4週目

2020/07/26 Python3のノート


先月に宣言したことについてのFB

  • DBスペシャリストになる為SQL頑張る。

職場で散々触っているからあまり勉強しなくても良いかなと

思いましたが、DBで仕事していることもあるので

仕事以外でも勉強しようと考えるようになりました。

  • AWSをうまく扱えるようにガンガン活用してみる。

正直なところ、触れていないというのが現状

それどころかAzureを触りにいく始末

ただ、Azureを触ってみたところ多少の手ごたえを感じた。
Azure Learnningを活用してもっと探りを入れながらも
ノートを作成したいと思う。
あわよくば、バックエンドにAzureをおきたい。(置くことが目的にならないように注意)

  • Pythonでデータ分析ができるように数学を復習する。

数学やって分析の「ぶ」の字をやっていたら

ソースコード解析という分野にのめりこんでしまった。

きっかけは自身の仕事の効率化

レビュー時にソースコードを読んだりドキュメントの更新したりが

結構大変で今後は全自動とまではいかなくでも

ドキュメントの自動更新やソースコード解析のスキームを仕上げる。

  • PHP案件を受ける為今後も引き続き勉強して発信する。

一応、PHP案件は受領しましたが中身がなんともレガシー(笑)
オンプレだからまぁそうなるんだろうなとは思っていました。
まぁプライベートでうまいこと使いたいなと思います。


今後

  • DBスペシャリストになる為SQL頑張る。
  • Azureで 使えるDBを実際に使ってみる。
  • 職場でPythonによるデータ分析をする。
  • 受領したPHP案件をクリアする。
  • RPAでロボットを大量生産する。
  • 令和2年度キタミ式イラスト塾の読破

おわり

来月から週1更新にして記事作成ではなく
記事更新を中心にやります。
(毎週日曜日更新)

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

【総集編】7月ふりかえり

はじめに

今月のふりかえりです。
月1で振り返り
今後は何を勉強するかを決めます。


7月 1週目

2020/07/01 【統計学】ふつうのエンジニアが統計学の勉強を始めてみた

2020/07/05 【統計学】ふつうのエンジニアが統計学の勉強を始めてみた- part2


7月 2週目

2020/07/08 【キニナル話】jexcel使ってみた.xlsx

2020/07/12 JavaとJavaScript 間違えられやすい問題


7月 3週目

2020/07/15 【UiPath】 UiPathを使いはじめての所感やメモ

2020/07/19 【勉強】エンジニアの学び方を考える


7月 4週目

2020/07/22 C#のノート

2020/07/26 Python3のノート


先月に宣言したことについてのFB

  • DBスペシャリストになる為SQL頑張る。

職場で散々触っているからあまり勉強しなくても良いかなと
思いましたが、DBで仕事していることもあるので
仕事以外でも勉強しようと考えるようになりました。

  • AWSをうまく扱えるようにガンガン活用してみる。

正直なところ、触れていないというのが現状
それどころかAzureを触りにいく始末

ただ、Azureを触ってみたところ多少の手ごたえを感じた。
Azure Learnningを活用してもっと探りを入れながらも
ノートを作成したいと思う。
あわよくば、バックエンドにAzureをおきたい。(置くことが目的にならないように注意)

  • Pythonでデータ分析ができるように数学を復習する。

数学やって分析の「ぶ」の字をやっていたら
ソースコード解析という分野にのめりこんでしまった。
きっかけは自身の仕事の効率化
レビュー時にソースコードを読んだりドキュメントの更新したりが
結構大変で今後は全自動とまではいかなくでも
ドキュメントの自動更新やソースコード解析のスキームを仕上げる。

  • PHP案件を受ける為今後も引き続き勉強して発信する。

一応、PHP案件は受領しましたが中身がなんともレガシー(笑)
オンプレだからまぁそうなるんだろうなとは思っていました。
まぁプライベートでうまいこと使いたいなと思います。


今後

  • DBスペシャリストになる為SQL頑張る。
  • Azureで 使えるDBを実際に使ってみる。
  • 職場でPythonによるデータ分析をする。
  • 受領したPHP案件をクリアする。
  • RPAでロボットを大量生産する。
  • 令和2年度キタミ式イラスト塾の読破

おわり

来月から週1更新にして記事作成ではなく
記事更新を中心にやります。
(毎週日曜日更新)

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

【Java】スーパークラス/サブクラスのコンストラクタあれこれ

目次

  • はじめに
  • 前提知識
    • 継承クラスについて
    • コンストラクタ
  • 今回のキモ
    • 暗黙的なコンストラクタ実行
  • おわりに

はじめに

どうも駆け出しエンジニアです。
先日会社でコーディングをしていた際に人の書いたコードの続きを書かなくちゃいけなくなったんですが、
その時にクラスの継承,コンストラクタでドツボにはまってしまいかなりの時間を使ってしまいまして....
もう一回頭から学習しなおした所、わからないことがボロボロ出てきてヒドかったので再度まとめることにしました。

なお、本記事は
 ・「現在Javaを触っている人」
 ・「もう一度内容を復習したい人」
向けとなっております。
各クラス名/変数名は適宜読み替えてください。

前提知識

継承クラスについて
  • 継承クラス=新しいクラスを作るとき、以前作った機能と共通する部分を引き継ぐクラス
  • 継承元のクラスのことを「親クラス」、継承先のクラスのことを「子クラス」と呼ぶ。
  • 同意義で「スーパークラス」「サブクラス」とも呼ぶ ※本記事ではスーパー/サブで表現。
  • 継承クラスのインスタンスを作成することで、継承クラスのメソッド/フィールドにアクセスできる。
  • ↓↓↓↓記述の仕方は↓↓↓↓
Super.java
class Super {
  public void exampleSuper(){
    //何らかの処理
  }
}
Sub.java
class Sub extends Super(){ //クラス名 extends 継承元クラス名 で継承。
  public void exampleSub(){
    //何らかの処理
  }
}

コンストラクタ

  • コンストラクタ=クラスのインスタンスを作成したときに自動で必ず呼び出されるメソッドのこと
  • クラス名と同じ名前のメソッドのこと
  • 通例コンストラクタ名は上記理由から先頭は大文字
  • 戻り値はもともと想定していないので、voidは書いちゃダメ(→コンパイルエラー)
  • 主にそのクラスのフィールド(メンバ変数)を初期化するのに用いられる。
  • というか通例として/暗黙的にそうらしいので、それ以外の余計なことはしない方が吉。
    →大規模開発における可読性/保守性の向上につながる
  • ↓↓↓↓記述の仕方は↓↓↓↓
Smple.java
class Sample{
  public Sample(){
    //ここがコンストラクタ
  }
  public void exampleMethod(){
    //これはただのクラスメソッド
  }
}

今回のキモ

暗黙的なコンストラクタ実行

  • クラスのインスタンス化時、継承階層の最上位から下方向へ、順番にインスタンス化されていく
  • サブクラスのコンストラクタは最初にスーパークラスのコンストラクタを呼び出す
  • スーパークラスのコンストラクタを明示的に呼び出さないとき、自動的に引数のないコンストラクタが呼び出される。
  • コンストラクタの呼び出し時はsuper()メソッドが暗黙的に(自動的に)実行されている

●super();

スーパークラスのコンストラクタを呼び出すメソッド。
サブクラスのコンストラクタは"言語実装として"暗黙的(自動的)にスーパークラスのコンストラクタを実行するので、
必ず記述が必要なものではない

  • ↓↓↓↓具体例↓↓↓↓
Super.java
class Super {
    Super() {
        System.out.println("スーパークラスです!");
    }
}

Sub.java
class Sub extends Super {
    Sub() {
        // 暗黙的にスーパークラスのコンストラクタが実行される
        System.out.println("サブクラスです!");
    }
}

Main.java
class Main {
    public static void main(String[] args) {
        Sub obj = new Sub();
}

//実行結果
スーパークラスです
サブクラスです

"暗黙的スーパーコンストラクターは未定義です"

  • スーパークラスのコンストラクタが引数を持つもののみ定義されている場合、暗黙的に実行される「super();」メソッドだけではコンパイルエラー。

▽解決方法
①スーパークラスに引数を持たないコンストラクタを作成する

Super.java
class Super {
    public name;
    public Super(){
        //コンストラクタをオーバーロードさせる
    }
    public Super(String name){
        this.name = name;
    }
}

②サブクラスのコンストラクタ内で、スーパークラスのコンストラクタの引数に合わせたsuper();メソッドで、明示的にスーパークラスのコンストラクタを呼び出す。

Super.java
class Sub {
    public name;
    public Super(String name){
        // メイン->サブ->スーパーの順で渡ってきたname変数の値をフィールドにセット
        this.name = name;
    }
}
Sub.java
class Sub extends Super {
    Sub(String name) {
    //メインクラスのStrin型変数nameと対応->スーパークラスのコンストラクタへ受け渡し
    super(name);
    }
}
Main.java
class Main {
    public static void main(String[] args) {
        Sub obj = new Sub(String name);
    }
}

終わりに

今回も長くなりましたが読んでいただきありがとうございました。
次回はtry-catchでの例外処理についてかければな~と思ってます。
では。

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

Apache Camel のroute構築で用いる Java DSL の個人的なコーディング規約

Apache Camel では「route」を作成する際、用意されたメソッドをひたすら繋げるという独自のDSLで書く。このDSLは条件分岐ループなどにも対応している。

ただ、Javaのスタイルガイドに従って書くと、条件分岐やループの内部処理を作るメソッドも同じインデントになってしまい、DSLとして非常に読みづらい。なので自前でインデントを追加した方が良いと考えられる。

また、他の部分についても複数の書き方ができたりするが、読みやすい側に統一したい。というわけで、個人的に決めているコーディング規約をまとめた。使ったことのある機能のみしか決められないので、今後経験が増えたら追加・修正していくつもり。

RouteBuilder

基本となるroute全体の形について。 configure() の中身だけ示す。

from("direct:sample").routeId("MySampleRoute")
        // some process
        .to("mock:aaa").id("SamplePartA")
        .log(LoggingLevel.DEBUG,
                "very long text...")

        // another process
        .to("mock:bbb")
;
  • 基本は1行1メソッド(1処理)とする
    • ただし直前のを修飾するものは同じ行を推奨
      • 例えば id() は同じ行(XMLのDSLの場合を考えればいい)
      • routeId() はrouteにIDを設定するので、 from() と同じ行、せめて次の行
    • 処理のグループ単位を表したければ空行を設ける
  • 継続行はインデントを2段(※)つける
    • Javaのスタイルに準拠
      • メソッドの引数を改行する場合もインデント2段
      • 引数が長すぎる場合は、定数に切り出すことも検討すること
    • 逆に言えば始まりの from() だけ2段飛び出す
    • DSLで構造化する際はさらにインデントする(後述)
  • 終わりを示す ; は行を分ける
    • 処理を追加した際、diffで余計な変更が出なくなる

※ インデント1段 = 4スペース(checkstyle)または1タブ、これは別途規約を定めること

構造化

条件分岐やループなどを作るものは、基本的に xxx()end() となっている。共通ルールは以下の通り。

  • その内部を1段インデントする
    • ブロックを視覚的に認識しやすくする
    • Javaの同機能の構文に合わせる
  • end() を省略しない
    • 後段に処理を追加する際、 end() を忘れると意味が変わってしまう
    • なお、 endXxx() が用意されていても使わないこと(使い道が違う?)
  • オプションは xxx() と同じ行にする(長くなる場合は次の行にして1段下げる)

choice

switch文に相当する(breakは不要)。ただしwhen側に条件式を書くので、SQLやRubyでできる式の無いcase文のほうがより似ている。

https://camel.apache.org/components/latest/eips/choice-eip.html

from("direct:sample")
        .choice()
            .when(new MyPredicateA())
                .to("mock:aaa")
            .when(new MyPredicateB())
                .to("mock:bbb")
            .otherwise()
                .to("mock:zzz")
        .end()
;
  • when()otherwise() は1段、内部処理はさらに1段下げる
    • Javaのswitch文に合わせた書き方
    • ちなみにRubyのcase式だとwhenは下げない(elsifと同じという考え方のため)
  • when() の引数に条件を書く
    • when().simple(...) などは禁止する
  • otherwise() は処理が無い場合は省略する

条件には Predicate のインスタンスを指定する。(ドキュメント

  • 自作したクラスを使う
  • header(name)simple("${expr}") などで直接booleanを得る(ValueBuilder)
  • header(name).isEqualTo(value) のようにbooleanを導く(PredicateBuilder)

filter

分岐が when() 1個のみの場合は、 choice() の代わりに filter() の使用を検討する。行数やインデントが減り読みやすくなる。ガード節を書く際などは特に有用。

https://camel.apache.org/components/latest/eips/filter-eip.html

ガード節の例
// ガード節無しだと読みにくい(※これはcamelに限らない)
from("direct:noGuard")
        .choice()
            .when(new MyPredicate())
                .to("mock:doNothing")
            .otherwise()
                .to("mock:doSomething1")
                .to("mock:doSomething2")
                .to("mock:doSomething3")
        .end()
;

// choiceでもガード節は作れるけど、ちょっと大げさ
from("direct:guardByChoice")
        .choice()
            .when(new MyPredicate())
                .to("mock:doNothing")
                .stop()
        .end()

        .to("mock:doSomething1")
        .to("mock:doSomething2")
        .to("mock:doSomething3")
;

// filterだと簡潔
from("direct:guardByFilter")
        .filter(new MyPredicate())
            .to("mock:doNothing")
            .stop()
        .end()

        .to("mock:doSomething1")
        .to("mock:doSomething2")
        .to("mock:doSomething3")
;

split

foreach文に相当する。Listなどの中身を個別に新しいexchangeに詰めて処理する。

https://camel.apache.org/components/latest/eips/split-eip.html

from("direct:sample")
        .split(body()).parallelProcessing()
            .log("content: ${body}")
            .to("mock:abc")
        .end()
;
  • split() の引数に、分割するものを書く
    • split().body() などは禁止する

loop, while

ループ回数をインデックス参照できる(0始まり)。for文のように回数指定する場合は loop() 、while文のように条件指定する場合は loopDoWhile() を使う。

https://camel.apache.org/components/latest/eips/loop-eip.html

from("direct:sample")
        .loop(100).copy()
            .log("index: ${exchangeProperty[CamelLoopIndex]}")
            .to("mock:abc")
        .end()
;

try … catch … finally

例外処理もある。

https://camel.apache.org/manual/latest/try-catch-finally.html

これもJavaの文法に合わせて、 doTry(), doCatch(), doFinally(), end() を同じインデント、それぞれの内部を1段下げることとする。

例: https://github.com/apache/camel/blob/camel-2.25.1/camel-core/src/test/java/org/apache/camel/processor/TryProcessorMultipleExceptionTest.java

TryProcessorMultipleExceptionTest.java
from("direct:start")
        .doTry()
            .process(new ProcessorFail())
            .to("mock:result")
        .doCatch(IOException.class, IllegalStateException.class)
            .to("mock:catch")
        .doFinally()
            .to("mock:finally")
        .end()
;

引数かメソッドチェーンか

以下のメソッドはexchangeにデータを入れるためのもの。

  • setHeader()
  • setProperty()
  • setBody()

これらは入れる値を「引数で指定する」方法と「メソッドチェーンで指定する」方法がある。規約では「引数で指定する」ほうに統一する。routeを構成する1メソッドがそのまま1処理になっているほうが分かりやすいと思う。

構造化のところで when()split() などに対し引数で指定しているのも、同じ考え方に基づく。

// disliked
from("direct:dislikedSample")
        .setHeader("foo").expression(new MyExpression())
        .setProperty("bar").header("foo")
        .setBody().exchangeProperty("bar")
;

// preferred
from("direct:preferredSample")
        .setHeader("foo", new MyExpression())
        .setProperty("bar", header("foo"))
        .setBody(exchangeProperty("bar"))
;

引数には Expression のインスタンスを指定する。(ドキュメント

  • 自作したクラスを使う
  • constant(obj) で直接Javaオブジェクトを指定する
  • header(name)simple("${expr}") などで値を得る

規則の例外

ただし引数指定だと煩雑になる場合はメソッドチェーンにする。この際はなるべく同じ行に続けて書く。

例えば marshal() 。引数に文字列を渡す方法もあるが、タイポなどを防ぐためにできれば用意された定数などを使いたい。そうすると引数の場合の方が長くなってしまう。

from("direct:marshalSample")
        .marshal().json(JsonLibrary.Gson)
        .marshal(new JsonDataFormat(JsonLibrary.Gson))
;

式展開

log() の引数の文字列では、 simple() と同じ式展開(と呼ぶのかは分からない…)が書ける。

https://camel.apache.org/components/latest/languages/simple-language.html

from("direct:loggingSample")
        .log("foo :: ${header[foo]}")
        .log("bar :: ${exchangeProperty[bar]}")
        .log("baz :: ${body}")
;
  • headerやpropertyの要素は、 .name, :name, [name] のどれででも参照できる
    • exchangeの中ではこれらは Map なので、連想配列らしく [name] が良い気がする
    • 必要ない限りは、キーをクォートで括らない
  • headerの要素の参照時には、変数 header を使い headers は使わない
    • route構築に使っているメソッド名に合わせる

メソッド呼び出しなどさらに強力な式も書けるのだが、まだ詳細な規約は決められていない。
https://camel.apache.org/components/latest/languages/ognl-language.html

状況に応じた選択

似たことを異なる方法でできる場合がある。目的に合ったもの、目的に特化したものを選ぶほうが可読性が高い。

ログ出力

2通り用意されている。用途が異なるので迷うことは無いはず。

from("direct:start")
        .log(LoggingLevel.DEBUG, "org.apache.camel.sample", "any message")
        .to("log:org.apache.camel.sample?level=DEBUG&showAll=true&multiline=true")
;

choiceかfilterか

構造化のところで説明した通り。 filter() はif文1個(else無し)の分岐だけを書けると思っていい。

式展開かメソッド組合せか

Simple Expression Language式展開(?)を使えば様々な値や条件式を作れる。一方で、普通の値(ValueBuilder)に対して操作できるメソッドもある。メソッドで書けばコンパイル時点で単純なミスに気付ける可能性が高まるが、良いメソッドが無いと長くなりやすい。どちらが読みやすいかは状況によるので参考程度に。

from("direct:simpleOrValue")
        // create same strings
        .setHeader("sample1", simple("hoge: ${header[hoge]}"))
        .setHeader("sample2", header("hoge").prepend("hoge: "))

        // check same conditions
        .choice()
            .when(simple("${header[CamelSqlRowCount]} != 1"))
                .log("record not unique!")
            .when(header(SqlConstants.SQL_ROW_COUNT).isNotEqualTo(1))
                .log("record not unique!")
        .end()
;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java入門】クラスについて(クラスの定義、インスタンス化、コンストラクタ)

目的

Java言語を含めたプログラミングの学習を始めたばかりの方、既学習者の方は復習用に、
今回はクラスについて学ぶために書いています。

【Java入門目次】
変数と型
型変換
変数のスコープ
文字列の操作
配列の操作
演算子
条件分岐
繰り返し処理
・クラスについて ←今ここ
・抽象クラス(準備中)
・インターフェース(準備中)
・カプセル化(準備中)
・モジュールについて(準備中)
例外処理について
ラムダ式について
Stream APIについて

クラスとは

  • 属性(変数) : そのクラスを元に生成された実体のデータに当たるもの。

    • メンバ変数と呼ばれ、インスタンス変数static変数(クラス変数)の2種類があります。
  • 操作(メソッド) : そのクラスを元に生成された実体の属性を処理するもの。

    • メンバメソッドと呼ばれ、インスタンスメソッドstaticメソッド(クラスメソッド)の2種類があります。

上記をまとめた設計図(雛形)の様なものです。

クラスの定義方法

構文
(修飾子) class クラス名 {
  // メンバ変数
  // メンバメソッド
}

変数の宣言方法

構文と例
// (修飾子) データ型 変数名
String name;
private int age = 5; // 初期化をする事も可能

メソッドの定義方法

構文
// (修飾子) 戻り値の型 メソッド名(引数) { 処理 };

戻り値の型には、メソッドを呼び出し値を返す場合、その返す結果のデータ型を記述します。
(int型同士の計算結果を返したいならint、String型の文字列結合を行って返したいならString)

戻り値を何も返さなくて良い場合は、voidと記述します。

何かしら値を返す場合(void以外の時)、処理の最後にreturn 戻す値(データ型は戻り値の型)としなければいけません。

メソッドの記述例
// 引数に何も受け取らず、戻り値としてString型を返す
public String getName() {
  return // String型の値
}

// 引数にString型の値を受け取り、戻り値は何も返さない
public void setName(String name) { }

// 引数にint型の値を受け取り、戻り値はint型の配列を返す
private int[] getNumbers(int i) {
  return // int型の配列
}

修飾子についての詳しい説明は、別記事にてまとめる予定ですので本記事では割愛します。

では、クラスを作成します。

クラスの例
public class Animal {

  String name; // インスタンス変数
  static int count; // static変数(クラス変数)

  // コンストラクタの定義(コンストラクタについては後述)
  Animal() {
    count++; // countをインクリメント
  }

  // インスタンスメソッド(nameを取得するため)
  public String getName() {
    return name;
  }
  // インスタンスメソッド(nameに値を代入するため)
  public void setName(String name) {
    this.name = name;
  }

  // staticメソッド(countを取得するため)
  public static int getCount() {
    return count;
  }

}

これでAnimalクラスの定義は完了です。

オブジェクトとは

クラス(設計図)を元に作成された実体の事です。設計図だけではプログラムを動かす事が出来ないので、オブジェクトを作成する必要があります。
クラスからオブジェクトを作成するには、newキーワードを用います。これをインスタンス化と言います。

構文
データ型 変数名 = new クラス名();

先ほどのAnimalクラスを元にインスタンス化してみます。

インスタンス化の例
// Animalクラスを定義
class Animal {
  String name;
  static int count;

  Animal() { count++; }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }

  public static int getCount() {
    return count;
  }
}

// Mainクラスを定義
class Main {
  public static void main(String[] args) {

    // catという変数名でオブジェクトを作成(インスタンス化)
    Animal cat = new Animal();
    cat.setName("きなこ"); // catのnameをセット
    System.out.println(cat.getName()); // catのnameを取得
    System.out.println(Animal.getCount()); // Animalクラスのcountを取得

    // dogという変数名でオブジェクトを作成(インスタンス化)
    Animal dog = new Animal();
    dog.setName("小太郎"); // dogのnameをセット
    System.out.println(dog.getName()); // dogのnameを取得
    System.out.println(Animal.getCount()); // Animalクラスのcountを取得

  }
}
実行結果
きなこ
1
小太郎
2

Animalクラス(設計図)を元にcat、dog(オブジェクト)を作成しています。
Animalクラスで定義されている各メソッドを呼び出し、name変数への代入や値の取得、static変数(クラス変数)の値の取得が出来ています。

コンストラクタとは

新たなオブジェクトを作成(インスタンス化)する時に一番初めに実行される処理の事です。

コンストラクタの定義方法は以下になります。

1.クラス内で明示的に定義する
2.明示的に定義しなかった場合はコンパイラによって追加される(クラス内に1つもコンストラクタがない時)

明示的に定義する方法はメソッドと似ていますが、以下のルールに注意しなければいけません。

  • コンストラクタ名はクラス名と同じ
  • 戻り値は持たないので戻り値の型宣言もしない
  • 引数を受け取る事が出来る

コンストラクタの処理には、インスタンス化された時に同時に行っておきたい事を記述します。

構文
(修飾子) コンストラクタ名(引数) {
  // 処理
}

コンストラクタの呼び出し方法は以下になります。

コンストラクタの呼び出し方
new コンストラクタ名()
new コンストラクタ名(引数)

先ほどのAnimal cat = new Animal();は、コンストラクタを呼び出していたという事になります。
クラス内に定義していなかったので、コンパイラによって追加されていたのです
これをデフォルトコンストラクタと呼びます。(明示的にコンストラクタを定義した場合、デフォルトコンストラクタは作成されなくなる。)

では、コンストラクタを明示的に定義して、インスタンス化時に行ってもらいたい処理を記述してみます。

コンストラクタの例
class Animal {

  String name;

  // コンストラクタを定義
  Animal(String name) {
    this.name = name; // 引数で受け取った値をインスタンス変数に代入している
  }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}


class Main {
  public static void main(String[] args) {

    Animal cat = new Animal("きなこ"); // コンストラクタを呼び出し、値を渡している
    // cat.setName("きなこ"); ← コンストラクタがnameをセットしてくれるため、不要になった
    System.out.println(cat.getName());


    // Animal dog = new Animal(); // 引数に何も書かないとコンパイルエラーになる(デフォルトコンストラクタがなくなった為)    
    Animal dog = new Animal("小太郎");
    // dog.setName("小太郎"); ← コンストラクタがnameをセットしてくれるため、不要になった
    System.out.println(dog.getName());

  }
}

この様に初期化作業など行えるため、先ほどは3行で行っていた処理を2行で行う事が出来ました。

オーバーロード

初期化はしたくない時は、何も処理をしない用のコンストラクタを定義しましょう。
明示的にコンストラクタを定義したため、引数なしのデフォルトコンストラクタをコンパイル時に用意してくれなくなった為です。

コンストラクタを複数定義する例
class Animal {

  String name;

  // コンストラクタを定義
  Animal(String name) {
    this.name = name;
  }

  // コンストラクタを定義2 ←追加
  Animal() {
  }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}


class Test {
  public static void main(String[] args) {

    Animal cat = new Animal("きなこ");
    System.out.println(cat.getName());

    // Animal dog = new Animal("小太郎");
    Animal dog = new Animal(); // ←追加 引数に何も書かなくてもエラーにならない
    dog.setName("小太郎"); // ←追加 その代わりに、名前を忘れずにセットする事
    System.out.println(dog.getName());

  }
}

この様に引数の順番やデータ型、数が異なっているという条件を満たしている場合、
同じ名前のコンストラクタを複数定義する事が可能です。

これをオーバーロードと呼び、メソッドも同様に条件を満たしていれば複数定義する事が可能です。

条件を満たしていない場合は、コンパイルエラーになるので注意しましょう。

メソッドのオーバーロードの例
class Animal {

  String name;

  public String getName() {
    return name;
  }

  // OK!
  public String getName(String str, int num) {
    return name;
  }

  // OK!
  public String getName(int num, String str) {
    return name;
  }

  // NG! オーバーロード出来ずコンパイルエラー
  // public String getName() {
  //   return name;
  // }

}

終わりに

オブジェクト指向において基本となるクラスについて学びました。
基本ですのでしっかり理解を深めておきたいですね。
修飾子や継承やインターフェースとまだまだ学ぶ事は多いと感じました。

参考サイト

クラスの基本

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

Kotlinから使えないJavaコード(社内勉強会用)

  • 概要
    • 業務でハマった問題について発表します
    • 実際のところ私もよく分ってないので、ぜひ分かる方はコメント下さい
  • 前提
    • Android Kotlin/JVMで、Java製のLibraryをKotlinから利用

実際にハマったコード

Desk.java
package library_package;

abstract class BaseDesk {
    public enum Color { BLUE, ORANGE }
}

public class Desk extends BaseDesk {
    private Color color;

    public Desk(Color color) {
        this.color = color;
    }
}

こういうJava実装を、Javaから使うのは、当然うまくいく。

java
new Desk(Desk.Color.BLUE);

Kotlinから使うと、Compile Errorになる。

kotlin
Desk(Desk.Color.BLUE) // Unresolved reference: Color
kotlin
import library_package.BaseDesk // Cannot access 'BaseDesk': it is package-private in 'library_package'

Desk(BaseDesk.Color.BLUE) // Cannot access 'Color': it is public in 'BaseDesk'

どう回避したか

この問題を解決するために(だろうか?) getColorEnum() という static method が用意されていた。

Desk.java
package library_package;

abstract class BaseDesk {
    public enum Color { BLUE, ORANGE }

    public static Color getColorEnum(String name) {
        return Color.valueOf(name);
    }
}
kotlin
@Suppress("INACCESSIBLE_TYPE") // suppress warning は必要だが
Desk(Desk.getColorEnum("BLUE")) // DeskコンストラクタにColorインスタンスを入れることが出来た

なぜエラーになったり/ならなかったり?

どういうケースでエラーとなるのか見てみると...

Foo.java
class BaseFoo {
    public static int i = 0;

    public static int inc() {
        return ++i;
    }

    public static class FooFoo {
        public static int j = 0;
    }
}

public class Foo extends BaseFoo {}
java
int foo_i = Foo.i;
int foo_inc = Foo.inc();
int foo_foo_j = Foo.FooFoo.j;
kotlin
val foo_i = Foo.i
val foo_inc = Foo.inc()
val foo_foo_j: Int = Foo.FooFoo.j // Unresolved reference: FooFoo

Kotlinでは、super class の static inner class にアクセスできないようだ。
根拠となる言語仕様を軽く調べてみたが、わからなかった。


なぜメソッドの戻り値としては使えたのか?

Javaは、もともと不可視なクラスを戻り値に定義できるようだ。

public class Bar {
    public static InternalBar getBar() {
        return new InternalBar();
    }

    private static class InternalBar extends Bar {}
}

Bar bar = Bar.getBar(); // OK

Kotlinでは、こんな事はできない。

open class Baz {
    companion object {
        fun getInternalBaz(): InternalBaz { // 'public' function exposes its 'private' return type InternalBaz
            return InternalBaz()
        }

        fun getBaz(): Baz { // OK
            return InternalBaz()
        }
    }
    private class InternalBaz : Baz()
}

INACCESSIBLE_TYPE warning とは?

参照できない場合にエラーとするKotlin Compilerの挙動が、前述のようなJavaの仕様と上手く合致せずにコンパイルできない問題があり、いまはCompile ErrorではなくWarningにしているが、今後適切に、本当にアクセス不可な場合だけコンパイルエラーとするように再変更する予定、ということらしい。

https://youtrack.jetbrains.com/issue/KT-11398 を参照。


もし Library 側に getColorEnum() が用意されてなかったら?

自分でJavaでUtility Methodを作ればよい。

DeskColorResolver.java
import library_package.Desk;

public class DeskColorResolver {
    public static Desk.Color getColor(String name) {
        return Desk.Color.valueOf(name);
    }
}
kotlin
val desk = Desk(DeskColorResolver.getColorEnum("BLUE"))

と書ける。
本当にこれが正解だろうか...?


thanks!

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

51歳(現52)からのプログラミング 備忘 VScodeでjava.awt javax.swing // Java 11 or more recent is required to run

VScodeでjavaを復習してたんだけれど
JFrameの挙動を確認しようとしたら

VScode「vscode Java 11 or more recent is required to run...」

私「うーむ」

VScodeでjava.awt javax.swing をimportする

僕の場合には、eclipseで使ってるjdkがver8なので、VScodeもver8で揃えたいのが前提

  1. windows側の環境設定で jdk 8のパスを指定(省略)
  2. VScode側のsettings.jsonで2項目を指定
  3. VScode側のLanguage Suport for javaのバージョン変更

をやってきます

なお、このエラーには、2020-9月のJDK更新時と、それにVScodeが対応した時に修正されるのかな?なので、この記事はそれまでの限定記事。

2.setting.json

java.homeでjdkの指定
java.configuration.runtimesでjdkの指定

    "java.home": "C:\\Program Files\\AdoptOpenJDK\\jdk-8.0.262.10-openj9",
    "java.configuration.runtimes": [  
        {
          "default":true,
          "name": "JavaSE-1.8",
          "path": "C:\\Program Files\\AdoptOpenJDK\\jdk-8.0.262.10-openj9",
        },
    ],

3.Language Supprt for java

何故か分からないけど、この拡張機能のバージョンを下げないと、エラーになってしまう。intelisense(コード補完機能)に対応させるなら、ver0.57以上ということなので、そこまで下げた。

エラー要因

要因の1つはJDK11のAPI(awt/swing)とwindowsの相性に問題があってエラー。これを改善するには2020年9月のjdk更新まで待つか、jdk8などの古いバージョンで対応するのだけれど、2つ目の要因としてVScodeの仕様でJDK11を求められてしまう。

VScodeはeclipseに準拠してて、eclipseは最新のjdkを推奨するようなのですけど、VScodeは、より強くそういうところを要求するらしいのですよね。なのでVScode側で指定するjdkが推奨バージョンと異なると、実行時エラーにするような仕様のよう。これを回避するには、javaの実行構成を指定するのですね。VScodeの拡張機能(LanguageSupportForJava)のバージョンを下げる理由は分からないけれど、もしかしたらバージョン毎に対応するjdkが違うってことなのかも。

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