- 投稿日:2019-09-27T22:45:06+09:00
Liferayのバッチの作成
はじめに
定期的に実行するバッチ処理はシステムよくあります。
Javaのスケジューラのライブラリとしてquartzは有名です。
quartz:http://www.quartz-scheduler.org/LiferayのスケジューラもQuaryzを採用しております。
Liferayの中でやり方を簡単にまとめます。
QuartzのCron設定フォーマット
出典:http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html
QuartzのCron設定サンプル
出典:http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html
Liferayのバッチ実装必要なメソッド
- activate:OSGiモジュール起動処理
- deactivate:OSGiモジュール停止処理
- receive:ビジネスロジック
サンプル
TestBatch.javapackage 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; }ポイントとなるトリガーの作成
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以上
- 投稿日:2019-09-27T17:20:49+09:00
Javaにおけるtransient修飾子とシリアライズに関して
初めて
transient
というフィールド修飾子に遭遇したのでメモ。private transient long originalTime;一般的な説明
transientを付与すると該当のフィールドは直列化の対象外となる。
該当の変数を持つクラスを直列化しようとして、NotSerilizabaleException
が発生した際にこの修飾子を付与するととりあえず例外は発生しなくなる。直列化ってなに?
直列化以外にも、シリアライズ、シリアル化などと呼ばれる。
オブジェクトと直列化することはオブジェクトの情報をストリーム化し、ファイルとして保存 or ネットワークを介してやり取りする
ことが可能になるっぽい。要するにJavaのオブジェクトをバイト列として出力するということ。どういう時に直列化できないの?
そもそもオブジェクトによっては直列化できる・できないが決まっている。そのようなオブジェクトを持っているクラス自体を直列化しようとすると前述の例外が発生すると思われる。
直列化する方法
あるクラスを直列化するには
java.io.Serializable
を実装すればいい。 シリアライズ化可能ですよー、という証でこのinterfaceを実装すると良い。個人的なまとめ
- Javaオブジェクトをファイルに保存したり、ネットワーク経由で伝達する場合は直列化(シリアライズ)が必要。
- 特定のクラスを直列化するには
Serializable
を実装する必要がある。- クラスを直列化した時に
NotSerilizabaleException
が発生することがある。- 直列化の対象外にするために
transient
を使う。
- 投稿日:2019-09-27T15:46:24+09:00
HiveRunner を試す
モチベーション
Hive のクエリのテストしたい。
mysql だったら、docker-compose とか比較的簡単にテストできるけど、hiveのクエリのテストも同じようにしたいけど、どうしたらいいですかね。(docker で ゴニョゴニョするのはちょっと辛そう..)
ってわけで良さそうなプラグインを適当に選んで試してみました。
選んだのは、公式でいくつか紹介されているツールの中で git のスターが一番多かった HiveRunner です。(バージョンは
4.1.0
)準備
HiveRunner
は基本的にJunit
のテストとして、クエリのテストをします。外部の依存関係は必要なく、
JVM
上にHiveServer
を立てて、Junit
がそのHiveServer
にhive 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に対処法など書いてありますが..)
とはいえ、
pom
にhiverunner
を入れるだけで、hive
のsql
のテストができるのは魅力的ですね。
- 投稿日:2019-09-27T15:02:45+09:00
【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
を渡すときも同様にする必要があります。参考にさせて頂いたサイト
- 投稿日:2019-09-27T14:16:02+09:00
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以上かなっと
- 投稿日:2019-09-27T14:00:19+09:00
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.javaimport 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.csstatic 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(); }動作結果
課題
今回はサーバをコンソールアプリケーションで作成したが、フォームアプリケーションでの作成を目指している。
- 投稿日:2019-09-27T12:50:02+09:00
vim
html&cssを書くのにAtomを最初に使用していたのですが。。
JAVAを使いだしてからはすぐにGitbBshHerを導入してvimで記述しております。最初のうちは扱いずらいなーと思ってましたが慣れたら作業的にもかなり時短になるなと個人の感想。
よくわかってませんしたがvimはかなり渋いらしいです。
*未完成*
- 投稿日:2019-09-27T12:50:02+09:00
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)で便利に
以上基本的に覚えて損がなかったコマンドでした。
- 投稿日:2019-09-27T01:19:55+09:00
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
・自作メソッド
等々…
一例として、(前記事)参照
- 投稿日:2019-09-27T01:08:27+09:00
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)など、様々な機能を備える。
- 投稿日:2019-09-27T00:57:59+09:00
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.javapublic 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.javaclass 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.javaclass 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.javaclass 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.javapublic class Line implements Contact { @Override public String findOnesPlace(Latecomer latecomer){ //遅刻してきた人にラインで連絡をとり、居場所を返却してくれる体の処理 } }Contact.javapublic interface Contact{ public String findOnesPlace(Latecomer latecomer); }AttendanceMonitor は外部からクラスを注入されることによって連絡手段のクラスへの依存が解消されました。
AttendanceMonitor 内でnewしてインスタンスを作っていません。外部のクラスとは、今回の例ではMainクラスです。
Main.javapublic 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って依存性の注入だよね~」
- 投稿日:2019-09-27T00:49:38+09:00
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を記述しないことは可能・
- 投稿日:2019-09-27T00:38:50+09:00
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に変換される。
- 投稿日:2019-09-27T00:19:14+09:00
等差数列を使った数当てゲームを作ったけれど、空白に納得できない話
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文を使って、行の最後の数値を出力するときは半角スペースを出力しないようにする。
これならちゃんと半角スペースで区切りができるし、文末に余計な半角スペースも付かない。一件落着!
と一瞬思ったものの、解決策があまりにも強引すぎるのではないかと感じてしまい、結局は最初の策を採用しました。とはいえこれもこれで絶対スマートではない気がする。結局文末に余計な半角スペースが付いてしまうし。うまいこと出力される値を切り離す綺麗な方法がどうしてもわからなかったので、今こうして助けを求めている次第です。コメントお待ちしております。
他にも「ここをこうしたら効率的になるんじゃない?」みたいなコメントがあったら嬉しいです。