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

Eclipseで作成した既存のSpringBootプロジェクトをVSCodeで実行

単にフォルダの読み込みだけではだめだったので書き留めます 環境 Eclipse 2020-12 Spring Boot 2.4.0 java 8 バージョン管理 Git やったこと VSCodeでEclipseで開発したSpringBootのWorkSpace(作業フォルダ)を読み込んだ。 んでRun → Start Debugging 読み込んだときに自動的にWorkSpaceに.vscodeのフォルダが作成され、その中にlaunch.jsonが作成されます。 どうやらそれがVSCodeの実行に必要みたい。 lauch.json(初期状態) { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "pwa-chrome", // ここを変えないといけない "request": "launch", "name": "Launch Chrome against localhost", "url": "http://localhost:8080", \\ ここは変えてあるかもしれません "webRoot": "${workspaceFolder}" } ] } とりあえず入れたExtensionsたち なんかjavaとかSpringで検索して出てきたPackになっているやつでいれました。 結果 Chromeが立ち上がるけどだめ launch.jsonを修正 launch.json(修正版) { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", // java.homeも設定するような記事があったので、インストールしていたものを読み込むようにしました "java.home": "C:\\Program Files\\AdoptOpenJDK\\jdk-11.0.9.101-hotspot", "configurations": [ { "type": "java", // 結局ここを"java"にすれば良いだけ "request": "launch", "name": "Launch Chrome against localhost", // 他にもかいてあったけど、消しても動きました } ] } 他にやったことは? configをいじった settings.json { "files.exclude": { "**/.classpath": true, "**/.project": true, "**/.settings": true, "**/.factorypath": true }, "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx1G -Xms100m -javaagent:\"c:\\Users\\yumasky\\.vscode\\extensions\\gabrielbb.vscode-lombok-1.0.1\\server\\lombok.jar\"", "editor.suggestSelection": "first", "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue", "spring-boot.ls.java.home": "", // ここにもJDKのパスを入力してたけど、消しても動いた! "cloudfoundry-manifest.ls.java.home": "" } まだちゃんとわかっているわけではないです。。。 とりあえず調べてた記事の中では基本的にVSCodeで新しくSpringBootのプロジェクトを作成の流れが多く、最初はEclipseで、途中からVSCodeでみたいな乗り換えの方法はなかなか見つかりませんでした。 そういう方の参考になればと思います。 また、補足説明できる方、ぜひコメントでよろしくお願いいたしますm(__)m
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java アルゴリズム修行⑥】線形探索と番兵法

方法論を学ぶことも大事そう 問題を解いて、自力で解法を得る思考回路を作るのも大事ですが、 先人が既に定義してくれている解法を勉強することも同じくらい大事ということで 今回は線形探索について学んだことを書いてみたいと思います! 線形探索とは?? 配列からの何か特定の要素を探すアルゴリズムとしては基本中の基本だそうです。 要素が直線状に並んだ配列から要素を探すとき、目的とする値を持つ要素に出会うまで先頭から順に要素を走査することで実現できる というのが、線形探索、もしくは逐次探索と呼ばれるアルゴリズムとのことで、、 頭から順番に、探している要素と同じですか?っていうのを聞いて回って、一緒だったらそいつです!っていうシンプルな話みたいですね。。 そんな線形探索ですが、永遠に走査するわけではなく下記のような終了条件があるそうです。 探索すべき値が見つからず終端を通り越したとき 探索すべき値と等しい要素を見つけたとき ふむふむ。見つからずに最後までいっちゃったか、見つけたかどっちかという感じですかね。 早速コードで表現してみましょう。 java.algo import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int count = sc.nextInt(); int array[] = new int[count]; for (int i = 0; i < count; i++) { array[i] = sc.nextInt(); } System.out.print("探す値: "); int target = sc.nextInt(); int answer = search(array, count, target); if (answer == -1) { System.out.println("探索失敗"); } else { System.out.println(++answer + "番目に存在します"); } } public static int search(int[] array, int n, int key) { int i = 0; //制御文をtrueとして無限ループ while (true) { //最後のインデックスまでいってしまえば探索失敗 if (i == n) { return -1; // キー値と同一であれば該当インデックスを返却 } else if (array[i] == key) { return i; } i++; } } } 最初に入力された数分だけの要素を持つ配列を生成し、要素分だけ配列に要素を詰めていきます。 その配列から線形探索を用いて、キー値(探している値)の位置を取得するという流れです。 線形探索を行っているのはsearchメソッドですが、中身ではwhile文の制御文をtrueとすることで無限ループを行っています。 無限ループといっても、return文やbreak文があれば抜けることができるので、先の終了条件2つに合わせて条件分岐を設定しましょう。 (n == i)のときに、ループ数が配列の要素数を超えてしまった場合と、(array[i] == key)のときが、キー値と配列の要素が一緒だった場合の2つで分岐させました。 前者は探索が失敗しているので、インデックスには存在しえない -1 を返し、キー値が存在した場合はインデックスを返すようにしています。 先頭から全ての要素を探す流れを無限ループで実現するというのは新鮮でしたね。。 ここではwhile文で実現していますが、for文でも以下のように実現可能です。 algo.java public static int search(int[] array, int n, int key) { for(int i = 0; i < n; i++){ if(array[i] == key){ return i; } } return -1; } for文ではループ数を条件文で制御することができるので、 キー値と一致する要素はなくfor文を抜ける = キー値は存在しないので -1を返す という流れでwhile文より簡潔に書くことができますね! 番兵法 while文で実現した場合、繰り返しの度に2つの終了条件の両方をチェックする
ことになりますが、この計算コストはバカになりません。。 このコストを半分にできるのが番兵法というものです。 例えば、10個要素がある配列の中で、2という値を探したいとなったとき、11個目の要素に2を入れてしまい、 その上で線形探索を行うというものです。 これだけ聞くと、「ん?走査する要素を増やしているだけで、効率上がるのか?」と自分でも思いましたが、実際にコードで表現してみましょう。 algo.java import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int count = sc.nextInt(); //番兵用に要素を1つ追加しておく int array [] = new int[count + 1]; for(int i = 0; i < count; i++){ array[i] = sc.nextInt(); } System.out.print("探す値: "); int target = sc.nextInt(); int answer = search(array,count,target); if(answer == -1){ System.out.println("探索失敗"); }else{ System.out.println(++answer +"番目に存在します"); } } public static int search(int [] array, int n, int key){ int i = 0; //末尾に番兵(キー値)を代入 array[n] = key; while(true){ //キー値と一致していればその時点でループを抜ける if(array[i] == key){ break; } i++; } //一致したインデックスが最後(番兵)であれば探索失敗、そうでなければ本来のデータ return i == n ? -1 : i; } } 初期のwhile文では下記の条件をif文で確かめていましが、 探索すべき値が見つからず終端を通り越したとき 探索すべき値と等しい要素を見つけたとき 番兵法を使うことで、これを(array[i] == key)という条件式だけで判断することができるんですね! もし本来の配列データにキー値と一致するものがなければ、末尾に追加したキー値(番兵)に辿り着くので、いずれにせよwhile文のループは抜けることができるということです、、(考えついた人の頭の柔らかさが欲しい) ループ後は、return i == n ? -1 : i; でループ回数(i)と要素数(n)が一致していれば、末尾までの番兵までたどり着いたということになるので、-1を返しています。 (nは最初の入力値である配列要素の数ですが、配列のインデックスは0から始まるので、n個の要素で成り立つ配列に追加した末尾のインデックスはnになるということですね!) この番兵を追加するだけで、終端を通り過ぎてしまったときの終了判定であった(i == n)の判定が不要になり、実質判定回数を半分にすることができました。。! 学んだこと 既に定義されているアルゴリズムは積極的に学んだ方が良さそう for文の中の条件式を半分にすれば、全体の判定回数も半分にできる 線形探索、、前から順番に探索するだけか とか思っていましたが、while文での無限ループや番兵方による判定回数の減らし方など、自分の中の手札として知っておくだけで違うことを学べたので、ここは引き続きインプットとアウトプットを続けていこうと思います!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring boot + PostgreSQL ローカル環境構築手順(社内勉強会用)

はじめに 社内勉強会を行うので、 事前準備としてローカル環境への構築の手順をまとめています。 勉強会では実際にコーディングするので、事前に実施してください。 概要 下記のアーキテクチャを使用します。 REST APIを作成できる環境構築を作ります。 OS:Windows IDE:Eclipse フレームワーク:SpringBoot DB:Postgres 構築手順 Eclipseのダウンロード~起動 こちらからダウンロードしてください。 最新版のJavaのFull Editionをダウンロードします。 ※2021/4/4時点では2021-03版が最新 ダウンロード後、7-Zipというソフトウェアで解凍する必要があるためインストールします。 ※それ以外の解凍ソフトでは正常に解凍されない可能性があります。 7-Zipのダウンロードはこちら 「7z1900-x64.exe」または「7z1900.exe」というファイルがダウンロードされているので、ダブルクリックし、インストールする。 あとはエクスプローラー上でファイルを選択し、右クリックで7-Zipという項目ができていればOK。 7-ZipでEclipseを解凍します。 eclipse.exeをダブルクリックし起動する。ワークスペースは任意の場所でOK。 Eclipseの手順は以上。 postgreSQLのダウンロード~ログイン ダウンロード こちらからダウンロードしてください。 バージョンが13.2のインストーラーを選択します。 インストール postgresql-13.2-1-windows-x64.exe というファイルがあるので、ダブルクリックします。 インストール画面1 インストール画面2 インストール画面3 インストール画面4 インストール画面5 インストール画面6 インストール画面7 インストール画面8 インストール画面9 インストール画面10 postgreSQLへログインする PostgreSQLが正しくインストールされたか確認するためにログインします。 ログインはコマンドプロンプトで psql コマンドで行います。 環境変数の設定を行うことでコマンドが打てるようになります。 環境変数の設定方法 ・コントロール パネル の システムとセキュリティ の システム をクリック ・設定の変更 をクリック ・詳細設定タブ の 環境変数をクリック ・システム環境変数のPath に C:\Program Files\PostgreSQL\13\binを追加 ・最後はOKを押下し、きちんと閉じる。 コマンドプロンプトでpostgreSQLへログイン ・コマンドプロンプトを開き、 psql -U postgres と入力する。 ・「ユーザ postgres のパスワード:」と表示されるので、インストール画面5で設定したパスワード を入力する。 ・「postgres=#」と表示されればログイン成功。 DBの作成 下記のコマンドを入力してください。 #testdbというデータベースを作成 create database testdb; #データベースの一覧を表示 \l 名前に ** testdb ** というものが追加されていればOK。 spring bootアプリケーションのひな型を用意~Eclipseへ読み込み 以下のサイトからひな型をダウンロードする。ダウンロードしたひな型をEclipseに読み込ませることですぐに実装となる。 Spring Initializr 下記と同じように入力し、GENERATEをクリックしてください。 ZIP形式でダウンロードされるので、解凍します。 解凍後、exlipseを開き、左側のパッケージエクスプローラー上で「プロジェクトのインポート」を押します。 「既存のGradleプロジェクト」を押します。 「プロジェクト・ルート・ディレクトリー」に解凍した「study」フォルダを選択します。 「完了ボタン」を押します。 正常に読み込めた場合、パッケージ・エクスプローラー上にstudyというプロジェクトが表示されます。 おわりに DBとの接続設定は勉強会での題材として取り上げる(予定)のため、記載していません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FizzBuzzをオブジェクト指向でやってみた

FizzBuzzをオブジェクト指向的にやってみたい Qiita始めました 記念すべき初投稿は読んで字の如くです。コロナで籠らざる得なくなった時にポリモーフィズムを勉強したので自分なりのアウトプットしようと思い立ちました。間違っていたり考えが浅かったりするかもしれませんがご愛敬です。 やってみる前に FizzBuzzとは 英語圏せんだみつおゲームの様なもの 数人で数字をコールしていき 3で割れる数字は「Fizz」 5で割れる数字は「Buzz」 3でも5でも割れる数字は「FizzBuzz」 を数字の代わりにコールする 詰まったり言い淀んだら負けという暇つぶしに丁度良さげな難度のゲームです。 先人達はこの題材で色々な縛りを課してプログラミングするみたいですが今回は特に縛りはありません。強いて言うならオブジェクト指向的にプログラミングしていきます。 オブジェクト指向的にとは 今回勉強してオブジェクト指向とは数字や文字列や処理の塊を人が理解して扱えるものとしてプログラミングする表現方法だと自分なりに解釈しました。そのことを反映してプログラミングしていきます。 今回はJavaを使いFizzBuzzというゲームを表現してみたいと思います。 やってみよう メイン main.java public class Main { public static void main(String[] args) { Game fizzBuzzGame = new Game(); fizzBuzzGame.setCount(20); fizzBuzzGame.start(); } } これだけです。ゲームクラスを呼び出しそのインスタンスに対して数を設定し開始する。 実行すると以下の出力が取れます。 GameStart!! 1 2 Fizz! 4 Buzz! Fizz! 7 8 Fizz! Buzz! 11 Fizz! 13 14 FizzBuzz! 16 17 Fizz! 19 Buzz! うまくいってそうですね。 注目点はメインではゲームクラスを扱うだけで全て終わらせている事です。コードを見辛くするif文やfor文は登場しません。 ゲームクラス Game.java class Game { private int count; public void setCount(int count) { this.count = count; } public void start() { System.out.println("GameStart!!"); for (int i = 1; i <= count; i++) { System.out.println(FizzBuzzBase.fizzBuzzCreate(i).call); } } } 先程扱ったゲームクラスです。こちらは内部変数としてint型のcountとそのセッター、スタートメソッドを持ちます。クライアントで扱う部分のクラスになります。 スタートメソッドは開始の合図とcount変数分System.out.printlnを実行します。 注目点はスタートメソッド内のfor文のprintln内の部分になりますが下記のFizzBuzzクラスで解説します。 FizzBuzzクラス FizzBuzz.java(抽象クラス) abstract class FizzBuzzBase { protected String call ; public static FizzBuzzBase fizzBuzzCreate(int i) { if( i%3 == 0 && i%5 == 0){ return new FizzBuzz(); }else if(i%3==0){ return new Fizz(); }else if(i%5==0){ return new Buzz(); } return new Normal(i); } } 抽象クラスFizzBuzzBaseです。実装クラスの継承元となります。 クラス内変数callを持ちます。実装クラスで持つか悩みましたがcountに対して返すクラス1つなのでクラス内変数で1つ持てばいいかと思いこの形になりました。 もう一つは静的メソッド Createです。これは実装クラスのファクトリーメソッドです。継承した4つの実装クラスのうちどれかを返します。どの条件にも当てはまらない場合Normalクラスを返します。この部分の条件式がFizzBuzzのルールの部分となります。 FizzBuzz.java(実装クラス) class Fizz extends FizzBuzzBase{ Fizz(){ call="Fizz!"; } } class Buzz extends FizzBuzzBase{ Buzz(){ call="Buzz!"; } } class FizzBuzz extends FizzBuzzBase{ FizzBuzz(){ call="FizzBuzz!"; } } class Normal extends FizzBuzzBase{ Normal(int i){ call= String.valueOf(i); } } 抽象クラスFizzBuzzBaseを継承した各クラス Fizz Buzz FizzBuzz Normal 実装クラスはコンストラクタのみ用意されその中でクラスに応じた文字列をcall変数へ代入します。 後は呼び出しもとでcall変数を読み出せば先程の出力が得られます。これでオブジェクト指向っぽく完成です。 System.out.println(FizzBuzzBase.fizzBuzzCreate(i).call); やってみて 普通にif文書けばよくね? 普通に書けばif文を書いて終わりのところをこねくり回したのでコード量がかなり増えましたね(汗) シンプルなルールなので現状だとオブジェクトで扱うことの良さが紹介できなかった気がします。今回書いてて気づいた部分もあり次回でそういった部分を紹介できればいいなと思っています。 お付き合いいただいてありがとうございます。お疲れ様でした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java で Azure Functionsの関数を実装する

Java で Azure Functionsの関数を実装する Azure Functions とは、イベントドリブンでプログラムを実行してくれるSaaSプラットフォームです。いわゆるサーバレスプラットフォームと呼ばれるもので、AWS で言うのところの Lambda です(知らないんですけど) Azure Functionsは、様々な言語とトリガサポートします。 言語では、 C# GO Java JavaScript / TypeScript PowerShell Python Rust トリガ(イベント)では、 HTTP タイマー Storage Queue / ServiceBug CosmosDb ... などです。 詳細は以下のDocsを当たってください。 Azure Functions のドキュメント | Microsoft Docs Javaからの利用 Azure Functions 用の Maven plugin がリリースされていますので、それを使いましょう。 Maven Plugin for Azure Functions | Microsoft Docs Functions プロジェクトの生成は、以下の通り mvn から generate します。サポートされている、Javaのバージョンは Java8 or Java11 です。javaVersionに使いたいJavaのバージョンを指定してください。 mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=8mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=8 デフォルトでHTTPトリガーが自動で生成されます。Web APIを実装できます。 @FunctionName("HttpExample") public HttpResponseMessage run( @HttpTrigger( name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, final ExecutionContext context) { context.getLogger().info("Java HTTP trigger processed a request."); // Parse query parameter final String query = request.getQueryParameters().get("name"); final String name = request.getBody().orElse(query); if (name == null) { return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build(); } else { return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build(); } } ローカル実行 ローカルで実行するには、Azure Functions Core Toolsが必要です。Visual Studio Code でプロジェクトを開くと、これらのツールのインストールが促されるのでインストールしてください。手動でもインストールできます。詳細は以下のURLへ。 Azure Functions Core Tools の操作 | Microsoft Docs インストールが終わると、func というコマンドがパスに通ると思いますが、Javaからはこのコマンドは直接利用せず、mvn経由で実行します。package してから azure-functions:runするようにしてください。 mvn package azure-functions:run 実行されると、以下のようにホストされた関数が表示されます。CURLなど curl http://localhost:7071/api/HttpExample?name=azure でクセスするとレスポンスを取得出来ると思います。 [INFO] Azure Functions Core Tools found. Azure Functions Core Tools (3.0.2931 Commit hash: d552c6741a37422684f0efab41d541ebad2b2bd2) Function Runtime Version: 3.0.14492.0 [2021-04-14T06:53:42.928] Worker process started and initialized. Functions: HttpExample: [GET,POST] http://localhost:7071/api/HttpExample 関数の追加 関数の追加もmvn で行います。Java以外の言語は、func コマンドで実行したりもするのですが。 mvn azure-functions:add 対話的に聞かれるので、追加したいトリガーを選択します。 Choose from below options as template for new function 0. HttpTrigger 1. BlobTrigger 2. QueueTrigger 3. TimerTrigger 4. EventGridTrigger 5. EventHubTrigger 6. CosmosDBTrigger 7. ServiceBusQueueTrigger 8. ServiceBusTopicTrigger Enter index to use: 3 [INFO] Selected function template: TimerTrigger [INFO] Successfully found function template: TimerTrigger [INFO] [INFO] Step 3 of 4: Prepare required parameters [INFO] Common parameter [Function Name]: name for both the new function and Java class Enter value for Function Name: TimerTriggerFunction [INFO] Common parameter [Package Name]: package name of the new Java class Enter value for Package Name: com.example.moris [INFO] Trigger specific parameter [schedule]:Enter a cron expression of the format '{second} {minute} {hour} {day} {month} {day of week}' to specify the schedule. Enter value for schedule(Default: 0 * * * * *): [INFO] [INFO] Summary of parameters for function template: [INFO] schedule: 0 * * * * * [INFO] functionName: TimerTriggerFunction [INFO] className: TimerTriggerFunction [INFO] packageName: com.example.moris [INFO] [INFO] Step 4 of 4: Saving function to file [INFO] Successfully saved new function at c:\p\moris\blog\functions-sample\src\main\java\com\example\moris\TimerTriggerFunction.java [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ デプロイ WebApps用のプラグインでは config があったのですが、 Functions 用のプラグインにはありません。あらかじめ構成したい場合は、先ほど紹介したDocsをみてconfigurationを追加してください。構成がないままazure-functions:deployすると、適当にAzureリソースが作られます。簡単にテストしたいときは、これで問題ないでしょう。以下がデプロイしたときに自動で生成されたものです。 <configuration> <!-- function app name --> <appName>${functionAppName}</appName> <!-- function app resource group --> <resourceGroup>java-functions-group</resourceGroup> <!-- function app service plan name --> <appServicePlanName>java-functions-app-service-plan</appServicePlanName> <!-- function app region--> <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-regions for all valid values --> <region>westus</region> <!-- function pricingTier, default to be consumption if not specified --> <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-pricing-tiers for all valid values --> <!-- <pricingTier></pricingTier> --> <!-- Whether to disable application insights, default is false --> <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details for all valid configurations for application insights--> <!-- <disableAppInsights></disableAppInsights> --> <runtime> <!-- runtime os, could be windows, linux or docker--> <os>windows</os> <javaVersion>8</javaVersion> <!-- for docker function, please set the following parameters --> <!-- <image>[hub-user/]repo-name[:tag]</image> --> <!-- <serverId></serverId> --> <!-- <registryUrl></registryUrl> --> </runtime> <appSettings> <property> <name>FUNCTIONS_EXTENSION_VERSION</name> <value>~3</value> </property> </appSettings> </configuration> デプロイする前には、正しくパッケージングしましょう。細かな話を言うと、azure-functions:package がパッケージングのゴールですが、シンプルにpackage で、必要なJSONファイルなどを生成してくれます。target/azure-functions が デプロイ用の成果物が格納されたディレクトリになります。各トリガの情報は、functions.json に自動生成されます。 { "scriptFile" : "../functions-sample-1.0-SNAPSHOT.jar", "entryPoint" : "com.example.moris.Function.run", "bindings" : [ { "type" : "httpTrigger", "direction" : "in", "name" : "req", "methods" : [ "GET", "POST" ], "authLevel" : "ANONYMOUS" }, { "type" : "http", "direction" : "out", "name" : "$return" } ] } デプロイはするには、以下のコマンドを実行します。あらかじめ、az login しておいてください。 mvn azure-functions:deploy ワーカーやライブラリの依存関係の話 トリガーを具体的に呼び出すのは Azure Functions Java Worker です。ソースはGithubで公開されています。Java Functions 上での怪しい挙動などは、ここにIssueを投げても良いでしょう(サポートでもいいですけど) https://github.com/Azure/azure-functions-java-worker また、Java8とJava11で、クラスロードの優先順位が変わるので注意が必要です。 Java8では、ワーカー側のJarを読み込んで、次にクライアント側のJarを読み込みますが、Java11では、常にクライアント側のJarを読み込みます。Java8でこの挙動を変更したいときは、環境変数 FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS を 1 or True に設定してください。 とくに、FunctionsのランタイムにJava8を選択したとき、 Azure SDK for Java との相性が悪いので 例外が出たり、ハングしてタイムアウトする場合があるので注意が必要です。 まとめ WebApps のほうは、azure-webapp なのに、Functions の方は、azure-functions でいつもプラグイン名が混乱します。単複系は難しい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クラスファイル内 コンスタントプールの動きString&Integer

javap クラスファイルの確認 詳細に見るために javap -vのオプションをつける Equals2.classの中身をみる コンスタントプールの確認 String a = "sample" String b = "sample" 定数化されコンスタントプールに保存されて使いまわしが行われる コンスタントプールに入っているかの確認 +補足 よく使われる値/文字列リテラルなどはメモリを無駄にしないために使い回しをしようとする コンパイルするとコンスタントプールにロードが行われる IntegerクラスやDoubleなどのラッパークラスも同じような仕掛けを持っている var a = new String("apple") var b = new String("apple")では 定数化されず同じ文字列でも使い回しは行われない 上の画像を見てわかるようにappleは別の場所にいる ここにいた Main3_12.java package chap3; public class Main3_12 { public static void main(String[] args) { var a = "sample"; var b = "sample"; System.out.println( a == b); System.out.println(", "); System.out.println(a.equals(b)); //これだと違う番地になるので==はfalseになる var x = new String("apple"); var z = new String("apple"); System.out.println(x == z);//false同じアドレスにはいないけど内容は同じだよねってこと System.out.println(x.equals(z));//true } } Integerだと−127~127まではコンスタントプールに入り 128からは入らない 使い回しをしていく仕掛けがコンパイラーに備わっている
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

equalsメソッドのオーバーライドの例

idが一緒ならItemNameが違ってもtrueを返す 自分の定義したクラスを比較するときはequals()をオーバーライドをする + hashCode()もオーバーライドする + equals()とhashCode()はセットで扱う ①等価(equals)の判定 指している2つのものが「同じ内容」であること(同じアドレスを指していなくてもよい) ②等値(==)の判定 指しているものが「完全に同一の存在」であること(つまり同じアドレスを指していること) equalsの場合は何をもって同じか判断するためにオーバーライドする Item.java public class Item { private int id ; private String name; public Item(int id, String name) { super(); this.id = id; this.name = name; } @Override public boolean equals(Object obj) {//なんでも入ってきていいようにObject型を if(obj == null) {return false;} //Itemがなければ //違う型だったら値を比べる話ではないので //もしも引数で受け取ったObjectクラスがItem型のインスタンスでなければfalse if(obj instanceof Item == false) {return false;}//この二つでnullでもなくItem型のインスタンスであることの補償となる //次はフィールドの値が一致するか/同じ値を持っているか //三通りありidだけ一致したらok/nameだけ一致したらok/id && nameが一致したらok //ここからはidが一致したら同じ商品だと言うことにする/自身にidとItem型にキャストしたobjの.id if(this.id == ((Item)obj ).id) {return true;} //条件に一致した時だけtrueを返したらいいからreturnはデフォルトはfalseにする return false; //親インスタンス部分のメソッドを呼び出す/親メソッドなのでこれではだめ // return super.equals(obj); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } Equals2.java package yasasikunaiYouTube; public class Equals2 { public static void main(String[] args) { Item a = new Item(100,"apple"); Item b = new Item(100,"apples"); System.out.println(a == b); System.out.println(a.equals(b)); } } 実行 false true hashCode()必要な理由 コレクションで色んなオブジェクトを扱っていくときにMapやSetやList色々比較検討をしたり,並び順を変えたりとか同じものがあらかじめ入っているかなどを検証したりやったりする. Item.java public class Item { private int id ; private String name; public Item(int id, String name) { super(); this.id = id; this.name = name; } // @Override // public boolean equals(Object obj) {//なんでも入ってきていいようにObject型を // if(obj == null) {return false;} // //Itemがなければ // //違う型だったら値を比べる話ではないので // //もしも引数で受け取ったObjectクラスがItem型のインスタンスでなければfalse // if(obj instanceof Item == false) {return false;}//この二つでnullでもなくItem型のインスタンスであることの補償となる // //次はフィールドの値が一致するか/同じ値を持っているか // //三通りありidだけ一致したらok/nameだけ一致したらok/id && nameが一致したらok // //ここからはidが一致したら同じ商品だと言うことにする/自身にidとItem型にキャストしたobjの.id // if(this.id == ((Item)obj ).id) {return true;} // //条件に一致した時だけtrueを返したらいいからreturnはデフォルトはfalseにする // return false; // //親インスタンス部分のメソッドを呼び出す/親メソッドなのでこれではだめ //// return super.equals(obj); // } public int getId() { return id; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Item other = (Item) obj; if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } Equals2.java package yasasikunaiYouTube; public class Equals2 { public static void main(String[] args) { Item a = new Item(100,"apple"); Item b = new Item(100,"apple"); System.out.println(a == b); System.out.println(a.equals(b)); System.out.println(a.hashCode()); System.out.println(b.hashCode()); } } 実行 false true 93033271 93033271
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java Wordで指定するテキストにブックマークを追加

今回はSpire.Doc for Javaという無料のライブラリを利用して、Wordで指定するテキストにブックマークを追加する方法を紹介します。 下準備 1.E-iceblueの公式サイトからFree Spire.doc for Java無料版をダウンロードしてください。 2.IDEを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire.doc.jarを参照に追加してください。 import com.spire.doc.*; import com.spire.doc.documents.Paragraph; import com.spire.doc.documents.TextSelection; import com.spire.doc.fields.TextRange; public class AppendBookmarkToCharacter { public static void main(String[]args){ //ファイルをロードします。 Document doc = new Document(); doc.loadFromFile("sample.docx"); //指定するテキストを探します。 TextSelection textSelection = doc.findString("。様々な花が咲き、果実が生じる。",false,false); TextRange range = textSelection.getAsOneRange(); Paragraph para = range.getOwnerParagraph(); int index = para.getChildObjects().indexOf(range); //ブックマークを追加します。 BookmarkStart start = new BookmarkStart(doc,"ブックマーク1"); BookmarkEnd end = new BookmarkEnd(doc, "ブックマーク1"); para.getChildObjects().insert(index, start); para.getChildObjects().insert(index + 2, end); //保存します。 doc.saveToFile("appendbookmarktocharacter.docx",FileFormat.Docx_2013); doc.dispose(); } } 実行結果  
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java ODTファイルをPDFで保存

ODTファイル「OpenDocument」 とは、ワープロソフトなどで作成・編集される文書ファイルの標準ファイル形式の一つです。今回はSpire.Presentation for Javaという無料のライブラリを利用して、ODTファイルをPDFに変換する技を紹介していきます。 下準備 1.E-iceblueの公式サイトからFree Spire. Presentation for Java無料版をダウンロードしてください。  2.IDEを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire. Presentation.jarを参照に追加してください。 サンプルコード import com.spire.presentation.*; public class Test { public static void main(String[] args) throws Exception { Presentation presentation = new Presentation(); presentation.loadFromFile("toPDF.odp",FileFormat.ODP); presentation.saveToFile("output/Result.pdf", FileFormat.PDF); } } 以上です 如何でしょうか?簡単でしょう? もしお役に立てば幸いです、なお、ここまで読んでくださってありがとうございます。  
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java Wordで指定するテキストにブックマークを追加

今回はSpire.Doc for Javaという無料のライブラリを利用して、Wordで指定するテキストにブックマークを追加する方法を紹介します。 下準備 1.E-iceblueの公式サイトからFree Spire.doc for Java無料版をダウンロードしてください。 2.IDEを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire.doc.jarを参照に追加してください。 import com.spire.doc.*; import com.spire.doc.documents.Paragraph; import com.spire.doc.documents.TextSelection; import com.spire.doc.fields.TextRange; public class AppendBookmarkToCharacter { public static void main(String[]args){ //ファイルをロードします。 Document doc = new Document(); doc.loadFromFile("sample.docx"); //指定するテキストを探します。 TextSelection textSelection = doc.findString("。様々な花が咲き、果実が生じる。",false,false); TextRange range = textSelection.getAsOneRange(); Paragraph para = range.getOwnerParagraph(); int index = para.getChildObjects().indexOf(range); //ブックマークを追加します。 BookmarkStart start = new BookmarkStart(doc,"ブックマーク1"); BookmarkEnd end = new BookmarkEnd(doc, "ブックマーク1"); para.getChildObjects().insert(index, start); para.getChildObjects().insert(index + 2, end); //保存します。 doc.saveToFile("appendbookmarktocharacter.docx",FileFormat.Docx_2013); doc.dispose(); } } 実行結果  
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

探索、Slay the Spire

はじめに 本記事ではゲームSlayTheSpireのソースコードを探索し、ゲームの細かい仕様を調べる方法を解説します。以下のような読者を想定しています。 非プログラマー PCをそれなりに使える Steam版 SlayTheSpireをインストール済みである SlayTheSpireを熟知しており、プログラミングの知識の不足をSlayTheSpireの知識で補える(A20よりは楽だと思います) 準備 jad(Java逆コンパイラ)のダウンロード こちらのサイトからjadをダウンロードし、適当なディレクトリ D:\Temporary に配置してください。(このディレクトリは必要に応じて読み替えてください) テキストエディタのインストール 逆コンパイルしたソースコードを読むためにテキストエディタをインストールしましょう。こだわりがなければサクラエディタあたりが無難かもしれません。 逆コンパイル まずはSlayTheSpireのjarファイルを見つけ出しましょう。SteamでSlayTheSpireを右クリックし、管理 ⇒ ローカルファイルを閲覧 をクリックしてください。エクスプローラが起動し、SlayTheSpireのインストールディレクトリが表示されるはずです。その中に desktop-1.0.jar というファイルがあるので、先ほどの作業用ディレクトリにコピーしてください。 次にそのファイルの拡張子をzipに変更し、右クリックで すべて展開 を選択します。展開先ディレクトリを聞かれるので D:\Temporary\desktop-1.0 を選択し、展開します。 次にコマンドプロンプトを起動します。Windowsキーを押しcmdと入力しエンターを押すことで起動できるはずです。 そうしたら D: cd Temporary と打ち込みます。 画面に D:\Temporary> と表示されたら成功です。 次に jad -s java -d src -r desktop-1.0\com\**\*.class と打ち込みます。 すると D:\Temporary\src 配下に逆コンパイルされたSlay the Spireのソースコードが生成され、仕様調査の準備が整いました。 仕様の調査 ゴールの設定 それではさっそくソースコードを読み解いていきましょう。題材は攻撃時/被攻撃の効果の解決処理が良いでしょう。 皆さまご存じの通り、このゲームではバッファー、猛毒の仕込み、ブーツ、鳥居、静電放電、タングステンロッド等、攻撃時に発動する効果がたくさんあります。せっかくバッファーを張っていてタングステンロッドも持っていたのに、痛みの効果によってバッファーが剥がれてしまった。HP減少は発生していなかったのに何故!?おかげで心臓に負けちゃったよ、というような悲劇には事欠きません。 そのような事故を防ぐため、仕様の詳細な理解は必要不可欠です。さぁ始めましょう。 ダメージ計算の中枢部を探す とっかかりはどこからでも良いのですが、まずは一番謎の多いタングステンロッドを入り口として調べていきましょう。 D:\Temporary\src の中をファイル名Tungstenで検索するとD:\Temporary\src\com\megacrit\cardcrawl\relics\TungstenRod.java というファイルが見つかります。これがどうやらタングステンロッドを表すクラスのようです。 それをテキストエディタで開いてみてください。以下のようなコードが見つかったはずです。 もしあなたが重度のSlayTheSpire中毒患者であれば、プログラミングに詳しくなくても書かれているメソッド名/変数名と計算式の内容から、これはタングステンロッドを表すコードで間違いなさそうだなという確信が得られると思います。 com\megacrit\cardcrawl\relics\TungstenRod.java public int onLoseHpLast(int damageAmount) { if(damageAmount > 0) { flash(); return damageAmount - 1; } else { return damageAmount; } } それでは次に D:\Temporary\src の中から、 onLoseHpLast という文字列を含むファイルを検索してみましょう(テキストエディタの検索機能を使うと早いと思います)。 これにより、タングステンロッドの処理を呼び出している部分、すなわちSlayTheSpireにおけるダメージ計算の中枢部が見つけられるはずです。 D:\Temporary\src\com\megacrit\cardcrawl\characters\AbstractPlayer.java というファイルが見つかりましたね? ダメージ計算処理の解読 onLoseHPLast を呼び出している箇所を上に辿っていくと、以下のような行に行き当たると思います。これがダメージ計算処理の中枢です。 com\megacrit\cardcrawl\characters\AbstractPlayer.java public void damage(DamageInfo info) { label0: { boolean hadBlock; label1: { label2: { int damageAmount = info.output; hadBlock = true; if(currentBlock == 0) hadBlock = false; if(damageAmount < 0) damageAmount = 0; if(damageAmount > 1 && hasPower("IntangiblePlayer")) damageAmount = 1; これを読み解いていけば、処理の順序がわかってくるはずです。 たとえばこのコードは何でしょうか。 com\megacrit\cardcrawl\characters\AbstractPlayer.java if(info.owner == this) { for(Iterator iterator = relics.iterator(); iterator.hasNext();) { AbstractRelic r = (AbstractRelic)iterator.next(); damageAmount = r.onAttackToChangeDamage(info, damageAmount); } } どうやら持っている全レリックのonAttackToChangeDamageメソッドを呼び出しているようですが、onAttackToChangeDamageとはいったい何なのでしょう。テキストエディタにてソースコードを検索してみれば何かわかるかもしれません。 ■ '\<onAttackToChangeDamage\>' を 'D:/Temporary/src/com/megacrit' 以下の '*.java' から 文字コード:自動 で検索中... "D:/Temporary/src/com/megacrit/cardcrawl/characters/AbstractPlayer.java" 1748: damageAmount = r.onAttackToChangeDamage(info, damageAmount); 1758: damageAmount = p.onAttackToChangeDamage(info, damageAmount); "D:/Temporary/src/com/megacrit/cardcrawl/powers/AbstractPower.java" 342: public int onAttackToChangeDamage(DamageInfo info, int damageAmount) "D:/Temporary/src/com/megacrit/cardcrawl/relics/AbstractRelic.java" 783: public int onAttackToChangeDamage(DamageInfo info, int damageAmount) "D:/Temporary/src/com/megacrit/cardcrawl/relics/Boot.java" 28: public int onAttackToChangeDamage(DamageInfo info, int damageAmount) '\<onAttackToChangeDamage\>' を 'D:/Temporary/src/com/megacrit' 以下の '*.java' から 文字コード:自動 で検索しました。 検索したファイル拡張子:java 5 行がマッチしました。( 0.79 sec.) はい、SlayTheSpireプレイヤーの方は一瞬で理解できましたね。みなさんご存じブーツです。 どうやらこのonAttackToChangeDamage は、バニラでは事実上のブーツ専用メソッドになっている模様。Modまで含めれば、ブーツ以外のレリックもこのメソッドを使っているかもしれません。 このようにして順々に調べていけば全貌が明らかになってくるはず…。 解析結果まとめ 以下がそのようにして調べた結果を日本語のコメントにて書き加えたものです。 貴方に良いSlayTheSpireライフを。 com\megacrit\cardcrawl\characters\AbstractPlayer.java public void damage(DamageInfo info) { label0: { boolean hadBlock; label1: { label2: { // 初期ダメージ int damageAmount = info.output; hadBlock = true; if(currentBlock == 0) hadBlock = false; if(damageAmount < 0) damageAmount = 0; if(damageAmount > 1 && hasPower("IntangiblePlayer")) damageAmount = 1; // ブロックによるダメージ軽減 damageAmount = decrementBlock(info, damageAmount); if(info.owner == this) { for(Iterator iterator = relics.iterator(); iterator.hasNext();) { // レリックによるダメージ変更処理(例:ブーツ) AbstractRelic r = (AbstractRelic)iterator.next(); damageAmount = r.onAttackToChangeDamage(info, damageAmount); } } if(info.owner != null) { for(Iterator iterator1 = info.owner.powers.iterator(); iterator1.hasNext();) { // バフによるダメージ変更処理(バニラでは対応効果なし) AbstractPower p = (AbstractPower)iterator1.next(); damageAmount = p.onAttackToChangeDamage(info, damageAmount); } } for(Iterator iterator2 = relics.iterator(); iterator2.hasNext();) { // レリックによるダメージ変更処理(バニラでは対応効果なし) AbstractRelic r = (AbstractRelic)iterator2.next(); damageAmount = r.onAttackedToChangeDamage(info, damageAmount); } for(Iterator iterator3 = powers.iterator(); iterator3.hasNext();) { // バフによるダメージ変更処理(例:心臓のターン内ダメージ上限, バッファー) AbstractPower p = (AbstractPower)iterator3.next(); damageAmount = p.onAttackedToChangeDamage(info, damageAmount); } if(info.owner == this) { // レリックによる攻撃時特殊効果(バニラでは対応効果なし) AbstractRelic r; for(Iterator iterator4 = relics.iterator(); iterator4.hasNext(); r.onAttack(info, damageAmount, this)) r = (AbstractRelic)iterator4.next(); } if(info.owner != null) { // 攻撃者側のバフによる攻撃時特殊効果(例:猛毒の仕込み) AbstractPower p; for(Iterator iterator5 = info.owner.powers.iterator(); iterator5.hasNext(); p.onAttack(info, damageAmount, this)) p = (AbstractPower)iterator5.next(); for(Iterator iterator6 = powers.iterator(); iterator6.hasNext();) { // バフによる攻撃時特殊効果(例: 静電放電, 炎の障壁, マッドグレムリンの怒りによる攻撃力上昇) AbstractPower p = (AbstractPower)iterator6.next(); damageAmount = p.onAttacked(info, damageAmount); } for(Iterator iterator7 = relics.iterator(); iterator7.hasNext();) { // レリックによる攻撃時特殊効果(例: 鳥居) AbstractRelic r = (AbstractRelic)iterator7.next(); damageAmount = r.onAttacked(info, damageAmount); } } else { logger.info("NO OWNER, DON'T TRIGGER POWERS"); } for(Iterator iterator8 = relics.iterator(); iterator8.hasNext();) { // レリックによる最終ダメージ変更処理(例: タングステンロッド) AbstractRelic r = (AbstractRelic)iterator8.next(); damageAmount = r.onLoseHpLast(damageAmount); } lastDamageTaken = Math.min(damageAmount, currentHealth); // ここまでの処理でダメージが0になっていたら処理を中断 if(damageAmount <= 0) break label1; for(Iterator iterator9 = powers.iterator(); iterator9.hasNext();) { // バフによるHP減少時処理(バニラでは対応効果なし) AbstractPower p = (AbstractPower)iterator9.next(); damageAmount = p.onLoseHp(damageAmount); } // レリックよるHP減少時処理(バニラでは対応効果なし) AbstractRelic r; for(Iterator iterator10 = relics.iterator(); iterator10.hasNext(); r.onLoseHp(damageAmount)) r = (AbstractRelic)iterator10.next(); // バフによるHP減少時処理(例:プレートアーマー効果減少) AbstractPower p; for(Iterator iterator11 = powers.iterator(); iterator11.hasNext(); p.wasHPLost(info, damageAmount)) p = (AbstractPower)iterator11.next(); // レリックによるHP減少時処理(例:ルーニックキューブ, 自己形成粘土) AbstractRelic r; for(Iterator iterator12 = relics.iterator(); iterator12.hasNext(); r.wasHPLost(damageAmount)) r = (AbstractRelic)iterator12.next(); if(info.owner != null) { // 攻撃者側のバフによるHP減少時特殊効果(例:刺創の本による苦痛の一刺し) AbstractPower p; for(Iterator iterator13 = info.owner.powers.iterator(); iterator13.hasNext(); p.onInflictDamage(info, damageAmount, this)) p = (AbstractPower)iterator13.next(); }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む