- 投稿日:2019-11-24T23:52:24+09:00
Mavenで導入したKotlinのInterfaceに実装した関数を、Java8からデフォルト実装として利用する方法
概要
KotlinのI/Fにはデフォルト実装を定義できますが、Java側からそのデフォルト実装を利用するにはあらかじめ設定が必要です。
今回はその設定方法を書き記します。前提
- Maven
- Kotlin 1.35
- Java 1.8
設定方法
①Kotlinのプラグインの設定
pom.xmlのkotlinをcompileさせることを定義している箇所の引数に、
-Xjvm-default=compatibility
を追加
例:pom.xml<plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>${kotlin.version}</version> <executions> <execution> <id>compile</id> <goals> <goal>compile</goal> </goals> <configuration> <sourceDirs> <sourceDir>${project.basedir}/src/main/kotlin</sourceDir> <sourceDir>${project.basedir}/src/main/java</sourceDir> </sourceDirs> <args> <arg>-Xjvm-default=compatibility</arg> </args> </configuration> </execution> <execution> <id>test-compile</id> <goals> <goal>test-compile</goal> </goals> <configuration> <sourceDirs> <sourceDir>${project.basedir}/src/test/kotlin</sourceDir> <sourceDir>${project.basedir}/src/test/java</sourceDir> </sourceDirs> <args> <arg>-Xjvm-default=compatibility</arg> </args> </configuration> </execution> </executions> </plugin>propertiesにjvmTargetを記載
例:pom.xml<properties> <jdk.version>1.8</jdk.version> <encoding>UTF-8</encoding> <kotlin.version>1.3.60</kotlin.version> <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> </properties>②Javaにデフォルト実装として認識させたいメソッドに
@JvmDefault
アノテーションを付与以上となります。
- 投稿日:2019-11-24T23:04:22+09:00
【Java】条件文の個人的まとめ(基礎)
【Java】条件文の個人的まとめ(基礎)
エンジニアの t-77 です。
個人的にJavaの勉強で大事だなと思ったことをまとめました。
今回は、条件文についてです。① if文
- if文は、条件がtrueだった場合に、そのブロック内の文を処理する。
- elseを使うことで、設定した条件以外がtrueとして判定され、そのブロック内の文を処理する。
- else ifを使うことで、複数の条件を設定可能。
sample.java// numberの値によって、出力される言葉が異なる。 // number == 10 の場合、処理が実行される。 if (number == 10) { System.out.println("Wayne"); // number == 11 の場合、処理が実行される。 } else if (number == 11) { System.out.println("Ryan"); // numberが上記以外の場合、処理が実行される。 } else { System.out.println("other"); }上記の例文の場合「出力処理」は、if文内で共通である。
したがって、下記の例文のように「出力処理」をまとめたほうが修正・保守しやすい。sample2.java// numberの値によって、出力される言葉が異なる。 // 変数nameを定義する。 String name; if (number == 10) { name = "Wayne"; } else if (number == 11) { name = "Ryan"; } else { name = "other"; } // numberによってnameに代入された文字列が出力される。 System.out.println(name);② switch文
- switch文は、caseの値に一致した場合、その文を処理する。
- どれにも一致しなかった場合、defaultの文を処理する。
- defaultは、省略することも可能。
- 処理を終了させるために、「break」を必ず書く。
sample.java// numberの値によって、出力される言葉が異なる。 // caseの値が10の場合、処理が実行される。 switch (number) { case 10: System.out.println("Wayne"); break; // caseの値が11の場合、処理が実行される。 case 11: System.out.println("Ryan"); break; // 値が上記以外の場合、defaultの処理が実行される。 default: System.out.println("other"); break; }下記のように、複数のcaseで同じ処理を行わせることも可能である。
sample2.java// numberの値によって、出力される言葉が異なる。 // caseの値が1、2の場合、処理が実行される。 switch (number) { case 1: case 2: System.out.println("低評価"); break; // caseの値が3の場合、処理が実行される。 case 3: System.out.println("及第点"); break; // caseの値が4、5の場合、処理が実行される。 case 4: case 5: System.out.println("高評価"); break; // 値が上記以外の場合、defaultの処理が実行される。 default: System.out.println("評価なし"); break; }③ while文
- while文は、条件がfalseになるまでブロック内の文を繰り返し処理する。
- falseになるように条件を記述しないと、ブロック内が永遠にループしてしまうため注意する。
sample.java// 初期値を設定する。 int i = 1; // falseになるまで、文を繰り返し処理する。 while (i <= 11) { System.out.println("背番号は、" + i + "番だ"); // iを増やすことで、永遠にループしないようにする。 i++; }④ do~while文
- do~while文は、条件がfalseになるまでブロック内の文を繰り返し処理する。
- while文が最初の繰り返し前に条件がfalseであれば、処理が行われないのに対して、do~while文は、少なくとも1回は繰り返し処理を行い、その後条件がfalseになるまで繰り返し処理を行う。
sample.java// 初期値を設定する。 int i = 1; // doブロック内の文を処理する。 do { System.out.println("背番号は、" + i + "番だ"); // iを増やすことで、永遠にループしないようにする。 i++; // falseになるまで、文を繰り返し処理する。 } while (i <= 11) ;⑤ 文のネスト
- 文は、ネストする(入れ子にする)ことができる。
- ネストすることで、より複雑な記述ができる。
- ネストしすぎるとコードが見ずらくなるため、複数の人と共同で開発する場合には切り分けられる部分は切り分けたほうが良い。
sample.java// for文の中にfor文のような記述が可能。 // if文など異なる条件文を組み合わせることも可能。 for (int i = 1; i <= 11; i++) { System.out.println("背番号が" + i + "番の選手だ。"); for (int s = 1; s <= 5; s++) { System.out.println(s + "回目のシュートを打った。"); if (s == 3) { System.out.println("シュートを決めた。"); } } }⑥ break文
- break文は、処理の流れを強制的に終了させ、ブロックから抜けることができる。
- switch文では、breakが必須。
sample.java// i = 8の場合、処理が終了する。 for (int i = 1; i <= 11; i++) { System.out.println("背番号が" + i + "番の選手だ。"); if (i == 8) { System.out.println("処理を終了します。"); break; } }console背番号が1番の選手だ。 背番号が2番の選手だ。 背番号が3番の選手だ。 背番号が4番の選手だ。 背番号が5番の選手だ。 背番号が6番の選手だ。 背番号が7番の選手だ。 処理を終了します。 ※i = 8になった時に、breakによって処理が終了されている。⑦ continue文
- continue文は、繰り返し内の処理をスキップし、ブロックの先頭に戻り、次の処理に入ることができる。
sample.java// i = 8の場合、処理をスキップし、次の処理に入る。 for (int i = 1; i <= 11; i++) { System.out.println("背番号が" + i + "番の選手だ。"); if (i == 8) { continue; } }console背番号が1番の選手だ。 背番号が2番の選手だ。 背番号が3番の選手だ。 背番号が4番の選手だ。 背番号が5番の選手だ。 背番号が6番の選手だ。 背番号が7番の選手だ。 背番号が9番の選手だ。 背番号が10番の選手だ。 背番号が11番の選手だ。 ※i = 8になった時に、continueによって処理がスキップされている。Javaの勉強の一環でしたが、条件文は、JavaScriptなど他の言語でも使用されるため、基礎をもう一度見直す良い機会となりました。
以上になります。
- 投稿日:2019-11-24T22:03:56+09:00
Spring フラッシュスコープを利用したリダイレクトと単体テスト
あるエンドポイントから別のエンドポイントにリダイレクトさせる際に、フラッシュスコープを利用するとリダイレクト先へパラメータを引き継がせることができる。
コントローラ
以下のコントローラで
/from
にGETでアクセスした際に、/to
へリダイレクトさせる。
リダイレクト元の処理で、bookName
とbuyerList
をフラッシュスコープに突っ込んで、リダイレクト先へ引き継がせる。package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import java.util.Arrays; import java.util.List; @Controller public class DemoController { @GetMapping(path = "/from") public String from(RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("bookName", "ドラえもん"); List<String> buyerList = Arrays.asList("野比", "剛田"); redirectAttributes.addFlashAttribute("buyerList", buyerList); return "redirect:/to"; } @GetMapping(path = "/to") public String to(Model model) { System.out.println(model); return "demo"; } }
/from
にアクセスすると/to
にリダイレクトされ、引き継がれたパラメータがコンソールに表示される。{bookName=ドラえもん, buyerList=[野比, 剛田]}ポイント
- リダイレクト元のメソッドで
RedirectAttributes
を引数に設定し、.addFlashAttribute
で引き継ぐattribute名と内容を指定する。なお、attribute名を省略することもできるが、その場合はクラス名に応じてattribute名が自動設定される。- リダイレクト先では引数に設定した
Model
の中にattributeが含まれている。内容を参照したい場合は.getAttribute
でattribute名を指定する。単体テスト
/from
にアクセスした際に、パラメータを引き継いで/to
へリダイレクトされることを確認する。package com.example.demo.controller; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import java.util.Arrays; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.flash; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc public class DemoControllerTest { @Autowired MockMvc mockMvc; @Test public void redirectWithAttributes() throws Exception { mockMvc.perform(get("/from")) .andExpect(status().isFound()) .andExpect(redirectedUrl("/to")) .andExpect(flash().attribute("bookName", "ドラえもん")) .andExpect(flash().attribute("buyerList", Arrays.asList("野比", "剛田"))); } }ポイント
andExpect()
で期待値通りに動いていることを確認。status().isFound()
でHTTPステータスが302
であることを確認。redirectedUrl()
でリダイレクト先のパスをアサーション。flash().attribute()
で引き継ぐパラメータのアサーション。
FlashMap
による取り出し以下のように引き継ぎパラメータを
FlashMap
で取り出すことができる。余計なパラメータが入っていないことの確認や、単純な文字列表現ではアサーションできない場合はこちらを利用する。@Test public void redirectWithAttributes() throws Exception { MvcResult mvcResult = mockMvc.perform(get("/from")) .andExpect(status().isFound()) .andExpect(redirectedUrl("/to")) .andReturn(); FlashMap flashMap = mvcResult.getFlashMap(); assertThat(flashMap.size()).isEqualTo(2); assertThat(flashMap.get("bookName")).isEqualTo("ドラえもん"); assertThat(flashMap.get("buyerList")).isEqualTo(Arrays.asList("野比", "剛田"));
- 投稿日:2019-11-24T21:43:24+09:00
Androidで文字を点滅するメソッドができてうれしい
こんにちはヨースケです。文字列の一致に"=="を使っていました(笑)。equalsですね!
初めて作ったアプリで実装
この文字を点滅させるメソッドは、初めてアプリを公開した時に実装したものになります。計算問題付き電卓←このアプリは名前の通り電卓に計算問題を出す機能を付けたアプリとなっています。計算問題がスタートするとタイマーをスタートさせ、全10問クリアするとタイマーがストップしそのタイムで点滅するようにしました。また、答え終わると過去のクリアタイムを表示するようにしています。
ソースコード
あんまり長ったらしくなってもよくないので稚拙なコードではありますが自分自身の備忘録として貼っておきます。
Quest.javapublic class Quest extends AppCompatActivity { private final Handler handler = new Handler(); //タイマーを表示 private TextView timerText; ...中略... //全問正解するとtimer_stop()を呼びます //タイマーストップ public void timer_stop() { handler.removeCallbacks(runnable); timerText.setTextColor(Color.RED); count = 0; insert_db(); result_tweet(); init(); } //止めたタイムをチカチカさせるメソッド private void init() { new Thread(new Runnable() { @Override public void run() { int time = 500; try { Thread.sleep(time); } catch (Exception e) { } handler.post(new Runnable() { @Override public void run() { if (timerText.getVisibility() == View.VISIBLE) { timerText.setVisibility(View.INVISIBLE); } else { timerText.setVisibility(View.VISIBLE); } init(); } }); } }).start(); } }このinit()メソッドで止めたタイマーをチカチカ点滅させています。この→テキストビューを点滅させる方法を参考にプログラムを組んだので大体の流れしか分からず、Threadやhandlerのところも勉強不足なのでまだまだ勉強が足りないなぁーと反省。(メソッド名ェ...)
現在は3つ目のアプリ、「一日日記(福岡編)」(仮題)を開発中です。ひと段落着いたときや投稿したいなーとなったときに書いていくのでよろしくお願いしますね(^ ^)。ちなみにTwitterもやっていますので気軽にフォローよろしくお願いします!→Twitterのアカウント
参考URL:
テキストビューを点滅させる方法:https://codeday.me/jp/qa/20190108/126818.html
- 投稿日:2019-11-24T21:43:23+09:00
Cloud Firestore を Java から使う際のドキュメントまとめ
Firestore 全般
- Cloud Firestore | Google Cloud
- Cloud Firestore documentation | Cloud Firestore | Google Cloud
- Cloud Firestore | Firebase
料金
データモデル
- Cloud Firestore データモデル | Firebase
- サポートされているデータ型 | Firebase
- Cloud Firestore のインデックスの種類 | Firebase
- 使用量と制限 | Firebase
Cloud Firestore API Client Library for Java
- SDK とクライアント ライブラリ | Firebase
- Google Cloud Java Client for Firestore at master · googleapis/google-cloud-java · GitHub
- Cloud Firestore API Client Library for Java | Google Developers
- com.google.cloud.firestore (Google Cloud API)
- Cloud Firestore API v1
サンプルコード
- 投稿日:2019-11-24T19:41:13+09:00
再帰下降構文解析法による数式の構文解析器の実装(Java)
職場のネット寸断が激しかったので久しぶりのネット活動です
タイトルは今のQiitaではあまり受けが良くなさそうな硬そうな命名にしてみました要件で求められるパフォーマンスの関係で、再帰下降構文解析法で四則計算する解析器を作成しました
誰かの参考になるかもしれないので置いておきます要件
バッチアプリで数式が文字列で取得されるので、それを計算して結果を返却したかったらしいのですが、その数が膨大でした
元々は、JavaからJavaScriptを呼び出して数式をそのまま渡して計算してもらうつもりだったそうなのですが、対象の式の数が何万何十万単位のため1日で終了しなかったようですしかもこれからもどんどん増えるそうなのです!
当然次のジョブもあるので、その開始時間までに処理が終わるようにしなければなりません
そこで僕に何とかしてほしいと話がまわってきました
最初に話を聞いたときは、外部プログラム呼び出しでしかもJavaScriptで高速な計算処理ができるわけないがな、と思いましたがようは、高速な四則計算が可能な解析器を作成すればよいわけです
除算時の丸め誤差も制御したいらしいので、それも考える必要がありますまあ全部Javaで実装すれば速度面は問題ないだろうと予想して、取り合えず単純な実装のわりにそこそこ強力な再帰下降構文解析法でいくことに決めました
コード
以下Java8で実装しています
FormulaParser.javaimport java.math.BigDecimal; import java.math.RoundingMode; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; public class FormulaParser { private static final int HIGH_PRIORITY = 3; private static final int MID_PRIORITY = 2; private static final int LOW_PRIORITY = 1; private static final Pattern EMPTY_BRACKET = Pattern.compile("\\(\\)"); private static final Pattern NOT_CLOSE_BRACKET = Pattern.compile("\\)\\("); private static final int NO_EXIST = -1; private static final String ZERO = "0"; private static final String BRACKET_AND_ZERO = "(0"; private String expression; // 式 private FormulaParser left; // 左子ノード private FormulaParser right; // 右子ノード private int scale; /** * スケールありコンストラクタ * ※除算の場合のみscaleを考慮する * * @param expression 計算式 * @param scale 除算時切り落とし小数点位置 */ public FormulaParser(String expression, int scale) { this.expression = format(expression); this.scale = scale; } /** * 式を二分木に分割し計算する * * @throws FormulaParseException */ public String execute() throws FormulaParseException { // 最も外側の括弧を消す String exp = delMostOuterBrackets(this.expression); // 式から演算子を探して位置を取得 int opePos = getOpePos(exp); // 式に演算子が含まれないなら項であるとみなす if (opePos < 0) { left = null; right = null; return new BigDecimal(exp).toPlainString(); } // 演算子位置が式の先頭か末尾の場合、不正扱い if (opePos == 0 || opePos == exp.length() - 1) { throw new FormulaParseException(exp); } // 演算子の左側を左の部分式としてノードを作成 left = new FormulaParser(exp.substring(0, opePos), scale); // 演算子の右側を右の部分式としてノードを作成 right = new FormulaParser(exp.substring(opePos + 1), scale); // 残った演算子をこのノートに設定 expression = exp.substring(opePos, opePos + 1); return calculate(left.execute(), OPERATOR.getEnum(expression), right.execute(), scale); } /** * 演算子の位置を取得 * * @param exp 式 * @return 演算子位置(0始まり)/ない場合は-1を返す */ private static int getOpePos(String exp) { int opePos = NO_EXIST; int curPriority = Integer.MAX_VALUE; int nest = 0; for (int i = 0, len = exp.length(); i < len; i++) { int priority = 0; switch (OPERATOR.getEnum(String.valueOf(exp.charAt(i)))) { case PLUS: case MINUS: priority = MID_PRIORITY; break; case MULTIPLY: case DIVIDE: priority = HIGH_PRIORITY; break; case LEFT_BRACKET: nest++; continue; case RIGHT_BRACKET: nest--; continue; default: continue; } if (nest == 0 && priority <= curPriority) { curPriority = priority; opePos = i; } } return opePos; } /** * 計算処理 * * @param lExp 左項 * @param ope 演算子 * @param rExp 右項 * @param scale スケール */ private String calculate(String lExp, OPERATOR ope, String rExp, int scale) throws FormulaParseException { BigDecimal left = new BigDecimal(lExp); BigDecimal right = new BigDecimal(rExp); switch (ope) { case PLUS: return left.add(right).toPlainString(); case MINUS: return left.subtract(right).toPlainString(); case MULTIPLY: return left.multiply(right).toPlainString(); case DIVIDE: return left.divide(right, scale, RoundingMode.DOWN).toPlainString(); default: throw new FormulaParseException(left + ope.val + rExp); } } /** * フォーマット * 半角スペースは排除 * 正負記号と加減算演算子の区別がつけ難いため、0埋めして簡単にする * * @param exp 式 * @return フォーマットされた式 ex) -3 + 1 → 0-3+1 */ private static String format(String exp) { // 半角スペースは排除する StringBuilder e = new StringBuilder(exp.replaceAll(" ", "")); int cur = 0; for (; ; ) { int plusIndex = e.indexOf(OPERATOR.PLUS.val, cur); int minusIndex = e.indexOf(OPERATOR.MINUS.val, cur); if (plusIndex == NO_EXIST && minusIndex == NO_EXIST) { break; } // 演算子が存在しかつ前にある方をのインデックスを取得 if (plusIndex < minusIndex) { cur = (plusIndex == NO_EXIST) ? minusIndex : plusIndex; } else { cur = (minusIndex == NO_EXIST) ? plusIndex : minusIndex; } if (cur == 0) { e.insert(cur, ZERO); cur = cur + ZERO.length() + 1; continue; } // 演算子の一つ前の文字が数値ではなく、閉じ括弧や乗算、除算演算子でもない場合0を追加 char preChar = e.charAt(cur - 1); if (!Character.isDigit(preChar) && preChar != OPERATOR.RIGHT_BRACKET.cVal) { if (preChar == OPERATOR.MULTIPLY.cVal || preChar == OPERATOR.DIVIDE.cVal || preChar == OPERATOR.MINUS.cVal) { int endDigits = 0; for (int i = cur + 1, len = e.length(); i < len; i++) { char c = e.charAt(i); endDigits = i; if (!Character.isDigit(c) && c != '.') { break; } } e.insert(cur, BRACKET_AND_ZERO).insert(endDigits + BRACKET_AND_ZERO.length() + 1, OPERATOR.RIGHT_BRACKET.cVal); cur = endDigits + BRACKET_AND_ZERO.length(); } else { e.insert(cur, ZERO); cur = cur + ZERO.length(); } } cur++; if (cur > e.length()) break; } return e.toString(); } /** * 丸括弧削除処理 * 式から最も外側の括弧を削除する * (1+2)+(3+4)のような式はそのまま返す * 括弧が閉じていないなら不正な式として例外をスロー * * @param exp 式 * @return 丸括弧を削除した式 ex) (4*2) → 4*2, ((3+4)) → 3+4, (1+2)+(3+4) → (1+2)+(3+4) * @throws FormulaParseException */ private static String delMostOuterBrackets(String exp) throws FormulaParseException { if (matchFirst(exp, EMPTY_BRACKET).isPresent()) throw new FormulaParseException(exp); if (matchFirst(exp, NOT_CLOSE_BRACKET).isPresent()) throw new FormulaParseException(exp); if (exp.charAt(0) == OPERATOR.RIGHT_BRACKET.cVal) throw new FormulaParseException(exp); boolean hasMostOuterBrackets = false; int nest = 0; // 1文字目を検証 if (exp.charAt(0) == OPERATOR.LEFT_BRACKET.cVal) { hasMostOuterBrackets = true; nest++; } // 1文字目以降を1文字ずつずつ検証 for (int i = 1, len = exp.length(); i < len; i++) { if (exp.charAt(i) == OPERATOR.LEFT_BRACKET.cVal) { nest++; } else if (exp.charAt(i) == OPERATOR.RIGHT_BRACKET.cVal) { nest--; if (nest == 0 && i < len - 1) { hasMostOuterBrackets = false; } } } // 括弧が閉じていないなら不正な式 if (nest != 0) throw new FormulaParseException(exp); // 括弧がないならそのまま返す if (!hasMostOuterBrackets) return exp; // 最初と最後の括弧を取り除く String ret = exp.substring(1, exp.length() - 1); // まだ括弧があるならもう一度処理 if (ret.charAt(0) == OPERATOR.LEFT_BRACKET.cVal && ret.charAt(ret.length() - 1) == OPERATOR.RIGHT_BRACKET.cVal) { return delMostOuterBrackets(ret); } return ret; } /** * 検索 * * @param s 検索対象 * @param p 正規表現 * @return 検索結果 */ private static Optional<String> matchFirst(String s, Pattern p) { Matcher m = p.matcher(s); return m.find() ? Optional.of(m.group(0)) : Optional.empty(); } /** * 演算子 */ private enum OPERATOR { PLUS("+", '+'), MINUS("-", '-'), MULTIPLY("*", '*'), DIVIDE("/", '/'), LEFT_BRACKET("(", '('), RIGHT_BRACKET(")", ')'), NO_OPE(" ", ' '); public String val; public char cVal; private final static Map<String, OPERATOR> m = new HashMap<>(); static { for (OPERATOR o : OPERATOR.values()) { m.put(o.val, o); } } private OPERATOR(String val, char cVal) { this.val = val; this.cVal = cVal; } public static OPERATOR getEnum(String val) { return m.getOrDefault(val, NO_OPE); } } }FormulaParseException.javapublic class FormulaParseException extends Exception { public FormulaParseException(String msg) { super(msg); } }例外はそれっぽいのを適当に実装しました
パーサによる解析と、計算処理は分けずに一つのクラスにまとめています
正負記号と加減演算子の区別が面倒なので0埋めしてます
必要に応じて括弧も追加しているのもポイントです解析もそれなりにコストがかかるので、本来のアプリは事前チェックもそれなりに手厚くしています
あと、Math関数や変数も処理できるようにしているのですが、思い出してコードを書くのがしんどいので省きました
matchFirst()
メソッドはその名残ですね
他にも便利なユーティリティーを実装して色々やっていました変数は適当に置換すればいいだけです
Math関数についてはヒントだけ言うと、↑のコードだとMath関数は項として扱われます
なので下記のコードあたりに、Math関数か判別してMath関数ならそれを処理するメソッドを呼び出すようにすればいいです
return new BigDecimal(exp).toPlainString();
Math関数を処理するメソッドは、
delMostOuterBrackets()
やformat()
みたいに地道に文字をチェックして処理すればいいです
つまり、記事に書いたコードを応用すればいけるので必要なら自力で作ってみてください終わりに
とりあえず実装して動かしてみたら要件を満たしてくれたのでそこで終了です
件数が何千万から億までいくと怪しいですが、そこまではいかないそうなので大丈夫のようですテストは山ほど書きましたが、思い出して移植するのがしんどいので省きます
まあ式の想定結果をチェックするだけなのでJUnitも不要なぐらいですが僕はCS専攻ではなく独学で学んでいる口なので、実務でこの手の設計実装をじっくり考えるのは結構ためになりました
またアルゴリズムとデータ構造の知識がないと太刀打ちできないような案件がでてきてくれることを祈って記事は終わりです
ノシ
- 投稿日:2019-11-24T18:56:14+09:00
Java11インストール後にEclipseが起動しなくなる現象
はじめに
職場でJava11をインストールしたところ、Eclipseが起動しなくなりました。
当初は原因が全く分からずに苦戦したので、記録として記事を書くことにしました。状況
当初の状態
以下のように古いJavaであったため、空いた時間でJavaのバージョンを上げることにしました。
なお、EclipseはPleiadesの日本語化版を使っています。
- OS:Windows 10 Pro
- Java:Oracle Java 8
- Eclipse:Eclipse 4.6(Neon)
Javaのバージョンアップ後の状態
無償で使えて簡単にインストールできる「Amazon Corretto」をインストールしました。
- OS:Windows 10 Pro
- Java:Amazon Corretto 11
- Eclipse:Eclipse 4.6(Neon)
発生した不具合
Eclipseのスプラッシュ画面が表示された後、
An error has occurred. See the log file ...
というダイアログが出てしまい、Eclipseが起動しませんでした。対応策
- 以下の記事を参考にして、最新版のEclipseをインストールしたところ、無事にEclipseが起動しました。
- ちなみに、今回インストールしたEclipseのバージョンは「リリース 2019-09」の最新版です。
まとめ
- Java 7からJava 8にバージョンアップした時には、Eclipseが起動しないという症状はなかったと思うので、今回はかなり驚きました。
- 当初はAmazon Correttoに不具合があるのでは...と思いましたが、色々調べていくうちにJava10以降で同様の症状が出ていると分かり、最終的に比較的簡単な方法で解決できて良かったです。
- バージョン管理に載せていないちょっとしたプログラムが幾つかありましたが、既存のワークスペースからコードを簡単にインポートできたので助かりました。
- 投稿日:2019-11-24T18:14:35+09:00
列挙型と switch 文の進化形!?Java で代数的データ型とパターンマッチングを実現してみる
Mikatus Advent Calendar 2019 8日目の記事。
Reactive in practice: A complete guide to event-driven systems development in Java を読んでいたら、The algebraic data type pattern(代数的データ型パターン)なんてものが出てきて面白かったのでメモっとく。
例題:株取引システムにおける注文種別を表現する
Reactive in practice には株取引システム Stock Trader における注文の種類を表現する方法が例題として掲載されている。株を取引したことがある人は知っていると思うのだが、株の注文には下記のような種類がある。
- 成行 (market)
- 指値 (limit)
- 逆指値 (stop limit)
これらの注文を表現するために、Reactive in practice で代数的データ型パターンと呼んでいるデザインパターンが使われている。なぜ列挙型 (Enum) ではないのか?その謎を紐解いていこう。
実験用の Gradle プロジェクトを生成する
Lombok を使いたかったりもするので JShell ではなく Gradle プロジェクトで実験する。下記のコマンドで Gradle プロジェクトを生成しよう。
$ mkdir stock-trader $ cd stock-trader $ gradle init \ --type java-library \ --dsl groovy \ --test-framework junit \ --project-name stock-trader \ --package com.example株取引の注文種別を列挙型として実装する
まずは成行注文と指値注文のみを列挙型として実装してみよう。指値注文は指値 (limit price) を保持する必要があるので、列挙型に
limitPrice
フィールドを持たせる。ゲッターとなるgetLimitPrice
メソッドとセッターとなるsetLimitPrice
メソッドも定義する。注文が実行可能かを判定するisExecutable
抽象メソッドを定義して、各列挙値でオーバーライドしている。src/main/java/com/example/order/OrderType.javapackage com.example.order; public enum OrderType { MARKET { @Override public boolean isExecutable(int currentPrice) { return true; } }, LIMIT { @Override public boolean isExecutable(int currentPrice) { return currentPrice <= getLimitPrice(); } }; private int limitPrice; public int getLimitPrice() { return limitPrice; } public void setLimitPrice(int limitPrice) { this.limitPrice = limitPrice; } public abstract boolean isExecutable(int currentPrice); }この
OrderType
列挙型を使用するテストを書いてみよう。src/test/java/com/example/order/OrderTypeTest.javapackage com.example.order; import org.junit.Test; import static org.junit.Assert.*; public class OrderTypeTest { @Test public void testIsExecutableOnMarketOrder() { OrderType orderType = OrderType.MARKET; assertTrue(orderType.isExecutable(100)); } @Test public void testIsExecutableOnLimitOrder() { OrderType orderType = OrderType.LIMIT; orderType.setLimitPrice(100); assertTrue(orderType.isExecutable(100)); } }実際のところ株取引の注文種別を列挙型で実装することには下記のような問題がある。
- 成行注文で
setLimitPrice
メソッドによって指値の指定ができる- 指値注文で指値なしの状態が実現できる
これらの問題の解決策は様々あるかもしれないが、今回は代数的データ型パターンを用いて解決してみようと思う。
シールドクラスパターンを用いて株取引の注文種別を代数的データ型として実装する
シールドクラスパターン (Sealed Class Pattern) として Maybe in Java という記事が Reactive in practice で参照されている。そのシールドクラスパターンで成行注文と指値注文のみを代数的データ型として実装してみよう。
src/main/java/com/example/order/OrderType.javapackage com.example.order; public abstract class OrderType { private OrderType() { } public static final class Market extends OrderType { @Override public boolean isExecutable(int currentPrice) { return true; } } public static final class Limit extends OrderType { private int limitPrice; public Limit(int limitPrice) { this.limitPrice = limitPrice; } public int getLimitPrice() { return limitPrice; } @Override public boolean isExecutable(int currentPrice) { return currentPrice <= limitPrice; } } public abstract boolean isExecutable(int currentPrice); }ここで
OrderType
クラスについていくつか補足しておこう。OrderType
を抽象クラスとして宣言し、プライベートコンストラクタを定義することで、OrderType
を継承できるクラスをOrderType
の内部クラスに限定している。また、Market
クラスとLimit
クラスをfinal
クラスとして宣言することで、Market
クラスとLimit
クラスを継承できないようにしている。これシールドクラスパターンと呼ばれる理由だと思う。この
OrderType
クラスを使用するテストを書いてみよう。src/test/java/com/example/order/OrderTypeTest.javapackage com.example.order; import org.junit.Test; import static org.junit.Assert.*; public class OrderTypeTest { @Test public void testIsExecutableOnMarketOrder() { OrderType orderType = new OrderType.Market(); assertTrue(orderType.isExecutable(100)); } @Test public void testIsExecutableOnLimitOrder() { OrderType orderType = new OrderType.Limit(100); assertTrue(orderType.isExecutable(100)); } }株取引の注文種別を列挙型で実装することで生じる下記の問題は、代数的データ型で実装することで解決できた。
- 成行注文で
setLimitPrice
メソッドによって指値の指定ができる- 指値注文で指値なしの状態が実現できる
その一方、注文が実行できるかどうかの判定はそもそも注文種別の責務なのかという問題がある。これは、列挙型と代数的データ型でそれぞれ例示した実装に共通する問題になる。注文が実行できるかどうかの判定かどうかを問わず、
OrderType
クラスの外で、下記のように条件分岐を実現したいことがあるのではないだろうか?@Test public void testSwitchOnLimitOrder() { OrderType orderType = OrderType.LIMIT; orderType.setLimitPrice(100); int currentPrice = 100; boolean result = false; switch (orderType) { case MARKET: result = true; break; case LIMIT: result = currentPrice <= orderType.getLimitPrice(); break; default: throw new UnsupportedOperationException("Unsupported order type"); } assertTrue(result); }@Test public void testIfOnLimitOrder() { OrderType orderType = new OrderType.Limit(100); int currentPrice = 100; boolean result = false; if (orderType instanceof OrderType.Market) { result = true; } else if (orderType instanceof OrderType.Limit) { result = currentPrice <= orderType.getLimitPrice(); } else { throw new UnsupportedOperationException("Unsupported order type"); } assertTrue(result); }このような条件分岐には共通して下記のような問題がある。
OrderType
クラスに新しい型を追加した場合、すべてのOrderType
についての条件分岐を探し出して修正する必要があるこの問題を解決するために、Visitor パターンを用いたパターンマッチングを導入してみよう。
Visitor パターンを用いたパターンマッチングを実装する
便宜的にパターンマッチングと呼んでいるが、Visitor パターンを適用するだけなので Scala のようなパターンマッチングを期待しないでほしい。また、
isExecutable
メソッドはコードを理解しやすくするために削除することにする。src/test/java/com/example/order/OrderTypeTest.javapackage com.example.order; public abstract class OrderType { private OrderType() { } public static final class Market extends OrderType { @Override public <T> T match(CaseBlock<T> caseBlock) { return caseBlock._case(this); } } public static final class Limit extends OrderType { private int limitPrice; public Limit(int limitPrice) { this.limitPrice = limitPrice; } public int getLimitPrice() { return limitPrice; } @Override public <T> T match(CaseBlock<T> caseBlock) { return caseBlock._case(this); } } public interface CaseBlock<T> { T _case(Market market); T _case(Limit limit); } public abstract <T> T match(CaseBlock<T> caseBlock); }
OrderType
抽象クラスにmatch
抽象メソッドを宣言し、それぞれの型で実装している。そのmatch
メソッドはCaseBlock
インターフェイスを実装したクラスのインスタンスを受け取り、その_case
メソッドを呼び出している。Visitor パターンを改めて説明する必要はないと思うが、ここの_case
メソッドがオーバーロードされていることによって、それぞれの型によって処理が分岐することになる。蛇足だが、_case
という名前にしているのは、case
が予約語で使えないからだ。この
OrderType
クラスを使用するテストを書いてみよう。使い方を見た方が理解しやすいと思う。src/test/java/com/example/order/OrderTypeTest.javapackage com.example.order; import org.junit.Test; import static org.junit.Assert.*; public class OrderTypeTest { @Test public void testPatternMatchingOnLimitOrder() { OrderType orderType = new OrderType.Limit(100); int currentPrice = 100; boolean result = orderType.match(new OrderType.CaseBlock<>() { @Override public Boolean _case(OrderType.Market market) { return true; } @Override public Boolean _case(OrderType.Limit limit) { return currentPrice <= limit.getLimitPrice(); } }); assertTrue(result); } }これで下記の問題は解決される。
OrderType
クラスに新しい型を追加した場合、すべてのOrderType
についての条件分岐を探し出して修正する必要がある
OrderType
クラスに新しい型を追加した場合、もちろんコードの修正はしなければならない。しかしながら、条件分岐を上記のようなパターンマッチングで記述している限りは、コンパイル時にエラーが発生するようになるので、修正箇所の特定が容易になり、修正漏れを防ぐことができる。Lombok で代数的データ型を洗練する
さて、代数的データ型パターンは便利そうだということがわかった。しかしながら、いかんせん定義するのが面倒でコードの見通しも良くない。その点を少し改善するために、ここでは Lombok を導入してみよう。
build.gradle
ファイルに下記の行を追加する。--- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ plugins { // Apply the java-library plugin to add support for Java Library id 'java-library' + id "io.freefair.lombok" version "4.1.5" } repositories {Lombok を使用して書くとこうなる。
src/test/java/com/example/order/OrderTypeTest.javapackage com.example.order; import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.Value; @NoArgsConstructor(access = AccessLevel.PRIVATE) public abstract class OrderType { @Value @EqualsAndHashCode(callSuper = false) public static class Market extends OrderType { @Override public <T> T match(CaseBlock<T> caseBlock) { return caseBlock._case(this); } } @Value @EqualsAndHashCode(callSuper = false) public static class Limit extends OrderType { int limitPrice; @Override public <T> T match(CaseBlock<T> caseBlock) { return caseBlock._case(this); } } public interface CaseBlock<T> { T _case(Market market); T _case(Limit limit); } public abstract <T> T match(CaseBlock<T> caseBlock); }プライベートコンストラクタの定義を
NoArgsConstructor
アノテーションで実現する。取引種別は値オブジェクトを生成するクラスとしてValue
アノテーションを付与する。これでMarket
クラスもLimit
クラスもfinal
クラスになる。Limit
クラスのフィールドの宣言を簡潔にしているが、フィールドはすべてprivate final
になるし、コンストラクターとゲッターも自動的に生成される。なおEqualsAndHashCode
アノテーションは、EqualsAndHashCode
アノテーションを明示しなさいという警告が発生するので付与している。スタティックコンストラクターを用意する
ここからは好みの問題だと思うけど、スタティックコンストラクターを用意するとよりそれっぽくなる。
src/test/java/com/example/order/OrderTypeTest.javapackage com.example.order; import com.google.errorprone.annotations.Var; import lombok.*; @NoArgsConstructor(access = AccessLevel.PRIVATE) public abstract class OrderType { @Value @EqualsAndHashCode(callSuper = false) @AllArgsConstructor(access = AccessLevel.PROTECTED) public static class Market extends OrderType { @Override public <T> T match(CaseBlock<T> caseBlock) { return caseBlock._case(this); } } public static OrderType market() { return new Market(); } @Value @EqualsAndHashCode(callSuper = false) @AllArgsConstructor(access = AccessLevel.PROTECTED) public static class Limit extends OrderType { int limitPrice; @Override public <T> T match(CaseBlock<T> caseBlock) { return caseBlock._case(this); } } public static OrderType limit(int limitPrice) { return new Limit(limitPrice); } public interface CaseBlock<T> { T _case(Market market); T _case(Limit limit); } public abstract <T> T match(CaseBlock<T> caseBlock); }
OrderType.market
メソッドとOrderType.limit
メソッドのようにスタティックコンストラクターを用意する。その上でMarket
クラスとLimit
クラスのコンストラクターをAllArgsConstructor
アノテーションでプロテクティッドコンストラクターにしている。テストも微修正する。
src/test/java/com/example/order/OrderTypeTest.javapackage com.example.order; import org.junit.Test; import static org.junit.Assert.*; public class OrderTypeTest { @Test public void testPatternMatchingOnLimitOrder() { OrderType orderType = OrderType.limit(100); int currentPrice = 100; boolean result = orderType.match(new OrderType.CaseBlock<>() { @Override public Boolean _case(OrderType.Market market) { return true; } @Override public Boolean _case(OrderType.Limit limit) { return currentPrice <= limit.getLimitPrice(); } }); assertTrue(result); } }ここまでやるとアノテーションでごちゃごちゃするのでお好みでどうぞ。
株取引の注文種別を代数的データ型として Scala で実装する
これが Scala だと簡単に実現できるということで Scala の REPL でやってみる。
scala> :paste // Entering paste mode (ctrl-D to finish) sealed trait OrderType case object Market extends OrderType case class Limit(limitPrice: Int) extends OrderType // Exiting paste mode, now interpreting. defined trait OrderType defined object Market defined class Limit scala> :paste // Entering paste mode (ctrl-D to finish) val orderType: OrderType = Limit(100) val currentPrice = 100 orderType match { case Market => true case Limit(limitPrice) => currentPrice <= limitPrice } // Exiting paste mode, now interpreting. orderType: OrderType = Limit(100) currentPrice: Int = 100 res3: Boolean = trueScala だと簡潔に書ける。Kotlin も簡潔に書けそうだけど試してはいない。
今回は代数的データ型パターンなるものを説明してみた。なんだかんだ Java って表現力豊かだ。また、Java が進化する方向性として代数的データ型パターンを実装しやすくなるような文法が導入されていきそうなので、今後の Java からは目が離せなさそうである。とはいえ、Scala の表現力はやはり魅力的なので、Java も Scala も楽しんでいきたいね。
参考文献
Reactive in practice: A complete guide to event-driven systems development in Java
- 投稿日:2019-11-24T18:13:46+09:00
Javaプログラミング (クラスとインスタンス、メインメソッド)
メインメソッド
Javaは必ずクラスで構成されます。クラスのなかで処理はメソッドに書かれます。メソッドのなかで、おおもとの操作や処理はメインメソッドというメソッドに書かれます。
メインメソッドの書き方
メインメソッドは次のように書きます。クラス名は命名ルール通りにTestクラスとしましょう。
public class Test(){ public void main(String[] args){ /* *メインメソッドの処理の中身 *おおもとの操作はここに書かれる。 */ } }ここで
public static void main(String[] args)という書き方は覚えてください。
ちなみに、publicとstaticの間のstaticはstatic句といい、メソッドや変数に付けられます。詳しい意味はここでは触れません。意味があってこのようなルールになったらしいのですが、そこまで追求しなくてもいいと思います。
ただ、普通のメソッドの書き方になっていることは理解してください。クラスを使う
では、このTestクラスのメインメソッドでCalculateクラスのmultipleIntegerNumberメソッドを使ってみましょう。
このメソッドはpublic class Calculate { public int multipleIntegerNumber(int num){ num = 3*num; return num; } }です。
インスタンス化
クラスを使うにはまず、クラスのインスタンス化をします。
Calculate cal1 = new Calculate();このcal1はインスタンスと呼ばれます。
メソッドの呼び出し
次にメソッドを呼び出します。
cal1.multipleIntegerNumber(3);こうすることで、メソッドは戻り値の9を結果として返してくれます。
- 投稿日:2019-11-24T17:03:51+09:00
ページ番号のロジックと参考コード(java)
■目次
1、初めに
2、ページ番号ロジック
3、コード例■初めに
検索サイトを作った時にページ番号の表示ロジックに手間取ったので載せておこうと
思いました。参考にしていただけたら幸いです。
(一例なので改善点・よりよいコードがあれば教えてください)■べーじ番号のロジック
ページが1の時は5までの数字を出し、間に「・・・」を表示させ最後の番号を表示させる
ページ番号が5以上の時に始めのページ・前2つのページ番号・後ろ2つ・最後の番号を表示
ページが(最後のページ ー 3)の場合は初めのページ・最後までのページと前のページを表示
■コード例(jsp)
aタグのhrefにはリンク抜き状態のコードです。
変数名や定数名などの命名はセンスがないので良い名前があれば教えてください。<% //ページ数・現在ページの変数宣言 int currentPage; int lastPageNum; //変数代入 currentPage = 5; lastPageNum = 9; //定数宣言 final int FIRST_PAGE = 1; final int FIRST_HALF_CHECK = 5; final int LAST_HALF_CHECK = 4; final int BEFORE_AND_AFTER = 2; %> <section> <div class="pageLeft"> <%if(currentPage != FIRST_PAGE){ %> <a href="">前のページへ</a> <%} %> </div> <div class="pageCenter"> <%if(currentPage >= FIRST_HALF_CHECK){ %> <a href="">1</a> … <%} %> <%if(currentPage < FIRST_HALF_CHECK){ %> <%for(int i = 1; i <= FIRST_HALF_CHECK; i++){ %> <%if(i <= lastPageNum){ %> //aタグを入れるか入れないかの分岐(現在ページにaタグは入れない) <%if(i == currentPage){ %> <span><%=i %></span> <%}else{ %> <a href=""><%=i %></a> <%} %> <%} %> <%} %> <%}else if(lastPageNum - currentPage < LAST_HALF_CHECK){ %> <%for(int i = lastPageNum - LAST_HALF_CHECK; i <= lastPageNum; i++){ %> <%if(i > 0){ %> //aタグを入れるか入れないかの分岐(現在ページにaタグは入れない) <%if(i == currentPage){ %> <span><%=i %></span> <%}else{ %> <a href=""><%=i %></a> <%} %> <%} %> <%} %> <%}else{ %> <%for(int i = currentPage - BEFORE_AND_AFTER; i <= currentPage + BEFORE_AND_AFTER; i++){ %> //aタグを入れるか入れないかの分岐(現在ページにaタグは入れない) <%if(i == currentPage){ %> <span><%=i %></span> <%}else{ %> <a href=""><%=i %></a> <%} %> <%} %> <%} %> <%if(lastPageNum - currentPage >= LAST_HALF_CHECK){ %> …<a href=""><%=lastPageNum %></a> <%} %> </div> <div class="pageRight"> <%if(currentPage != lastPageNum){ %> <a href="">次のページへ</a> <%} %> </div> </section>■まとめ
検索サイトでページナンバーロジックに1回詰まったので書いてみました。
もっといい方法や改善点等あると思いますので、その際は教えていただけると幸いです。
- 投稿日:2019-11-24T15:25:20+09:00
DefaultGroovyMethodsとStream APIの相互変換まとめ
GroovyのDefaultGroovyMethodsとJavaのStream APIとの相互変換
仕事でGroovyのDefaultGroovyMethodsをJavaのStream APIを使った形に書き直すという作業を行ったので、備忘録も兼ねてまとめます。
サンプルコードの動作はそれぞれ以下のバージョンで確認しています。
Java: 11
Groovy: 2.5.8DefaultGroovyMethod ⇔ Stream API
each ⇔ forEach
Groovydef list = ["Java", "Groovy", "Scala"] list.each { println it } ---結果--- Java Groovy ScalaJavaList<String> list = List.of("Java", "Groovy", "Scala"); list.forEach(System.out::println); ---結果--- Java Groovy Scalacollect ⇔ map + collect
Groovydef lowerCases = ["java", "groovy", "scala"] def upperCases = lowerCases.collect { it.toUpperCase() } println upperCases ---結果--- [JAVA, GROOVY, SCALA]JavaList<String> lowerCases = List.of("java", "groovy", "scala"); List<String> upperCases = lowerCases.stream().map(language -> language.toUpperCase()).collect(Collectors.toList()); System.out.println(upperCases); ---結果--- [JAVA, GROOVY, SCALA]findAll ⇔ filter + collect
Groovydef numbers = [1, 2, 3, 4, 5] def odds = numbers.findAll { it % 2 != 0 } println odds ---結果--- [1, 3, 5]JavaList<Integer> numbers = List.of(1, 2, 3, 4, 5); List<Integer> odds = numbers.stream().filter(number -> number % 2 != 0).collect(Collectors.toList()); System.out.println(odds); ---結果--- [1, 3, 5]参考資料
公式リファレンス
List
https://docs.oracle.com/javase/jp/8/docs/api/java/util/List.html
Stream
https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html
Collectors
https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Collectors.htmlDefaultGroovyMethods
http://docs.groovy-lang.org/latest/html/api/org/codehaus/groovy/runtime/DefaultGroovyMethods.htmlQiita記事
Groovyよく使いそうなメソッド(List編)
https://qiita.com/kimromi/items/e326bf9c24220df97ecf
- 投稿日:2019-11-24T15:25:20+09:00
GroovyのDefaultGroovyMethodsとJavaのStream APIの相互変換まとめ
仕事でGroovyのDefaultGroovyMethodsをJavaのStream APIを使った形に書き直すという作業を行ったので、備忘録も兼ねてまとめます。
サンプルコードの動作はそれぞれ以下のバージョンで確認しています。
Java: 11
Groovy: 2.5.8DefaultGroovyMethod ⇔ Stream API
each ⇔ forEach
Groovydef list = ["Java", "Groovy", "Scala"] list.each { println it } ---結果--- Java Groovy ScalaJavaList<String> list = List.of("Java", "Groovy", "Scala"); list.forEach(System.out::println); ---結果--- Java Groovy Scalacollect ⇔ map + collect
Groovydef lowerCases = ["java", "groovy", "scala"] def upperCases = lowerCases.collect { it.toUpperCase() } println upperCases ---結果--- [JAVA, GROOVY, SCALA]JavaList<String> lowerCases = List.of("java", "groovy", "scala"); List<String> upperCases = lowerCases.stream().map(language -> language.toUpperCase()).collect(Collectors.toList()); System.out.println(upperCases); ---結果--- [JAVA, GROOVY, SCALA]findAll ⇔ filter + collect
Groovydef numbers = [1, 2, 3, 4, 5] def odds = numbers.findAll { it % 2 != 0 } println odds ---結果--- [1, 3, 5]JavaList<Integer> numbers = List.of(1, 2, 3, 4, 5); List<Integer> odds = numbers.stream().filter(number -> number % 2 != 0).collect(Collectors.toList()); System.out.println(odds); ---結果--- [1, 3, 5]参考資料
公式リファレンス
List
https://docs.oracle.com/javase/jp/8/docs/api/java/util/List.html
Stream
https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html
Collectors
https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Collectors.htmlDefaultGroovyMethods
http://docs.groovy-lang.org/latest/html/api/org/codehaus/groovy/runtime/DefaultGroovyMethods.htmlQiita記事
Groovyよく使いそうなメソッド(List編)
https://qiita.com/kimromi/items/e326bf9c24220df97ecf
- 投稿日:2019-11-24T13:54:09+09:00
Caused by: java.lang.NoSuchMethodError: 'boolean javax.servlet.ServletContext.setInitParameter(java.lang.String, java.lang.String)'
logCaused by: java.lang.NoSuchMethodError: 'boolean javax.servlet.ServletContext.setInitParameter(java.lang.String, java.lang.String)'Cause
The error indicates multiple version servlet-api jar in class path.
javax.servlet:servlet-api
(< 3.0)javax.servlet:javax.servlet-api
(>= 3.0)Resolution
Remove old servlet-api dependency.
Basically, old class depends on old servlet api will work with new api.build.gradleconfigurations.all { exclude module: "servlet-api" // Old pre-3.0 servlet API artifact }
- 投稿日:2019-11-24T10:50:46+09:00
Selenium × Java
SeleniumをJavaで使ってみた
Seleniumとは
※以下抜粋
Seleniumは、Webアプリケーションをテストするためのポータブルフレームワークです。
Seleniumは、テストスクリプト言語を学ぶ必要なく機能テストを作成するための再生ツールを提供します。要はwebアプリケーションを自動で実行できたり、HTMLを解析(Webスクレイピング)するためのライブラリ。python、node.js、Java、PHPなど多言語でライブラリが用意されており、簡単に実装が可能。
経緯
会社の勤務システムがwebアプリケーションで動いており、PC起動時にブラウザ起動から提出まで自動化したいというのが最終目標。本記事はSelenium導入、「Chrome起動→Google検索を開く」までとする。
アーキテクト
言語 Java( ver.11 ) build Maven ブラウザ Google Chrome IDE IntelliJ 手順
前提
java x Mavenのアプリケーションの環境構築済みであること。準備
1. Seleniumのライブラリをpomに依存ライブラリを追加、読み込み。
<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.12.0</version> </dependency>2. Chromeで実行するため、Chromeのdriverをダウンロードする。これにより、Chromeによる実行が可能となる。別ブラウザでやりたい場合は、各ブラウザのdriverをダウンロードすればOK。
chromedriverのダウンロード
http://chromedriver.chromium.org/downloadsサンプルコードの実行
「Chrome起動→Google検索を開く」
import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; public class MainApplication { public static void main(String[] args){ final String PATH = "※chromeDriverのpath"; System.setProperty("webdriver.chrome.driver", PATH); WebDriver driver = new ChromeDriver(); final String URL = "http://www.google.com"; // URL遷移 driver.get(URL); } }
- 投稿日:2019-11-24T10:44:15+09:00
JJUG CCC 2019 Fall 資料まとめました
タイトルのとおり昨日開催された「JJUG CCC 2019 Fall」の資料をまとめました。
資料が見つからなかった場合のリンクは、部屋番号のハッシュタグといった関連する内容のツイッターになっています。
ーーー
10:00〜10:45
A+B
試して学ぼう、Java EE アプリケーションをOpenShift(Minishift)でデプロイ!C+D
Head toward Java 13 and Java 14E+F
All people are VIP~Disney哲学から考えるDiversityG+H
Gradle を完全に理解した人が、何も分からなくなるための第一歩I
JavaとGraalVMとPicocliで、ときめくネイティブコマンドラインアプリを作ろうL
Coding That Sparks Joy with QuarkusM後半
バーコードリーダから飛ばされたJANコードを元にJavaからのAPI呼び出しで商品情報を取得してFirebaseに登録&ロケットチャットに通知した話11:00〜11:45
A+B
Javaで学ぶオブジェクト指向プログラミングの基礎知識C+D
入門 例外E+F
Rethinking Runtime Efficiency with GraalVMI
Jakarta EE: today and tomorrowM
Spring Cloud AWSをクラウドエンジニアがいじってみた12:00〜12:45
13:30〜14:15
A+B
最新:Azure Spring Cloud のご紹介C+D
Reliability Engineering Behind The Most Trusted Kafka Platform at LINEE+F
開け!ドメイン駆動設計の扉G+H
Mavenの真実とウソL
Modern Identity Management (in the Era of Serverless and Microservices)14:30〜15:15
C+D
CLRのValueTypeを起点にProject Valhallaを覗いてみる
M
JavaオンプレシステムをAKS + Quarkusに移行した話N
元インフラエンジニアがSpringBoot2を用いてFW開発を学んでいる話15:45〜16:30
A+B前半
Java における乱数 (生成器) とのつき合い方A+B後半
Use Kotlin scripts and custom DSL in your web appsE+F
AngularとSpring Bootで作るSPA + RESTful Web Serviceアプリケーション - 開発ツールやプロジェクト構成も含めて45分で丸わかり -G+H
Javaの起動速度といかに戦うかI
How to adapt MicroProfile API for general Web applicationsM
Where is my cache? Architectural patterns for caching microservices by example16:45〜17:30
A+B前半
新卒3年目が立ち向かった、お名前.comでの超巨大レガシーシステム脱却の事例A+B後半
オレ流OpenJDK「の」開発環境C+D
JavaでTracing17:45〜18:30
A+B
分散トレーシングの技術選定・OSS 貢献と Stackdriver Tracer での性能可視化・改善C+D
Swagger ではない OpenAPI Specification 3.0 による API サーバー開発G+H
DIコンテナ入門I
JVMs in Containers: Best Practicesーーー
JJUGスタッフ/発表者/スポンサーの皆様ありがとうございました。
- 投稿日:2019-11-24T10:18:39+09:00
SpringBoot×OpenAPI入門 〜Generation gapパターンで作るOpenAPI〜
背景
Javaのコミュニティイベント「JJUG CCC 2019 Fall」に参加。
そこで聞いた「Swagger ではない OpenAPI Specification 3.0 による API サーバー開発」の登壇内容に触発されて超簡単なOpenAPIを作った話。(浅いです)今回のゴール
SpringBootを使ってOpenAPIを書く
OpenAPIを使った開発フロー(ざっくり)
ルール:Generation gapパターン → 自動生成したクラスファイルは編集しない。
1. API定義ファイルを用意
OAS(OpenAPISpecification)にあるサンプルを使用
https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml
2. 定義よりコード自動生成
Gradleのプラグイン【openapi-generator-gradle-plugin】を使用。
APIの定義ファイルよりコードを自動生成してくれるGradleプラグイン。build.gradleplugins { id "org.openapi.generator" version "4.2.1" }ポイント1:コンパイル時の設定
自動生成したクラスファイルをコンパイル時に含めるように設定
build.gradlecompileJava.dependsOn tasks.openApiGenerate sourceSets.main.java.srcDir "${openApiGenerate.outputDir.get()}/src/main/java" sourceSets.main.resources.srcDirポイント2:OpenapiGeneratorの設定
openapi-generator-gradle-pluginの実行例をほぼほぼコピーでOK。
ただ、インターフェイスを作成するようにコンフィグファイルを操作。build.gradle//https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-gradle-plugin openApiGenerate { generatorName = "spring" //コンフィグ設定 configFile = "$rootDir/specs/config.json".toString() //サンプルAPI指定 inputSpec = "$rootDir/specs/petstore-v3.0.yaml".toString() outputDir = "$buildDir/generated".toString() apiPackage = "org.openapi.example.api" invokerPackage = "org.openapi.example.invoker" modelPackage = "org.openapi.example.model" configOptions = [ dateLibrary: "java8" ] systemProperties = [ modelDocs: 'false' ] }config.json{ "interfaceOnly": true }クラスの自動生成はGradleのタスク【openApiGenerate】でOK。
タスク実行すると、以下のJavaファイルが自動生成される
3. API実装
自動生成されたインターフェイスからimplementして、コントローラーを生成
PetsApiController.java@RestController public class PetsApiController implements PetsApi{ @Override public ResponseEntity<List<Pet>> listPets(@Valid Integer limit) { System.out.println("Here list pet"); return new ResponseEntity<>(HttpStatus.OK); } }完成!!
完成したコード
https://github.com/harutotanabe09/SpringBootOpenAPIBegin
おまけ:OpenAPIのドキュメントツールを使ってみた
OpenAPIのドキュメントツール(redoc)を使って、ドキュメントを自動生成。
※ 前提:Dockerが入っていることdocker run -it --rm -p 80:80 \ -v $(pwd)/specs/petstore-v3.0.yaml:/usr/share/nginx/html/swagger.yaml \ redocly/redoc出力イメージ:定義ファイルを元にAPIのパラメータや戻り値を見やすい画面で出力
参考資料
Swagger ではない OpenAPI Specification 3.0 による API サーバー開発
https://www.slideshare.net/techblogyahoo/swagger-openapi-specification-30-api
- 投稿日:2019-11-24T06:32:26+09:00
Gradle5 で Lombok が使えない
macOS x IDEA x Gradle5 x Spring-boot2 で Lombok を使おうとして、コンパイルはできるがビルドができない。
アノテーションの設定や Lombok Plugin の設定は済んでいて、@Slf4 を記述し、log.debug を記載してエディタ上でエラーは発生しないけど、ビルドすると以下エラーが発生する。
/src/to/path/TestController.java:14: エラー: シンボルを見つけられません log.info("start"); ^ シンボル: 変数 log 場所: クラス TestController以下の設定を build.gradle に追加したら解決
compileOnly group: 'org.projectlombok', name: 'lombok', version: "${lombokVersion}" annotationProcessor group: 'org.projectlombok', name: 'lombok', version: "${lombokVersion}"※「providedCompile」で読み込もうとしていたのが誤りのようでした。
- 投稿日:2019-11-24T05:44:39+09:00
IntelliJでJarファイルをワンクリックでpluginにビルドする
マイクラでPluginの開発をしている時に、すこしでも時間短縮をしたかったので、ワンクリックで使用したいサーバーのpluginsへぶっこむ方法を書きます。
環境
- Windows 10 Pro
- IntelliJ IDEA 2019.2.2
素晴らしい前置き今日もいい天気なのに、どうして僕(私)はいちいちビルドしてからビルドしたjarファイルをいちいちpluginsファイルに置いてreloadしないといけないんだろう...と思ったことはありませんか?かなりの開発者が思ったことがあるはずです。
さて、そんなあなたに朗報です。右上の緑の右三角を押すだけで、そのプロセスをすべて行って、コンソールでreloadとうつだけであなたの最高で素晴らしいプラグインが試せます!では参りましょう。
Build Artifactを作る
基本設定
1... Fileを押す
2... Project Structureを押す
3... Project Settingsを見る
4... Artifactsを押す
5... 上のプラスボタンを押す
6... JAR ▶を押す
7... From modules with dependenciesを押す
8... 画像と特に違いがなければ、OKを押す19... Output Layoutの下辺りにあるプラスボタンを押す
10... Fileを押す
11...プロジェクトへのパス\src\main\resources\plugin.yml
を指定する
12... OKを押す
13... Output Directoryに、サーバーのpluginフォルダを設定する
14... OKを押すBuild Artifactを試してみる
1... 上のメニューのBuildを押す
2... Build Artifactsを押す
3... 先程作ったArtifactを押す
4... Buildを押すこれで、pluginsファイルにプラグインの名前のjarファイルが生成されているはずです!やったあ!
あとは、サーバーで実行してテストしてみてください。ボタンを押して指定したディレクトリへビルドする
1... 右上のSample Buildを押す
2... Edit Configurationsを押す
3... 左上のプラスボタンを押す
4... JAR Applicationを押す
5-1... Nameを変える(任意)
5-2... Path to JARを、サーバーのjarのパスにする
5-3... Working Directoryを、サーバーのルート(一番浅いフォルダ)にする
5-4... JREをDefaultにする1
5-5... Search sources using module's classpathをにする
6... 先ほど作ったArtifactを設定する(チェックを付ける)
7... OKを押すあとは、右上のドロップダウンからいま作ったJAR Applicationを選択して、Runボタンを押せばサーバーが起動してビルドしたものが自動で読み込まれているはずです!
それでは皆様、よき開発ライフを。
参考
場合によっては設定が変わることもあるかもしれませんので、環境によって合わせてください ↩
- 投稿日:2019-11-24T01:23:35+09:00
Javaの入門書を一通り読んだので何か作ってみる
javaの入門書を一通り読んだので...
プログラミングは作ってなんぼ!!!
ということで何か簡単なゲームでも作ろうかと思い考えたのはずばり『じゃんけん!!!』(しょぼい)
これは自分のプログラミングロード第一歩ということでゲームの原点といってもいい『じゃんけん』!!!でちょうどいいじゃんと思い即座にコードを書いてみました!!!!!
class Janken{ public static void main(String[] args){ janken(); } //メイン public static void janken(){ int loop = 0; //あいこの場合loop==0、勝利か負けの場合loop=1, //※loop変数であいこの場合でもじゃんけんを繰り返す while(loop==0){ String hand[] = {"グー","チョキ","パー"}; //出し手変数 System.out.println("最初はグー!じゃんけん・・・"); System.out.println("グー、チョキ、パー:0,1,2"); int myHand = new java.util.Scanner(System.in).nextInt(); //自分の出し手 int youHand = new java.util.Random().nextInt(3); //相手の出し手 System.out.println("自分:"+hand[myHand]+",相手:"+hand[youHand]); if(myHand == youHand){ System.out.println("あいこです( ゚Д゚)"); } else if((myHand==0 && youHand==1) || (myHand==1 && youHand==2) || (myHand==2 && youHand==0)){ System.out.println("勝利です)^o^("); loop += 1; } else{ System.out.println("負けです( ;∀;)"); loop += 1; } } } //じゃんけんメソッド }
まだまだ稚拙だけどこれから頑張ります!!!
- 投稿日:2019-11-24T01:14:55+09:00
Javaにおけるスレッド実装方法の比較とラムダ式的記述方法
はじめに
急遽、Javaでマルチスレッドプログラムを作れという職場からの
無茶苦茶な要望に答えるべく速攻で勉強したことをまとめておく。
※ Javaの経験日数はまだ3日程度なのでミスしてたらご指摘ください。結論:とりあえずサクッと起動したい場合
サブスレッド起動までのパスが少ない&サブスレッドをインスタンスとして保持しないなら、ラムダ式を組み合わせて
ThreadStartTemplate.javanew Thread( () -> {サブスレッドで実行したいメソッド or 処理} ).start()でよさそう。便利っすねぇー。
※僕の中では、ラムダ式はローカルな無名クラスと理解しています。実行環境
自前でEclipseのインストールとかは後回しにしてとりあえず、文法を確かめるためにpaiza.ioを使いました。
サブスレッドの実装方法
以下の2パターンでスレッドを実装できるみたい。
1. Rnnableインタフェースを使用する。
2. Threadクラスを継承する。1. Runnableインタフェースを使う
JavaにはRunnableインタフェースなるものがあるらしく、run()をオーバーライドすることで、スレッド時に実行される処理が実装できるようだ。
使い方は以下の通り。
1. Runnableインタフェースを実装したクラスのインスタンスを生成
2. コンストラクタにRunnnableオブジェクトを渡して、Thread型のオブジェクトを生成
3. Threadクラスのstart()メソッドをコールしてサブスレッドを起動この通りに従って書いたサンプルコードがRunnableSample.javaです。
RunnableSample.javaimport java.util.*; public class Main { private static class RunnableSample implements Runnable{ private String thread_no; RunnableSample(String str){ this.thread_no = str; } public void run(){ System.out.println("RunnableThread Starting No."+thread_no); } } public static void main(String[] args) throws Exception { String str1 = "1"; String str2 = "2"; RunnableSample runner1 = new RunnableSample(str1); // 1. RunnableSample runner2 = new RunnableSample(str2); // 1. Thread thread1 = new Thread(runner1); // 2. Thread thread2 = new Thread(runner2); // 2. thread1.start(); // 3. thread2.start(); // 3. Thread.sleep(200); System.out.println("MainThread End"); } }実行結果RunnableThread Starting No.1 RunnableThread Starting No.2 MainThread EndMainクラスのローカルクラスとしてRunnableSampleクラスを定義しています。
MainスレッドからRunnableSampleクラスのオブジェクトを生成し、2つのサブスレッドとして実行します。RunnableThread Starting No.1
RunnableThread Starting No.2
は逆順で出力される可能性がある。200msのスリープを挟んでいるのでMainThread Endはたいてい最後に出力されるでしょう。2. Threadクラスを継承する。
次にThreadクラスを継承してサブスレッドの処理を実装する方法について書く。
使い方は次の通り。コードはThreadSample.java。
- Threadクラスのrun()をオーバーライドしたクラスのインスタンスを生成
- Threadクラスのstart()メソッドをコールしてサブスレッドを起動
ThreadSample.javaimport java.util.*; public class Main { private static class ThreadSample extends Thread{ private String thread_no; ThreadSample(String str){ this.thread_no = str; } public void run(){ System.out.println("RunnableThread Starting No."+thread_no); } } public static void main(String[] args) throws Exception { String str1 = "1"; String str2 = "2"; ThreadSample thread1 = new ThreadSample(str1); // 1. ThreadSample thread2 = new ThreadSample(str2); // 1. thread1.start(); // 2. thread2.start(); // 2. Thread.sleep(200); System.out.println("MainThread End"); } }実行結果RunnableThread Starting No.2 RunnableThread Starting No.1 MainThread End実行結果は同じになる(今回はThread1とThread2の出力の順番が逆転した)。
結局「Runnableインタフェースの実装」と「Threadクラスの継承」どちらがいいのか?
基本的にはRunnableインタフェースを使った方がメリットが多そう。
- Javaは多重継承を許していないため、Threadクラスを継承すると他のクラスが継承できなくなってしまう。Runnableインタフェースを実装したクラスであれば他のクラスを継承することができる。
- Threadクラスが抱えるオーバーヘッドをそのまま受け継がなくてすむ。
- Threadクラスを継承した方がコードはスッキリしそう。
Runnableインタフェースでもすっきりと書けたら完璧やん。ということでやってみる。
Runnableインタフェースをラムダ式で記述を簡単にする。
Java8のラムダ式を理解するを参考にラムダ式でコードを簡潔にしてみる。
LambdaThreadSample.javaimport java.util.*; public class Main { static private void subthread_run(String thread_no){ System.out.println("RunnableThread Starting No."+thread_no); } public static void main(String[] args) throws Exception { String str1 = "1"; String str2 = "2"; new Thread( () -> {subthread_run(str1);} ).start(); new Thread( () -> {subthread_run(str2);} ).start(); Thread.sleep(200); System.out.println("MainThread End"); } }実行結果RunnableThread Starting No.2 RunnableThread Starting No.1 MainThread End詳しい記述方法はJava8のラムダ式を理解するを参考にしていただくとするが、
難解に簡単に説明すると、先のRunnableSampleクラスをsubthread_runメソッドをもつ無名クラスとし、Threadクラスのオブジェクトをnewしてstartしている。
ラムダ式を用いることで随分とプログラムがすっきりとし可読性もぐっと上がった。Threadをインスタンスとして管理する必要がないならこの書き方が良さそうだ。次はSynchronizedについてまとめたい。参考文献
世界で戦うプログラミング力を鍛える150問 Chapter.16:スレッドとロック