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

Liferayのバッチの作成

はじめに

定期的に実行するバッチ処理はシステムよくあります。
Javaのスケジューラのライブラリとしてquartzは有名です。
quartz:http://www.quartz-scheduler.org/

LiferayのスケジューラもQuaryzを採用しております。

Liferayの中でやり方を簡単にまとめます。

QuartzのCron設定フォーマット

image.png

出典:http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html

QuartzのCron設定サンプル

image.png

出典:http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html

Liferayのバッチ実装必要なメソッド

  • activate:OSGiモジュール起動処理
  • deactivate:OSGiモジュール停止処理
  • receive:ビジネスロジック

サンプル

TestBatch.java
package com.test.batch;

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.messaging.DestinationNames;
import com.liferay.portal.kernel.messaging.Message;
import com.liferay.portal.kernel.messaging.MessageListener;
import com.liferay.portal.kernel.messaging.MessageListenerException;
import com.liferay.portal.kernel.scheduler.SchedulerEngineHelper;
import com.liferay.portal.kernel.scheduler.SchedulerEntryImpl;
import com.liferay.portal.kernel.scheduler.TimeUnit;
import com.liferay.portal.kernel.scheduler.Trigger;
import com.liferay.portal.kernel.scheduler.TriggerFactoryUtil;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;

@Component(immediate = true, property = {
}, service =TestBatch.class)
public class TestBatch implements MessageListener {

    private static Log _log = LogFactoryUtil.getLog(TestBatch.class);

    // バッチ起動間隔
    private static int INTERVAL_TIME = 15;

    @Override
    public void receive(Message message) throws MessageListenerException {

        _log.info("バッチ 開始");

        // do something

        _log.info("バッチ 終了");
    }

    @Activate
    @Modified
    protected void activate() {
        String batchClassName = this.getClass().getName();
        // トリガーの設定
        Trigger trigger = TriggerFactoryUtil.createTrigger(batchClassName, batchClassName, INTERVAL_TIME, TimeUnit.MINUTE);
        SchedulerEntryImpl schedulerEntryImpl = new SchedulerEntryImpl(batchClassName, trigger);

        _schedulerEngineHelper.register(this, schedulerEntryImpl, DestinationNames.SCHEDULER_DISPATCH);

        _log.info("Batch is activated.");
    }

    @Deactivate
    protected void deactivate() {
        _schedulerEngineHelper.unregister(this);
    }

    @Reference(unbind = "-")
    private volatile SchedulerEngineHelper _schedulerEngineHelper;

}

ポイントとなるトリガーの作成

image.png
TriggerFactoryUtilクラスに用意されていますので、簡単に作成できます。

CronTrigger: http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html
参考記事:https://portal.liferay.dev/docs/7-1/tutorials/-/knowledge_base/t/message-listeners

以上

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

Javaにおけるtransient修飾子とシリアライズに関して

初めてtransientというフィールド修飾子に遭遇したのでメモ。

private transient long originalTime;

一般的な説明

transientを付与すると該当のフィールドは直列化の対象外となる。
該当の変数を持つクラスを直列化しようとして、NotSerilizabaleExceptionが発生した際にこの修飾子を付与するととりあえず例外は発生しなくなる。

直列化ってなに?

直列化以外にも、シリアライズ、シリアル化などと呼ばれる。
オブジェクトと直列化することはオブジェクトの情報をストリーム化し、ファイルとして保存 or ネットワークを介してやり取りすることが可能になるっぽい。要するにJavaのオブジェクトをバイト列として出力するということ。

どういう時に直列化できないの?

そもそもオブジェクトによっては直列化できる・できないが決まっている。そのようなオブジェクトを持っているクラス自体を直列化しようとすると前述の例外が発生すると思われる。

直列化する方法

あるクラスを直列化するにはjava.io.Serializableを実装すればいい。 シリアライズ化可能ですよー、という証でこのinterfaceを実装すると良い。

個人的なまとめ

  • Javaオブジェクトをファイルに保存したり、ネットワーク経由で伝達する場合は直列化(シリアライズ)が必要。
  • 特定のクラスを直列化するにはSerializableを実装する必要がある。
  • クラスを直列化した時にNotSerilizabaleExceptionが発生することがある。
  • 直列化の対象外にするためにtransientを使う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HiveRunner を試す

モチベーション

Hive のクエリのテストしたい。

mysql だったら、docker-compose とか比較的簡単にテストできるけど、hiveのクエリのテストも同じようにしたいけど、どうしたらいいですかね。(docker で ゴニョゴニョするのはちょっと辛そう..)

ってわけで良さそうなプラグインを適当に選んで試してみました。

選んだのは、公式でいくつか紹介されているツールの中で git のスターが一番多かった HiveRunner です。(バージョンは 4.1.0)

準備

HiveRunner は基本的に Junit のテストとして、クエリのテストをします。

外部の依存関係は必要なく、JVM上にHiveServerを立てて、Junit がそのHiveServerhive sql を実行するイメージみたいです。

