20210427のJavaに関する記事は5件です。

Azure Function x Twitter4Jで乃木坂46への愛を叫ぶ

Azure Functionから自動的にツイートするプログラムをJavaで作りました。乃木坂ちゃんへの愛を叫ぶだけです(^^; Twitterの予約投稿機能、Bufferのようなサービス、ノーコードツールなどを使って同じことはできますが、Javaのコードで自由に処理を書けるので、より自由度が高い気がします。 JavaにはTwitter4Jという素晴らしいツールがあるので簡単に実現できます。 環境構築 Azure Functionをローカル環境で実行するには.NET Coreなどのインストールが必要です。今回はMicrosoftが提供している.NET CoreのDockerイメージをベースにしました。Azure CLI、JDK、azure-functions-core-toolsなど必要なものを入れています。 FROM mcr.microsoft.com/dotnet/core/sdk:3.1 RUN apt-get update && \ apt-get install -y --no-install-recommends \ openjdk-11-jdk && \ apt-get install -y maven RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg RUN mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg RUN sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/debian/$(lsb_release -rs | cut -d'.' -f 1)/prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list' RUN apt-get update RUN apt-get install azure-functions-core-tools-3 プロジェクトの準備 Mavenのazure-functions-archetypeを使ってプロジェクトを作成したらpom.xmlにTwitter4Jの依存性を追加します。 <dependency> <groupId>org.twitter4j</groupId> <artifactId>twitter4j-core</artifactId> <version>4.0.7</version> </dependency> あとはsrc/main/resourcesの配下にtwitter4j.propertiesファイルを作成してTwitterで発行した各種キーを設定します。 debug=true oauth.consumerKey=xxxxx oauth.consumerSecret=xxxxx oauth.accessToken=xxxxx oauth.accessTokenSecret=xxxxxx azure-functions-archetypeで作ったプロジェクトにはコードの雛形が用意されている(Function.java)ので、その中に以下のコードを追加しました。Cronのように定期実行されるFunctionです。 @FunctionName("keepAlive") public void keepAlive( @TimerTrigger(name = "keepAliveTrigger", schedule = "0 */30 * * * *") String timerInfo, ExecutionContext context ) { Twitter twitter = new TwitterFactory().getInstance(); try { Status updateStatus = twitter.updateStatus("乃木坂46が大好きです!"); context.getLogger().info(updateStatus.getText()); } catch (TwitterException e) { e.printStackTrace(); } } やったことはこれだけです。あとはビルドして mvn clean package -DskipTests 実行します。 mvn azure-functions:run このときハマった点は別途、以下の記事でまとめました。 ローカル環境でうまく動いたら、あとはデプロイするだけです。 mvn azure-functions:deploy 今回はツイートするだけの簡単なものでしたが、普通のJavaプログラムなので、Twitter4Jのようなライブラリを利用できるのが嬉しいです。色々と面白いものが作れそうですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Azure Functions x Twitter4Jで乃木坂46への愛を叫ぶ

Azure Functionsから自動的にツイートするプログラムをJavaで作りました。乃木坂ちゃんへの愛を叫ぶだけです(^^; Twitterの予約投稿機能、Bufferのようなサービス、ノーコードツールなどを使って同じことはできますが、Javaのコードで自由に処理を書けるので、より自由度が高い気がします。 JavaにはTwitter4Jという素晴らしいツールがあるので簡単に実現できます。だいぶ昔に書いた記事でTwitter Developersの画面が古いですが、興味ある方はこちらもご参照くださいm(_ _)m 環境構築 Azure Functionsをローカル環境で実行するには.NET Coreなどのインストールが必要です。今回はMicrosoftが提供している.NET CoreのDockerイメージをベースにしました。Azure CLI、JDK、azure-functions-core-toolsなど必要なものを入れています。 FROM mcr.microsoft.com/dotnet/core/sdk:3.1 RUN apt-get update && \ apt-get install -y --no-install-recommends \ openjdk-11-jdk && \ apt-get install -y maven RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg RUN mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg RUN sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/debian/$(lsb_release -rs | cut -d'.' -f 1)/prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list' RUN apt-get update RUN apt-get install azure-functions-core-tools-3 プロジェクトの準備 Mavenのazure-functions-archetypeを使ってプロジェクトを作成したらpom.xmlにTwitter4Jの依存性を追加します。 <dependency> <groupId>org.twitter4j</groupId> <artifactId>twitter4j-core</artifactId> <version>4.0.7</version> </dependency> あとはsrc/main/resourcesの配下にtwitter4j.propertiesファイルを作成してTwitterで発行した各種キーを設定します。 debug=true oauth.consumerKey=xxxxx oauth.consumerSecret=xxxxx oauth.accessToken=xxxxx oauth.accessTokenSecret=xxxxxx azure-functions-archetypeで作ったプロジェクトにはコードの雛形が用意されている(Function.java)ので、その中に以下のコードを追加しました。Cronのように定期実行されるFunctionです。 @FunctionName("keepAlive") public void keepAlive( @TimerTrigger(name = "keepAliveTrigger", schedule = "0 */30 * * * *") String timerInfo, ExecutionContext context ) { Twitter twitter = new TwitterFactory().getInstance(); try { Status updateStatus = twitter.updateStatus("乃木坂46が大好きです!"); context.getLogger().info(updateStatus.getText()); } catch (TwitterException e) { e.printStackTrace(); } } やったことはこれだけです。あとはビルドして mvn clean package -DskipTests 実行します。 mvn azure-functions:run このときハマった点は別途、以下の記事でまとめました。 ローカル環境でうまく動いたら、あとはデプロイするだけです。 mvn azure-functions:deploy Azure Functionsといっても中身は普通のJavaプログラムなので、Twitter4Jのようなライブラリを利用できるのが嬉しいです。今回はツイートするだけの簡単なものでしたが、他のライブラリと合わせて面白いものが色々と作れそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java アルゴリズム修行⑫】単純選択、挿入ソート

単純選択ソート 前回の記事ではソートの勉めを始め、ベーシックなバブルソートについても触れましたが、 今回はそこから派生する単純選択ソート、単純挿入ソートについて見ていきたいと思います。 まずは単純選択ソートですが、ざっくりいうと以下のようなものです 最小要素を先頭に移動し、2番目に小さい要素を先頭から2番目に移動するのを繰り返すアルゴリズム だそうです。。小さい方の値をどんどん先頭寄りに持っていくことで昇順にするという感じみたいですね 実際に{5,4,8,7,9,4,3,1} という順番がバラバラの数列で考えてみましょう! まず着目するのは、最小の要素「1」
であり、配列の先頭に位置すべきなので、先頭要素の「5」と交換します。 すると、{1,4,8,7,9,3,5} という並びになるので、 次に2番目に小さい要素「3」に着目すると、
先頭から2番目の要素「4」よりも小さいので同様に交換を行います。 すると{1,3,8,7,9,4,5}という並びで2番目の要素までソートが完了しますね! この過程を繰り返すと、下記のような流れになります。 常に小さい値を先頭寄りに交換することで、結果的に昇順になるという流れのようです。 言い換えれば、未ソート部(ソート対象としていない要素)から最小の要素を見つけ、 未ソート部の先頭要素と交換する操作を繰り返している

と言えます。 条件としてまとめると、、 ① 未ソート部から最小のキーを持つ要素 a[最小値のインデックス]を選択する
 ② a[min]と未ソート部の先頭要素を交換する

 隣、これを n - 1 回繰り返すと、未ソート部がなくなってソートが完了しそうですね。。!
 一方で、この選択ソートアルゴリズムは、離れた要素を交換するため、安定ではありません。 同値が離れていた場合は、ソート後に前後が入れ替わってしまう可能性がありますね。。 例えば、{3,4,2,3,1}という配列をソートしようとして、 最初の3→1の交換で元々は先頭にあった「3」が末尾に入ってしまう、4番目の3よりも後ろになってしまう。。という ことが選択ソードではあり得てしまうようです汗 諸々の条件を踏まえて、実際にコードに落としてみましょう! SelectionSort.java public static void selectionSort(int[] a, int n) { for (int i = 0; i < n - 1; i++) { int min = i; // 未ソート部の最小要素のインデックス(最初は先頭要素のインデックスを格納) for (int j = i + 1; j < n; j++) { if (a[j] < a[min]) { // 最小値よりも小さければ、その値のインデックスをminに代入する min = j; } }// 未ソート部の先頭要素と最小要素を交換する swap(a, i, min); } } 上記はメソッドだけなので、ソートを行う配列の生成や、実際に交換を行うswapメソッドなどは バブルソートの記事内に載せているのでそちらを参考にしてください! 先ほどの{5,4,8,7,9,3,1} を上のコードに当てはめて流れを追ってみましょう。 まずは 先頭インデックスである 0 が 最小値のインデックスとして min変数に代入され、 jはその右隣にあるインデックスから比較していく、という流れになります j = 1から始まり、 j < 7 なので、そのままfor文の中に処理が移ります。 if(a[j] < a[min])は 

a[1](4) < a[0](5) となるので、条件文は 4 < 5となり、 この時点の最小値は「4」 → min の値は「4」のインデックスである[1]となります jがインクリメントされ、 2 < 7 なので、そのままfor文の中に処理が移ります。 

a[2](8) < a[1](4) となるので、条件文は 8 < 4となり、「8」は最小値ではないので そのまま次の繰り返しに移行します。 jがインクリメントされ、 3 < 7 なので、 

a[3](7) < a[1](4) → 条件文は 7 < 4となり、「7」は最小値ではないので次の処理へ jがインクリメントされ、 4 < 7 なので、 

a[4](9) < a[1](4) → 条件文は 9 < 4となり、「9」は最小値ではないので次の処理へ jがインクリメントされ、 5 < 7 なので、 

a[5](3) < a[1](4) → 条件文は 3 < 4となり、この時点での最小値は「3」となるので min の値は「3」のインデックスである[5]となります jがインクリメントされ、 6 < 7 なので、 

a[6](1) < a[5](3) → 条件文は 1 < 3となり、この時点での最小値は「1」となるので min の値は「1」のインデックスである[6]となります j < 7なのでこのループは抜けて、 swap(a,0,6)が行われ、[0]である「5」と[6]である「1」が交換されるので 1ソート目を終えた時点で、{1,4,8,7,9,3,5}となります。 そのままiがデクリメントされ、1となるので、 minにも1が代入され、 j = 1 + 1 で2から始まります。 a[2](8)< a[1](4)→ 条件文は8 < 4 となり、「8」は最小値ではないので次の処理へ jがインクリメントされ、 3 < 7 なので、 

a[3](7) < a[1](4) → 条件文は 7 < 4となり、「7」は最小値ではないので次の処理へ。。 という感じに繰り返していき、先頭寄の要素よりも小さい要素があれば最小値のインデックスを更新し、 末尾まで行った時点で、未ソート部の先頭要素と交換していくという流れになります。 やってることは最小値となる部分を選択して、先頭と交換を繰り返しているので、選択ソートと言われる感じでしょうか。。 単純挿入ソート バブル、選択ときたので次に単純挿入ソートを見ていきましょう。 挿入と言われるくらいなので、値を要素の合間に入れ込んでいくイメージですが、 着目要素をそれより先頭側の適切な位置に”挿入する”という作業を繰り返してソートを行うアルゴリズム という感じらしいです。。イメージは湧きますが、ちょっと分かりにくいのでこれも実際に流れを見て見ましょう {8,3,1,5,2,1}という数列で考えてみます。 先頭の「8」をソート済として、2番目の要素の「3」に着目すると 「8」よりも小さいので、先頭寄りに位置すべきということになり、先頭に挿入すると、{3,8,1,5,2,1}となります 次に3番目の要素に着目し、「3」「8」と比べると、それよりも小さいので、先頭に挿入すると`{1,3,8,5,2,1}となります 次に4番目の要素の「5」に着目し、「8」よりも小さいので、8の手前に挿入すると{1,3,5,8,2,1}となります。 というように、ソート済の要素と、未ソートの要素の先頭の値を比較して、大きい値があればその直前に挿入する という操作を繰り返すことでソートを完了することができそうです。 ただ、この「直前に挿入する」という操作をコードで実現させるには少し工夫が必要そうです。 というのも、Javaには配列の要素を「適切な位置に挿入する」というメソッドがないんですね。。涙 配列で考えるならば、未ソート部において着目した要素よりも、その左隣の値が大きい限り 大きい方の値の右隣に、そのまま大きい方の値を代入し、 それ以下の要素に出会ったら、その位置に着目した要素を代入すルコとで実現できそうです。 と言葉にしてもピンとこないので、先ほどの続きをこの方法で操作してみましょう {1,3,5,8,2,1}で終わっており、「3」→「1」→「5」と着目してきて、 それより手前の値に大きいものがあればその直前に挿入するというのを繰り返してきので、 次に着目すべきは5番目の要素である「2」ということになります。 その左隣は「8」で、「2」より大きいので比較した「8」の右隣にそのまま「8」を代入します → {1,3,4,5,8,8,1} 次も「5」の方が大きいので、「5」の右隣に「5」を代入して{1,3,4,5,5,8,1}となり 次も「4」の方が大きいので、「4」の右隣に「4」を代入して{1,3,4,4,5,8,1}となり 次も「3」の方が大きいので、「3」の右隣に「3」を代入して{1,3,3,4,5,8,1}となり 次の「1」ですが、ここで初めて「2」よりも小さい値に出会うので、 「1」の右隣に「2」を代入すると、最終的に{1,2,3,4,5,8,1}と、2を正しい位置に挿入することができます。 着目した要素を保存する一時変数を持たせて、左隣が大きいか小さいかで処理を分け、 小さければその右隣に一時変数を代入することで、結果的に「目的の位置に挿入する」という行為が実現できています。 (処理自体は比較と代入を繰り返しているだけなので、言い方がややこしいですが汗) ここまでやり方が分かってきたので、実際にコードに落とし込んでみましょう! InsertionSort.java static void insertionSort(int[] a, int n) { for (int i = 1; i < n; i++) { int j; int tmp = a[i]; //一時変数 //走査する要素が先頭以外で、一時変数よりも値が大きい間は代入操作を続ける for (j = i; j > 0 && a[j - 1] > tmp; j--) { a[j] = a[j - 1]; //左隣に値を代入する } a[j] = tmp; //最小要素を先頭寄りに代入する } } ソートの繰り返し制御用変数をjとして、着目する要素を一時変数として tmpに代入しています。 ソートを終了する条件は、下記条件のいずれかが成立したときとすれば良さそうです 目的列の左端に達した tmpと等しいか、それよりも小さい値を持った項目 a[j-1]が見つかった 2つのいずれか一方が成立するまでjをデクリメントして末尾から先頭への比較、代入操作を繰り返しています。 コード上ではfor (j = i; j > 0 && a[j - 1] > tmp; j--)となっていますが、言い換えると、 jが0より大きい(先頭以外のインデックス) かつ
 a[j - 1]の値が一時変数よりも大きい (もっと先頭寄りの方に代入する必要がある)間は代入操作を繰り返せばよいということになりそうです。 もし一時変数よりも小さければその時は繰り返し処理を抜けて、a[j] = tmpとして、 意図した位置への挿入(操作自体は代入)を行なっています。 仮に{1,3,5,8,2,1}という数列を最初からソートするとして、コードで流れを追ってみましょう。 ■ i = 1から始まる tmp変数には a[1]の3が代入される もし j > 0 かつ、a[1-1] > 3 だったら代入操作を行うが、 この時点で既に a[0]の1の方が小さいので、代入操作は行わずにfor文を抜ける a[1] = 3でそのまま変わらない → {1,3,5,8,2,1} ■ i =2 なので tmp変数にはa[2]の5が代入される もし j > 0 かつ a[2-1] > 5 だったら代入操作を行うが、 この時点で既にa[1]の3の方が小さいので、代入操作は行わずにfor文を抜ける a[2] = 5でそのまま変わらない → {1,3,5,8,2,1} ■ i = 3 なので tmpe変数にはa[3]の8が代入される もし j > 0 かつ a[3-1] > 8 だったら代入操作を行うが、 この時点で既にa[2]の5の方が小さいので、代入操作は行わずにfor文を抜ける a[3] = 8なので変わらない → {1,3,5,8,2,1} ■ i = 4 なので tmp変数にはa[4]の2が代入される もし j > 0 かつ a[4-1] > 2 だったら代入操作を行うが、 a[3] の8の方が大きいため、代入操作を行い、 a[4] に a[3]の8を代入 → {1,3,5,8,8,1}となる
 もし j > 0 かつ a[3-1] > 2 だったら代入操作を行うので a[2] の5の方が大きいため、代入操作を行い、 a[3] に a[2]の5を代入して {1,3,5,5,8,1}となる もし j > 0 かつ a[2-1] > 2 だったら代入操作を行うので a[1] の3の方が大きいため、代入操作を行い、 a[2] に a[1]の3を代入して {1,3,3,5,8,1}となる もし j > 0 かつ a[1-1] > 2 だったら代入操作を行うが、 a[0] の1の方が小さいため、代入操作は行わず a[1]にtmpの2が代入され、 {1,2,3,5,8,1}となり、2を前に出すことができました これを繰り返すことで、昇順へのソートが完了しますが、 単純挿入ソートは、常に隣り合う値を比較、必要に応じて代入していくので、飛び越えた要素の交換は行われません。 そのため、安定したアルゴリズムとみなすことができます。 バブル・選択・挿入の比較 ここまでで学んできた3つのアルゴリズムを比較してみると下記のようになります。 種類 速度 安定性 バブルソート O(n2) 安定 選択ソート O(n2) 不安定 挿入ソート O(n2) 安定 速度は変わらずで、選択ソートだけが離れた要素を交換する可能性があるので不安定という感じですね。。 あくまで考え方ですが、実装を少し変えるだけでもソートの動きが変わるのが実感できた気がします! 学んだこと 選択ソートは最小値インデックスを走査し、未ソート部の先頭と交換する 挿入ソートは着目要素を保存し、自分より小さい値を見つける位置まで代入を繰り返す(実質、挿入操作ではない) バブル、選択、挿入と触れてきて、隣り合う要素の比較から、 最小値インデックスを使ったり、代入を繰り返したりと、ひとえにソートといっても 様々なやり方があることが分かりました。。! とは言え、これらの速度はo(n2)というのは高速とは言い難く、、シェル、クイックソートというものがあるらしいので、 引き続き頑張っていきます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ガベージコレクタとは?

ガベージコレクタとは? ガベージコレクタの説明 ガベージコレクタとは、プログラムが使用しなくなったメモリ領域を検出し解放します。 例えば、int型のインスタンス変数を宣言したとすると、int型のデータサイズである 32ビット分のメモリ領域が使用されることになります。 しかし、このオブジェクトが使用されなくなると、ガベージコレクタによってこのオブジェクトが 使用していたメモリ領域を解放します。 オブジェクトをガベージコレクタの対象にする。 オブジェクトがどこからか参照されている間は、ガベージコレクタの対象にはなりません。 オブジェクトへの参照を取り除く方法は2つあります。 nullを代入 プログラムの中で明示的に「この変数はオブジェクトを参照しない」ということを表現する nullを代入します。これによりガベージコレクタの対象になります。 Employee e1 = new Employee(); //a1変数は、Employeeオブジェとを参照している e1 = null; //nullを代入することで、「その変数は何も参照していない」という意味になる。 参照変数を他のオブジェクトに割り当てる オブジェクトを参照している変数に、新たなオブジェクトを割り当てたことで、元のオブジェクトが どこからも参照されなくなったら、その元のオブジェクトはガベージコレクタの対象になる。 Employee e1 = new Employee(); //a1変数は、Employeeオブジェクトを参照している e1 = new Employee(); //a1変数は新しいオブジェクトを参照する。その結果、最初のオブジェクトはガベージコレクタの対象になる。 まとめ ・ガベージコレクタとは、プログラムが使用しなくなったメモリ領域を検出し解放する動作を指す。 ・変数にnullを代入すると、ガベージコレクタの対象になる。 ・参照変数を他のオブジェクトに割り当てると、ガベージコレクタの対象となる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaのBigDecimalの割り算の丸め処理をPythonに書き換える

最近Javaで書かれたバッチをPythonに書き換えている。 Javaで正確な丸めを行うためにBigDecimalを使ったコードがある。 それをPythonに書き換える際に対応するメソッドがなく困った。 本記事では対応策をまとめる。 Java側 Javaのコードが以下のようだとする。 import java.math.BigDecimal; import java.math.RoundingMode; class BigDecimalDivideTest { public static void main(String[] args) { BigDecimal someValue = BigDecimal.valueOf(3215); BigDecimal BD_100 = BigDecimal.valueOf(1000); int SCALE_2 = 2; System.out.println(someValue.divide(BD_100, SCALE_2, RoundingMode.HALF_UP)); // 3.22が表示される } } Python側 from decimal import * some_value = Decimal('3215') bd_100 = Decimal('1000') scale_2 = 2 divided_value = some_value / bd_100 scaled_decimal = Decimal(str(10 ** - scale_2)) # => Decimal('0.01')になる。 # 丸め処理にはquantizeメソッドを使う divided_value.quantize(scaled_decimal, rounding=ROUND_HALF_UP) # => Decimal('3.22') 説明 Pythonにおける、JavaのBigDecimalに対応するライブラリはdecimalである。 https://docs.python.org/ja/3/library/decimal.html だが decimal の divide メソッドでは、Javaのようにスケールや丸めについて引数を取るものがない。 なので、スケール処理と丸めはquantizeで割り算のあとに行う。 なお、quantizeでエラーが出る場合がある。 from decimal import * getcontext().prec = 2 # 追加 some_value = Decimal('3215') bd_100 = Decimal('1000') scale_2 = 2 divided_value = some_value / bd_100 scaled_decimal = Decimal(str(10 ** - scale_2)) divided_value.quantize(scaled_decimal, rounding=ROUND_HALF_UP) # => decimal.InvalidOperation 例外が発生する https://docs.python.org/ja/3/library/decimal.html#decimal.Decimal.quantize 他の操作と違い、打ち切り(quantize)操作後の係数の長さが精度を越えた場合には、 InvalidOperation がシグナルされます。 getcontext().prec = 2を追加した上でquantizeを行うと、quantize結果が数値全体で2桁(3.2とか)でないとエラーになる。 今回はquantize結果は3.22であり結果が3桁になるので、InvalidOperationが出る。 なんで書こうと思ったか Pythonのドキュメントの一番上で以下のようなコードが書いてある。 from decimal import * getcontext().prec = 6 Decimal(1) / Decimal(7) # => Decimal('0.142857') これを見て、私は桁数を指定するにはgetcontext().precを指定すればいいのかとミスリードした。 precは数値全体の桁数の話なので、prec = 6としても小数点以下6桁を保証してくれるわけではない。 例えば上記の割り算の対象数字が大きかったとすると、以下のようになる。 from decimal import * getcontext().prec = 6 print(Decimal(10000000) / Decimal(7)) # => Decimal('1.42857E+6') print(float(Decimal(10000000) / Decimal(7))) # floatに変換すると1428570.0 # prec = 有効桁数は6なので、142857までの6桁までは計算結果が保持されるがそれ以降は0に 参考 なぜBigDecimalを使わなければならないのか | Java好き BigDecimalを使う理由が理解できた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む