今回は maven でプロジェクトを作っていきます。
以下、今回実行する際の pom です。 特に理由はありませんが、BEELINE のエミュレータを指定しています。

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.21.0</version>
            <configuration>
                <forkMode>always</forkMode>
                <systemProperties>
                    <!-- Defaults to HIVE_CLI, other options include BEELINE and HIVE_CLI_PRE_V200 -->
                    <commandShellEmulator>BEELINE</commandShellEmulator>
                </systemProperties>
            </configuration>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>com.klarna</groupId>
        <artifactId>hiverunner</artifactId>
        <version>4.1.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

とりあえず実行してみる

@RunWith(StandaloneHiveRunner.class)
public class TestHiveRunner {
    @HiveSQL(files = {})
    private HiveShell shell;

    /*
     * DB と テーブルを作成
     */
    @Before
    public void setupSourceDatabase() {
        shell.execute(
                "CREATE DATABASE source_db; " +
                "CREATE TABLE source_db.test_table (year STRING, value INT);");

        shell.execute(
                "CREATE DATABASE my_schema; " +
                "CREATE EXTERNAL TABLE my_schema.result " +
                "(year STRING, value INT) " +
                "STORED AS PARQUET " +
                "TBLPROPERTIES (\"parquet.compress\"=\"snappy\")");
    }

    @Test
    public void testMaxValueByYear() {
        /*
         * 集計対象のテーブルにテストデータを格納
         */
        shell.insertInto("source_db", "test_table")
                .withColumns("year", "value")
                .addRow("2014", 3)
                .addRow("2014", 4)
                .addRow("2015", 2)
                .addRow("2015", 5)
                .commit();

        /*
         * 集計クエリを実行 (INSERT クエリ)
         */
        shell.executeStatement("INSERT INTO my_schema.result " +
                "SELECT " +
                "   year, " +
                "   MAX(value) " +
                "FROM " +
                "   source_db.test_table " +
                "GROUP BY year");

        /*
         * 集計結果が INSERT されているテーブルから結果を取得
         */
        List<Object[]> result = shell.executeStatement("SELECT * FROM my_schema.result");

        assertEquals(2, result.size());
        assertArrayEquals(new Object[]{"2014",4}, result.get(0));
        assertArrayEquals(new Object[]{"2015",5}, result.get(1));
    }
}

上記ほとんど Example に載っているコードをちょっと書き換えたものです。

とても簡単にテストすることができるように見えます。

切り出して置いたクエリの読み込みや、テストデータのインサートが多くなってきて別途tsv等に切り出した場合など、それらを読み込むこともできます。

それぞれちょっとだけ見ていく

@HiveSQL

// デフォルトで src/test/resources ディレクトリを参照している。
@HiveSQL(files = {"create_test_table.sql", "create_max.sql"})
private HiveShell shell;

files = {} にSQLファイルを指定することで、インスタンスが作られた後に自動で実行してくれる。

@HiveSQL(files = {...}, autoStart = false) とすることで、任意のセットアップを行なった後、起動させることができる。(start()メソッドをコールする)

ちなみに、任意のセットアップで設定出来る項目は以下のようなものがあります。(オーバーロードされているメソッド多々あり.)

// HiveConf を設定
void setProperty(String key, String value);
void setHiveConfValue(String key, String value);

// テストデータを HDFS にコピー
void addResource(String targetFile, File sourceFile);

// HiveShell起動時に実行されるスクリプトの登録
// @HiveSetupScript でも同様だが、以下はスクリプトの実行順序が保証される。
void addSetupScript(String script);
void addSetupScripts(Charset charset, File... scripts);

// stream を開いて、テストデータを HDFS に書き込んでくれるらしい
OutputStream getResourceOutputStream(String targetFile);

execute

// 直書き
shell.execute("CREATE DATABASE source_db; " +
        "CREATE TABLE source_db.test_table (year STRING, value INT);");


// 切り出されたSQLの読み込みも可
shell.execute(Paths.get("src/test/resources/calculate_max.sql"));

返り値なしの、スクリプト(クエリ)実行。

; で区切ることで、複数のクエリを実行できる。

複数のクエリを実行できるから、返り値がないってことですかね。

executeQuery & executeStatement

// 下記、executeQuery でも同様に実行できる。
shell.executeStatement("INSERT INTO my_schema.result " +
        "SELECT " +
        "   year, " +
        "   MAX(value) " +
        "FROM " +
        "   source_db.test_table " +
        "GROUP BY year");

// executeQuery に限り、切り出されたSQLの読み込みも可
shell.execute(Paths.get("src/test/resources/calculate_max.sql"));

execute と異なり、複数のクエリを一回で実行することはできないし、文末に ; が含まれるとエラーになる。

その代わり、List<String> でクエリの実行結果が返ってくる。

insertInto

shell.insertInto("source_db", "test_table")
        .withColumns("year", "value")
        .addRow("2014", 3)
        .addRow("2014", 4)
        .addRow("2015", 2)
        .addRow("2015", 5)
        .commit();

// tsv 等からデータをインサートすることもできる。
shell.insertInto("source_db", "test_table")
        .withColumns("year", "value")
        .addRowsFromTsv(new File("src/test/resources/insert_data_of_test_table.tsv"))
        .commit();

このメソッドは、commit() しないと実行されない。

テストデータの準備はめんどくさいですが、tsvでインサートしてくれるのはとても便利ですね。

まとめ

クエリのテストやちょっとクエリ試したいときなど、(ちょっと重い感じがしますが)使えそうですね。

一方で、カラム数が多いテーブルだったり、テストデータの量が多い場合のテストだったり、めっちゃ複雑なクエリのテスト等では、メモリや実行速度的に辛そうですが、どうなるのでしょうか (READMEに対処法など書いてありますが..)

とはいえ、pomhiverunner を入れるだけで、hivesql のテストができるのは魅力的ですね。

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

【Kotlin】Javaの可変長引数にKotlinのArrayを渡す【Java】

やること

以下のような関数にKotlinのArrayを渡します。

void hoge(HogeClass... hogeClasses) {
  /* 省略 */
}

やり方

以下のように、Arrayの前に*を入れることでできます。

val hogeList: Array<HogeClass> = // 初期化は省略

// 呼び出し
hoge(*hogeList)

やっていること

先頭に補っている*はSpread演算子で、Arrayの展開を行なって渡しています。

Kotlinではfuga(vararg hoge: HogeClass)というように宣言することで可変長引数を利用できますが、ここにArrayを渡すときも同様にする必要があります。

参考にさせて頂いたサイト

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

JAVA(超超超基本編:GitBush編)

初学者だった僕にとってはかなりきっちりしてる言語だなーと感じてました。
つまずきばかりでしたが慣れてくれば理解度は深まったように思えます。

その前にコードのやり取りはdiscordがいいみたいでよく使用してます。
多人数で開発又は教育開発をする場合は便利だと思われます。

まず初めに場所を確認する

pwd /*現在の場所表示を確認する*/

文字化け防止に

vi ~/.bashrc 

これを貼り付けとく

  alias javac='javac -J-Dfile.encoding=UTF-8'
   alias java='java -Duser.language=ja -Dfile.encoding=UTF-8'
   sc(){
   start chrome $1
   }

抜けてセーブ

 ctrl + c から:wq 

任意の場所に移動する

cd フォルダ名 //cd test/test2と時短移動も可能

フォルダを作成する

mkdir フォルダ名

移動したフォルダにvimでファイルを作り開く

vi フォルダ名.java

記述してみる

public class Main{
  public static main(String[] arrgs){
     System.out.println("Hello World!");
  } 
}

セーブ

ctrl + c でインサートモードを抜けて:wq

コンパイル

$ javac Main.java

コンパイル

$ java Main
Hello World! //と出力されればok

以上かなっと

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

AndroidからPCへ加速度センサの値をUDPで送信する

プログラムの概要

今回のプログラムは、C#のコンソールアプリケーションで作成したサーバにAndroidの加速度センサの値をUDP通信で送信するものである。基本的にAndroid側で通信の制御をするので、C#側はただのエコーサーバを用いている。

プログラムのソースコード

activity._main.xml
<EditText
        android:id="@+id/IP_Address"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="52dp"
        android:layout_marginEnd="16dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="192.168.0."
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/Port"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="48dp"
        android:layout_marginEnd="16dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="8080"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/IP_Address" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="280dp"
        android:text="X:"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:text="Y:"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:text="Z:"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2" />

    <TextView
        android:id="@+id/X_Data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="280dp"
        android:text="TextView"
        android:textSize="32sp"
        app:layout_constraintStart_toEndOf="@+id/textView"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/Y_Data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="TextView"
        android:textSize="32sp"
        app:layout_constraintStart_toEndOf="@+id/textView2"
        app:layout_constraintTop_toBottomOf="@+id/X_Data" />

    <TextView
        android:id="@+id/Z_Data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="TextView"
        android:textSize="32sp"
        app:layout_constraintStart_toEndOf="@+id/textView3"
        app:layout_constraintTop_toBottomOf="@+id/Y_Data" />

    <TextView
        android:id="@+id/textView7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="230dp"
        android:text="加速度センサの値"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/Ran"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="87dp"
        android:layout_marginLeft="87dp"
        android:layout_marginBottom="70dp"
        android:text="通信開始"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="IPアドレス"
        android:textSize="24sp"
        app:layout_constraintBottom_toTopOf="@+id/IP_Address"
        tools:layout_editor_absoluteX="16dp" />

    <TextView
        android:id="@+id/textView5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="ポート番号"
        android:textSize="24sp"
        app:layout_constraintBottom_toTopOf="@+id/Port"
        tools:layout_editor_absoluteX="16dp" />

    <Button
        android:id="@+id/End"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="87dp"
        android:layout_marginLeft="87dp"
        android:layout_marginEnd="87dp"
        android:layout_marginRight="87dp"
        android:layout_marginBottom="70dp"
        android:text="通信解除"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/Ran" />
MainActivity.java
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class MainActivity extends AppCompatActivity implements SensorEventListener{

    private SensorManager sensorManager;
    private TextView X_Data_TextView;   //加速度センサXの値
    private TextView Y_Data_TextView;   //加速度センサYの値
    private TextView Z_Data_TextView;   //加速度センサZの値
    private String Data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        X_Data_TextView = findViewById(R.id.X_Data);
        Y_Data_TextView = findViewById(R.id.Y_Data);
        Z_Data_TextView = findViewById(R.id.Z_Data);



        Button ran = findViewById(R.id.Ran);
        Button end = findViewById(R.id.End);
        ran.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                final String address = ((EditText) findViewById(R.id.IP_Address)).getText().toString();
                String port = ((EditText) findViewById(R.id.Port)).getText().toString();
                int Port = Integer.parseInt(port);
                byte buf[] = new byte[Data.length()];

                try {
                    buf = Data.getBytes("SHIFT_JIS");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                InetSocketAddress inetSocketAddress = new InetSocketAddress(address, Port);
                final DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, inetSocketAddress);

                    AsyncTask<DatagramPacket, Void, Void> task = new AsyncTask<DatagramPacket, Void, Void>() {
                        @Override
                        protected Void doInBackground(DatagramPacket... datagramPackets) {
                            DatagramSocket datagramSocket = null;
                            try {
                                datagramSocket = new DatagramSocket();
                                datagramSocket.send(datagramPackets[0]);
                                datagramSocket.close();
                                //TimeUnit.MILLISECONDS.sleep(500);
                            } catch (SocketException e) {
                                e.printStackTrace();
                            } catch (IOException e) {
                                e.printStackTrace();
                            } //catch (InterruptedException e) {
                               // e.printStackTrace();
                            //}

                            return null;
                        }

                    };
                    task.execute(datagramPacket);

            }
        });

        end.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final String address = ((EditText) findViewById(R.id.IP_Address)).getText().toString();
                String port = ((EditText) findViewById(R.id.Port)).getText().toString();
                int Port = Integer.parseInt(port);
                String exit = "exit";
                byte buf[] = new byte[exit.length()];

                try {
                    buf = exit.getBytes("SHIFT_JIS");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                InetSocketAddress inetSocketAddress = new InetSocketAddress(address, Port);
                final DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, inetSocketAddress);

                AsyncTask<DatagramPacket, Void, Void> task = new AsyncTask<DatagramPacket, Void, Void>() {
                    @Override
                    protected Void doInBackground(DatagramPacket... datagramPackets) {
                        DatagramSocket datagramSocket = null;
                        try {
                            datagramSocket = new DatagramSocket();
                            datagramSocket.send(datagramPackets[0]);
                            datagramSocket.close();
                        } catch (SocketException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return null;
                    }

                };
                task.execute(datagramPacket);

            }
        });

    }



    @Override
    protected void onResume(){
        super.onResume();
        //Event Listener登録
        Sensor accel = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sensorManager.registerListener((SensorEventListener) this,accel,SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause(){
        super.onPause();
        //Event Listener登録解除
        sensorManager.unregisterListener((SensorEventListener) this);
    }

    @Override
    public void onSensorChanged(SensorEvent event){
        if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
            X_Data_TextView.setText(String.format("%.3f",500+(event.values[0])*25));
            Y_Data_TextView.setText(String.format("%.3f",500+(event.values[1])*25));
            Z_Data_TextView.setText(String.format("%.3f",500+(event.values[2]) *25));
            Data = (500+event.values[0]*25) + " " +
                    (500+event.values[1]*25) + " " +
                    (500+event.values[2]*25);
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy){

    }
}

Program.cs

static void Main(string[] args)
        {
            //バインドするローカルIPとポート番号
            string localIpString = "192.168.0.16";
            System.Net.IPAddress localAddress =
                System.Net.IPAddress.Parse(localIpString);
            int localPort = 8080;

            //UdpClientを作成し、ローカルエンドポイントにバインドする
            System.Net.IPEndPoint localEP =
                new System.Net.IPEndPoint(localAddress, localPort);
            System.Net.Sockets.UdpClient udp =
                new System.Net.Sockets.UdpClient(localEP);

            int i = 0;
            string[] xyz = { "X", "Y", "Z" };
            for (;;)
            {
                //データを受信する
                System.Net.IPEndPoint remoteEP = null;
                byte[] rcvBytes = udp.Receive(ref remoteEP);

                //データを文字列に変換する
                string rcvMsg = System.Text.Encoding.UTF8.GetString(rcvBytes);
                string[] RcvMsg = rcvMsg.Split(' ');
                //受信したデータと送信者の情報を表示する

                //"exit"を受信したら終了
                if (RcvMsg[0] =="exit")
                {
                    break;
                }

                for (i = 0; i < 3; i++) {
                    Console.WriteLine("{0}:{1}",xyz[i], RcvMsg[i]);
                }

                Console.WriteLine("送信元アドレス:{0}/ポート番号:{1}",
                    remoteEP.Address, remoteEP.Port);


            }

            //UdpClientを閉じる
            udp.Close();

            Console.WriteLine("終了しました。");
            Console.ReadLine();
        }

動作結果

キャプチャUDP.PNG
サーバ.PNG

課題

今回はサーバをコンソールアプリケーションで作成したが、フォームアプリケーションでの作成を目指している。

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

vim

html&cssを書くのにAtomを最初に使用していたのですが。。
JAVAを使いだしてからはすぐにGitbBshHerを導入してvimで記述しております。

最初のうちは扱いずらいなーと思ってましたが慣れたら作業的にもかなり時短になるなと個人の感想。

よくわかってませんしたがvimはかなり渋いらしいです。

*未完成*

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

vim(gitbush)基本編

html&cssを書くのにAtomを最初に使用していたのですが。。
JAVAを使いだしてからはすぐにGitbBushを導入してvimで記述しております。
(macならターミナルでいいらしい)

GitbBushとは
簡単に言えば、命令を画面に打ち込みコンピュータが命令に従いファイルの操作やファイルの編集、削除といった操作ができるソフトウェアです。
よくUnixやLinuxといったOSに搭載されており、Unixコマンドと言われているコマンドを打ち込むことで様々な命令を出すことができます。
つまり、Git BashとはGitの機能が搭載されたBashというものになります。

最初のうちは扱いずらいなーと思ってましたが慣れたら作業的にもかなり時短になるなと個人の感想。

よくわかってませんしたがvimはかなり渋いらしいです。

title
インストール手順は上を参照

次にvimtutorを触ってみました。

$ vimtutor

モード切替

内容 キー
インサート i
ノーマル ctrl + c

移動コマンド

内容 キー
w
s
d
a

保存関係

内容 キー
save /wq
何もせずぬける /q!
複製 /w ファイル名.java

行番号

内容 キー
:set number
:set nonumber

コピペ、消す

内容 キー
ヤンク(コピー) yy
消す(デリート) dd

上に行数+(3yy)で便利に

以上基本的に覚えて損がなかったコマンドでした。

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

Java基礎学習内容9(ラムダ式)

概要

ラムダ式…命名せずに定義する関数(=無名関数)の記法の一つ。
引数と処理を記述する。

記法

ラムダ式(基本文法)
 Function<int> func1 = (int num) -> { return num + 1};
 Function<int> func2 = num -> { return num + 2};
 Function<int> func3 = num -> num + 3;

※引数の型はインターフェイス宣言時に決定するため省略可能
※引数が一つの場合、引数の()を省略可能
※処理が一行な場合、{}およびreturnを省略可能。

使い道

ラムダ式を引数とするメソッドを活用すれば、処理の一部を引数として渡すことが可能となる。
・Stream関連
・ArrayListのreplaceAll
・自作メソッド
等々…
一例として、(前記事)参照

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

Java基礎学習内容8(Java API)

java.lang.Obcect

全てのクラスのスーパークラスとなるもの。
boolean equals(Object hoge) → オブジェクトのインスタンスが等しいかを比較
final Class<?> getClass() → オブジェクトの実行時のクラスを返す
int hachCode() → オブジェクトのハッシュコード値を返す
String toString() →オブジェクトをStringに変換する

java.lang.Math

数学ライブラリを提供するもの。

static final double E → 定数e(自然対数の定数)
static final double PI →定数π(円周率)

static double random() → 0.0~1.0の一様分布乱数を返す

java.time

日付・時間を扱うもの。
java.util.Dateの不備を解消するため導入された(?)

日付をLocalDate、時間をLocalTime、日付+時間をLocalDateTime、期間をPeriodで扱う。

現在時刻によるインスタンス化(now)、時刻などを設定したインスタンス化(of)に加え、文字列からの変換(parse)や日付の加減算(plusDays)など、様々な機能を備える。

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

DIとか@Autowiredとかインジェクションの意味がよく分からなかったので調べてみた

目的

「依存性の注入ってなんだよ!!DIってなんだよ!!」と思っている方が
読み終わる頃には「DIって依存性の注入だよね~」となれることを目標としています。

私が「DIって依存性の注入だよね~」となったのは土岐さんスライドを読んだ時でした。
https://www.slideshare.net/KouheiToki/dispring

土岐さんのスライドを読めば私の記事を読む必要はありません。
でも、読んで欲しいのでしばしお付き合いよろしくお願いします!!

DIについて整理できなかった部分

はじめてDIに触れたのはSpringの@Autowiredをつかった時でした。
転職してきて半年くらいたった時のことです。
今までJavaの参考書には「クラスを使うときにはnewすべし」と書いてあるのに現場では全然そんなことをやっていなくて大変困惑しました。

Sample.java
@Autowired
Test test;
test.sayHello();

で動いているから、インターフェースとかその実装とかのことも全然知らない当時の自分には全く意味不明でした。
魔法で動いてるのかよ!!と

そこでこの訳の分からない@Autowiredとやらをサイトや参考書で調べると

依存性の注入(Dependency Injection)

全く意味不明!!!
この言葉にはずいぶん悩まされました。そして説明や例をつかった実装を読んでもピンと来ず。
ただ土岐さんのスライドを読んで

DI→ただのデザインパターン
DIコンテナ→DIを実現してくれるフレームワーク(@Autowiredはこっちの話)

ということを知り、参考書で読んだことが自分の中で整理されました。
ということで@Autowiredを調べる前に知るべきはDIです。
DIとは何かについて知るために

1. DIのDってなんだ
2. 依存してると何が問題か
3. DIのIってなんだ

の順に書きたいと思います。

1.DIのDってなんだ

例えば勤怠監視プログラムがあったとします。
勤怠監視プログラムは、朝の弱いA君が始業時間に出勤していない場合、A君に連絡を取って居場所を教えてくれます。

Main.java
public class Main {
    public static void main(String[] args) {
        // A君の情報をセット
        SomeOne aKum = new Akun();
        aKum.setName("A君");
        aKum.setNumber(09095171835);
        AttendanceMonitor monitor = new AttendanceMonitor();
        // monitor.tellWhereHeIs(aKum)はA君の居場所を教えてくれる。
        String akumsPlace = monitor.tellWhereHeIs(aKum); 
    }
}
AttendanceMonitor.java
class AttendanceMonitor {
    private Call call;// 居場所を確認するための電話をかけるクラス
    AttendanceMonitor() {
        // 今回のテーマのDの部分
        call = new Call();
    }
    public String tellWhereHeIs(Latecomer latecomer) {
        return call.findOnesPlace(latecomer);
    }
}

この例ではAttendanceMonitorクラスがCallクラスに依存しています。
そもそも依存とは何か。
日本語のWikipediaには明確には書いていなかったので英語のWikipediaより

A "dependency" is an object that can be used, for example as a service.

依存性とはサービス(処理的な意味ですかね?)として使われるオブジェクトなど、的な意味だと思います。
依存性はオブジェクトのことを指しているのです。
今回の場合はAttendanceMonitorクラスがCallクラスを使っているので、
AttendanceMonitorクラス内でnewされているCallクラスは"dependency"です。

CallクラスをnewせずにはAttendanceMonitorを生成できない状態を依存(D)していると言います。

2.依存してると何が問題か

依存性があるオブジェクトは変更の対応に柔軟ではありません。

今回の例だとA君には電話で連絡を取っています。
ただ、毎回毎回電話するのは面倒くさい。電話代もかかるし。
なのでLineでの連絡に変更になったとしましょう。

その場合、Callクラスに依存していると以下のように変更する必要があります。

AttendanceMonitor.java
class AttendanceMonitor {
    //private Call call;// Lineに変更になったので削除
    private Line line;
    AttendanceMonitor() {
        //call = new Call();// Lineに変更になったので削除
        line = new Line ();    
    }
    public String tellWhereHeIs(Latecomer latecomer) {
        // String onesPlace = call.findOnesPlace(latecomer);// Lineに変更になったので削除
        return line.findOnesPlace(latecomer);
    }
}

連絡方法を変更しただけなのにAttendanceMonitorを3箇所変更しました。
今回は例なので3箇所ですが、実際の業務で使われるコードではもっと変更箇所があるかもしれません。
AttendanceMonitorを修正したので、AttendanceMonitorを単体テストする必要もあります。

依存していると変更の対応に柔軟ではありません。

この解決策が注入です。
つまりDIのI(Injection)の部分です。

3.DIのIってなんだ

今回の使っている例ではAttendanceMonitorクラスがCallクラスに依存しています。
もしA君と連絡をとる手段をLineなどに変更したくなった場合、AttendanceMonitorクラスに修正をする必要がありました。
この変更に対して柔軟性がない状態は、
インターフェースを実装してインスタンスを注入すれば解決です

AttendanceMonitor.java
class AttendanceMonitor {
    //private Line line; 
    private Contact contact;// 連絡手段のインターフェース
    AttendanceMonitor(Contact contact) {
        //line = new Line (); // 依存するクラスをnewでインスタンス化しない
        // 呼び出し元(Mainクラス)から渡されたインスタンスを使う
        contact = contact; 
    }
    public String tellWhereHeIs(Latecomer latecomer) {
        return contact.findOnesPlace(latecomer);
    }
}
Line.java
public class Line implements Contact {
    @Override 
    public String findOnesPlace(Latecomer latecomer){
       //遅刻してきた人にラインで連絡をとり、居場所を返却してくれる体の処理
    }
}
Contact.java
public interface Contact{
    public String findOnesPlace(Latecomer latecomer);
}

AttendanceMonitor は外部からクラスを注入されることによって連絡手段のクラスへの依存が解消されました。
AttendanceMonitor 内でnewしてインスタンスを作っていません。

外部のクラスとは、今回の例ではMainクラスです。

Main.java
public class Main {
    public static void main(String[] args) {
        // A君の情報をセット
        SomeOne aKum = new Akun();
        aKum.setName("A君");
        aKum.setNumber(09095171835);
        // 使う側でインスタンス化して依存性を注入!!!
        Line line = new Line(); 
        AttendanceMonitor monitor = new AttendanceMonitor(line);
        monitor.tellWhereHeIs(aKum); 
    }
}

MainクラスからA君への連絡方法のインスタンスを渡してあげることによってAttendanceMonitor は疎結合になるのです。
そうすれば今後A君をドローンで探そうと、なにかもっと便利な連絡手段で探そうと、変更は使う側のクラスだけになります。

依存性の注入のおかげです。

DIって依存性の注入だよね(まとめ)

DIとはデザインパターンでした。
クラス内でnewしている部分を依存していると言い、それを解消するために呼び出し元からnewしたいクラスを渡してあげる。
このことが理解できたら

Sample.java
@Autowired
Test test;
test.sayHello();

もわかりました。
DIコンテナはDIなど色々(AOPなど?)実現してくれるフレームワークということです。
@Autowiredなんて奇妙なものがついてるけど、実際やっていることはSampleクラスにTestクラスをコンストラクタで渡しているだけ!!(だけじゃないと思うけど)

結局「DIって依存性の注入だよね~」

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

Java基礎学習内容7(例外)

独自例外クラスの定義方法

独自例外
  public class MyException extends Exception {
    ...
  }

try

tryブロック内で例外が発生した場合処理を中断し、catchブロックの処理を行う。

try
  ...
  void method(){
    try{
      ...
    } catch (MyException1 | MyException2 e){
      ...
    } catch (MyException3 e){
      ...
    } finaly {
      ...
    }   
  }

# throws, throw
メソッドから呼び出し元に例外を渡す可能性がある場合、throwsを用いる。
また、明示的に例外を投げる場合throwを用いる。l

```java:throws
class classA {
  void methodA() throes MyExceptionA {
    ...
    if(isError){
      throw new MyException();
    }
    ...
  }

}

※スーパークラスのメソッドでthrowsを定義していたとしても、サブクラスの同意メソッドでthrowsを記述しないことは可能・

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

Java基礎学習内容6(継承・抽象クラス・インタフェース)

継承

既存クラスを元に新しいクラスを定義する。(元となるクラス=スーパークラス、新しく定義するクラス=サブクラス
この際、スーパークラスのメソッドやフィールドは受け継がれる。
※アクセス修飾子がprivate,修飾子なしのメソッド・フィールドにはアクセス不可
※複数のスーパークラスを継承する(多重継承)は不可(ただしサブクラスをスーパークラスとした継承は可)
※final修飾子のついたクラスは継承不可

継承
class SubClass extends SuperClass {
  ...
}

サブクラスでは、スーパークラスのメソッドの処理を上書きするオーバーライドが可能

オーバーライド
class SubClass extends SupreClass {
  @Override methodA() {
    super.methodA(); //既存メソッドの処理を実行
    ...
  }
}

オーバーライドするためには以下の条件を満たす必要がある。
・メソッド名、引数が同一であること
・戻り値は元メソッドと同じかサブクラスであること
・アクセス修飾子は元メソッドと同じかより公開範囲が広いこと
・final修飾子のついていないメソッドであること

抽象クラス

処理内容を定義しないメソッドを含むクラス。
※abstract修飾子はアクセス修飾子より後、class・戻り値の型より前に記述すること。
※abstractをつけたメソッドには{}を付けないこと。

抽象クラス
abstract class AbsClass {
  public abstract void methodA();
}

インタフェース

実装が必要なメソッドを定義したクラス。
※SE8からはデフォルトの実装とstaticメソッドが定義できるようになった。

インターフェイス
public interface InterfaceSampl(){
  public abstract void methodA();
  default void methodB(){
    ...
  }
}

※インターフェイスは多重継承が可能である。
※private,protectedなメソッドはコンパイルエラーとなる
※コンパイル時に暗黙でpublic abstractに変換される。

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

等差数列を使った数当てゲームを作ったけれど、空白に納得できない話

yoritoです。最近はHuawei Mate30 proが欲しすぎて困っています。スマホの進化はすごい。でもその前にAndroidをエミュレートしてもフリーズしないノートパソコンを給料で買わないといけないんだ。

今日はJavaで等差数列ゲームを作りました。
空白に納得がいかない話は後ほどします。

縦横に等差数列を作り出し、最後の数値を100にしよう

4つ数値を入力するとタテとヨコに等差数列を弾き出してくれるプログラムです。
例えば A, B, C, D に 1, 3, 2, 4 と入力します。

1 3
2 4

そしてコンパイルすると、

1 3 5 7 9 11 13
2 4 6 8 10 12 14
3 5 7 9 11 13 15
4 6 8 10 12 14 16
5 7 9 11 13 15 17
6 8 10 12 14 16 18
7 9 11 13 15 17 19
最後の数字は19です
100ではありません

という風に等差数列を出力してくれます。
右下の数値をうまいこと100にできたらクリアです。上の場合は19なのでまだまだですね。
以下がコードです。

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner sccaner = new Scanner(System.in);

        // 縦マス、横マスの数
        int tate = 7;
        int yoko = 7;

        System.out.print("マスAの値を入力:");
        int masuA = sccaner.nextInt();
        System.out.print("マスBの値を入力:");
        int masuB = sccaner.nextInt();
        System.out.print("マスCの値を入力:");
        int masuC = sccaner.nextInt();
        System.out.print("マスDの値を入力:");
        int masuD = sccaner.nextInt();

        // b_a は、マスAからマスBへの増加数を求める変数
        // d_c は、マスCからマスDへの増加数を求める変数
        int b_a = masuB - masuA;
        int d_c = masuD - masuC;

        // 1行目を出力
        int x = 0;
        for (int e = 0; e < yoko; e++) {
            System.out.print(masuB - b_a + x + " ");
            x += b_a;
        }
        System.out.println("");

        // 2行目を出力
        int y = 0;
        for (int f = 0; f < yoko; f++) {
            System.out.print(masuD - d_c + y + " ");
            y += d_c;
        }
        System.out.println("");

        // 3行目以降を出力
        // toleranceは行が降りる毎に公差はどれだけ増えていくかを求めている。

        int c_a = masuC - masuA;
        int fitFirstTerm = 0;
        int addTolerance = 0;
        int tolerance = d_c - b_a;
        int target = 0;

        for (int g = 0; g + 2 < tate; g++) {
            int nextTerm = 0;
            // 行が終わったら再定義してリセットする。

            for (int h = 0; h < yoko; h++) {
                System.out.print(masuC + c_a + fitFirstTerm + nextTerm + " ");
                // masuC + c_a で、3行目の初項が求まる。

                if (h - 2 == g) {
                    target = masuC + c_a + fitFirstTerm + nextTerm;
                }
                // 出力された表の最後の数字を求める。

                nextTerm += d_c + tolerance + addTolerance;
                // 項が進むたびに公差が足されていくところ。
            }

            fitFirstTerm += c_a;
            // 行が降りる度に初項に公差が足されていくので、fitFirstTermで補正する。
            addTolerance += tolerance;
            // addToleranceを使い、行が降りる度に公差が追加されていくようにする。
            System.out.println("");

        }

        System.out.println("最後の数字は" + target + "です");
        if (target == 100) {
            System.out.println("クリアです!");
        } else {
            System.out.println("100ではありません");
        }

    }
}

こんな感じです。
法則性をつかむと意図して100を出せたりするので、暇なときに遊ぶと楽しいかもしれない。

空白に納得がいかない

ここからが本題です。
出力された数値を空白で切り離すのに四苦八苦していました。

数値を出力するときにSystem.out.printlnを使うと改行されてしまって表として成り立たなくなるので、改行されないSystem.out.printを使っています。
しかし数値をそのまま繰り返し出力するだけだと、数値が連続してしまうので見づらくなってしまいます。最初の例だと一行目が135791113になって数値の区切りがわかりません。
そこで、出力内容の最初に半角スペースを文字列として入れました。
これなら区切りを付けつつ上手くいけるだろう。と思ったら……

// 1行目を出力
        int x = 0;
        for (int e = 0; e < yoko; e++) {
            System.out.print(" " + masuB - b_a + x);
            x += b_a;
        }

なぜかエラーが出て出力ができない。
「演算子 - は引数の型 String, int で未定義です」
なんじゃこりゃ。

試しに半角スペースを文頭ではなく文末に入れてみると……

// 1行目を出力
        int x = 0;
        for (int e = 0; e < yoko; e++) {
            System.out.print(masuB - b_a + x + " ");
            x += b_a;
        }

こっちだと問題なくコンパイルできる。この違いがよくわからない。

ただこの場合だと、出力された行の最後に当然余計な半角スペースが付いてしまい、あまり美しくない。
そこで僕が考えた解決策がこちら。

// 1行目を出力
        int x = 0;
        for (int e = 0; e < yoko; e++) {
            System.out.print(masuB - b_a + x);
            if (e != yoko - 1) {
                System.out.print(" ");
            }
            x += b_a;
        }

if文を使って、行の最後の数値を出力するときは半角スペースを出力しないようにする。
これならちゃんと半角スペースで区切りができるし、文末に余計な半角スペースも付かない。一件落着!
と一瞬思ったものの、解決策があまりにも強引すぎるのではないかと感じてしまい、結局は最初の策を採用しました。とはいえこれもこれで絶対スマートではない気がする。結局文末に余計な半角スペースが付いてしまうし。

うまいこと出力される値を切り離す綺麗な方法がどうしてもわからなかったので、今こうして助けを求めている次第です。コメントお待ちしております。
他にも「ここをこうしたら効率的になるんじゃない?」みたいなコメントがあったら嬉しいです。

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