- 投稿日:2019-03-05T22:18:12+09:00
Javaで素数判定プログラムを書きました
Javaで素数判定
昨日から本格的にJavaの講義を受けていて、do-while文まで学習したあたりで
素数判定プログラムを書いてみることになったので、その備忘録です。Sosu.javapackage sample; import java.util.Scanner; public class Sosu { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int num; boolean b = true; while (true) { System.out.println("素数判定"); System.out.print("2以上の整数を入力してください:"); num = sc.nextInt(); if (num < 2) { System.out.println("2未満の整数です。"); } else { break; } } if (num == 2) { System.out.println(num + "は素数です。"); } else { for (int i = 2; i < num; i++) { if (num % i == 0) { System.out.println(num + "は素数ではありません。"); b = false; break; } } if (b) { System.out.println(num + "は素数です。"); } } } }内容
- while文で入力内容が2未満であるものを弾いて再入力させる。
- while文をbreakで脱出し、入力が2以上であるものをif文で判定。
- 入力が2のときは素数。
- 入力が2より大きいときは、2以上num未満の数で順に割っていってどこかで割り切れたら素数ではない。
- 割り切れなかったものは素数。最後の判定はbooleanで判定。
コメント
正直もっといいやり方はありそうなので、この先学んでいってもし思いついたら訂正します。
また、現在の形のままここをこうした方がいい、などアドバイスがあれば教えてもらえると嬉しいです。
- 投稿日:2019-03-05T22:00:59+09:00
JSONArray、JSONObjectの判定
JSONArray、JSONObjectの判定
JSONファイルの中身が配列なのか単体なのか?ってこと
というわけで、パッとおもいつきでかいたのがこんなかんじ。
1文字目が [ だったらとりあえずJSONArrayだなって判断する。
その文字列がパーサ通るかは別としてね。if(jsonStr.charAt(0) == '[') { //JSONArray } else if(jsonStr.charAt(0) == '{') { //JSONObject }もっとスマートなやり方ないかなーって探してたらこういうのがあったよ
Object object = new JSONTokener(data).nextValue(); if (object instanceof JSONArray) { //JSONArray } else if (object instanceof JSONObject) { //JSONObject }こっちのほうががいいかんじ
おわり
- 投稿日:2019-03-05T20:34:30+09:00
JavaFX8 ファイル書き込み(TextField)
1. 仕様
文字を入力しボタンを押すことで,入力した文字をファイルに書き込む.
TextFieldを用いる.2. ファイル構造
Eclipseでプロジェクトを作成する.
write ・・・・・・・・・・・・・・・・・(1)
├ test.txt・・・・・・・・・・・・・・(2)
└ src ・・・・・・・・・・・・・・・・(3)
└ pkg ・・・・・・・・・・・・・・(4)
├ FileWrite.java ・・・・・・・(5)
├ Main.java ・・・・・・・・・(6)
├ MainController.java ・・・・ (7)
└ screen.fxml ・・・・・・・・(8)(1) 作成するプロジェクト
(2) 書き込み対象となるテキストファイル(ファイルが存在しない場合は実行時に作成され,存在する場合は追記する)
(3) プロジェクト作成時に勝手に作られる,ソースファイル用ディレクトリ
(4) 作成するパッケージ
(5) ソースファイル(次章に記述),ファイル書き込み
(6) ソースファイル(次章に記述),画面起動
(7) ソースファイル(次章に記述),画面のコントローラー
(8) ソースファイル(次章に記述,SceneBuilderで作成)3. ソースファイル
3.1. FileWrite.java
FileWrite.javapackage pkg; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class FileWrite { public void write(String text) throws IOException { try { //どちらかを記述,どちらかをコメントアウト----------------------------------- //FileWriter file = new FileWriter("test.txt");//上書き FileWriter file = new FileWriter("test.txt", true);//追記 //--------------------------------------------------------------------- // PrintWriterクラスのオブジェクトを生成する PrintWriter pw = new PrintWriter(new BufferedWriter(file)); //ファイルに書き込む pw.println(text); pw.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } }3.2. Main.java
Main.javapackage pkg; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage primaryStage) { try { //FXMLからのシーングラフの読み込み FXMLLoader loader = new FXMLLoader(getClass().getResource("screen.fxml")); Parent root = loader.load(); //シーングラフのルートノードを設定したシーンの作成 Scene scene = new Scene(root, 600, 400); //ステージへのシーンの設定 primaryStage.setScene(scene); primaryStage.setTitle("no title"); primaryStage.show(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { launch(args); } }3.3. MainController.java
MainController.javapackage pkg; import java.io.IOException; import java.net.URL; import java.util.ResourceBundle; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.TextField; import javafx.stage.Modality; public class MainController { @FXML private ResourceBundle resources; @FXML private URL location; @FXML private TextField textField; @FXML private Button writeButton; @FXML void OnclickedWriteButton(ActionEvent event) throws IOException { String text = textField.getText(); if (!text.isEmpty()) { FileWrite a = new FileWrite(); a.write(text); textField.setText(""); } else { Alert alert = new Alert(AlertType.INFORMATION); //情報というアラート種を設定 alert.initModality(Modality.WINDOW_MODAL); //操作が終わるまで一部を除く他ウィンドウを操作できない alert.setTitle("警告"); //タイトルを設定 alert.setContentText("テキストが入力されていません."); //内容を設定 alert.showAndWait(); //アラートを表示して閉じるまで実行を待つ } } @FXML void initialize() { assert textField != null : "fx:id=\"textField\" was not injected: check your FXML file 'screen.fxml'."; assert writeButton != null : "fx:id=\"writeButton\" was not injected: check your FXML file 'screen.fxml'."; textField.setText(""); } }3.4. screen.fxml
screen.fxml<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.TextField?> <?import javafx.scene.layout.Pane?> <Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pkg.MainController"> <children> <TextField fx:id="textField" layoutX="155.0" layoutY="187.0" /> <Button fx:id="writeButton" layoutX="364.0" layoutY="187.0" mnemonicParsing="false" onAction="#OnclickedWriteButton" prefHeight="27.0" prefWidth="80.0" text="書き込み" /> </children> </Pane>
- 投稿日:2019-03-05T14:31:39+09:00
デザインパターン ~Strategy~
1. はじめに
GoFのデザインパターンにおける、Strategyパターンについてまとめます。
2. Strategyパターンとは
- Strategyという英単語は、戦略という意味になります。プログラミングの場合はアルゴリズムと考えていいみたいです。
- どんなプログラムも問題を解くために書かれています。問題を解くために特定のアルゴリズムが実装されています。Strategyパターンは、アルゴリズムを実装した部分をごっそりと交換できる方式です。
- GoFのデザインパターンでは、振る舞いに関するデザインパターンに分類されます。
3. サンプルクラス図
4. サンプルコード
4-1. Handクラス
じゃんけんの手を表すクラスです。
Hand.javapublic class Hand { public static final int HANDVALUE_GUU = 0; public static final int HANDVALUE_CHO = 1; public static final int HANDVALUE_PAA = 2; public static final Hand[] hand = { new Hand(HANDVALUE_GUU), new Hand(HANDVALUE_CHO), new Hand(HANDVALUE_PAA), }; private int handvalue; private Hand(int handvalue) { this.handvalue = handvalue; } public static Hand getHand(int handvalue) { return hand[handvalue]; } public boolean isStrongerThan(Hand h) { // thisがhより強いときtrue return fight(h) == 1; } private int fight(Hand h) { if (this == h) { // 引き分け return 0; } else if ((this.handvalue + 1) % 3 == h.handvalue) { // thisの勝ち return 1; } else { // hの勝ち return -1; } } }4-2. Playerクラス
じゃんけんを行うプレイヤーを表すクラスです。
Player.javapublic class Player { private String name; private Strategy strategy; private int wincount; private int losecount; private int gamecount; public Player(String name, Strategy strategy) { this.name = name; this.strategy = strategy; } public String getName() { return name; } public Hand nextHand() { return strategy.nextHand(); } public void win() { wincount++; gamecount++; } public void lose() { losecount++; gamecount++; } public void even() { gamecount++; } public String toString() { return "[" + name + "] " + gamecount + " gemes, " + wincount + " win, " + losecount + " lose"; } }4-3. Strategyインターフェース
じゃんけんの「戦略」を表すインターフェースです。
Strategy.javapublic interface Strategy { public abstract Hand nextHand(); }4-4. RandomStrategyクラス
ランダムに手を出す戦略を表すクラスです。
RandomStrategy.javaimport java.util.Random; public class RandomStrategy implements Strategy { public Hand nextHand() { Random random = new Random(); return Hand.getHand(random.nextInt(3)); } }4-5. GuuStrategyクラス
グーのみの手を出す戦略を表すクラスです。
GuuStrategy.javapublic class GuuStrategy implements Strategy { public Hand nextHand() { return Hand.getHand(Hand.HANDVALUE_GUU); } }4-6. Mainクラス
メイン処理を行うクラスです。
Main.javapublic class Main { public static void main(String[] args) { Player player1 = new Player("Taro", new RandomStrategy()); Player player2 = new Player("Hana", new GuuStrategy()); for (int i = 0; i < 5; i++) { Hand nextHand1 = player1.nextHand(); Hand nextHand2 = player2.nextHand(); if (nextHand1.isStrongerThan(nextHand2)) { System.out.println("Winner:" + player1.getName()); player1.win(); player2.lose(); } else if (nextHand2.isStrongerThan(nextHand1)) { System.out.println("Winner:" + player2.getName()); player1.lose(); player2.win(); } else { System.out.println("Even..."); player1.even(); player2.even(); } } System.out.println("----- Total result -----"); System.out.println(player1.toString()); System.out.println(player2.toString()); } }4-7. 実行結果
Winner:Taro Winner:Hana Even... Winner:Hana Even... ----- Total result ----- [Taro] 5 gemes, 1 win, 2 lose [Hana] 5 gemes, 2 win, 1 lose5. メリット
Strategyパターンでは、アルゴリズムの部分をほかの部分と意識的に分離します。そしてアルゴリズムとのインターフェースの部分だけを規定し、委譲によってアルゴリズムを利用します。
これは、プログラムを複雑にしているように見えますが、そうではありません。例えば、アルゴリズムを改良してもっと高速にしたい場合、Strategyパターンを使っていれば、Strategy役のインターフェースを変更しないようにして、アルゴリズムをだけを追加、修正すればいいのです。委譲というゆるやかな結びつきを使っているのため、アルゴリズムを用意に切り替えることができます。
また、ゲームプログラム等では、ユーザーの選択に合わせて難易度を切り替えたりすることにも使えます。6. 参考
- 投稿日:2019-03-05T13:20:25+09:00
MicronautでServerless Function
Micronaut Severless Function
Micronautには、Serverless Functionを作成するための機能があります。
Springなどとの他のフレームワークに比べての利点は、Micronautはコンパイル時に依存関係を解決する仕組みや、メモリのフットプリントの軽さが売りのようです。
作成したFunctionは、AWS LambdaやOpenFaaSなどにデプロイすることができるようです。
このMicronautのServerless Functionを作成する機能を、簡単に試してみたいと思います。
環境
環境は、こちらです。
$ mn -V | Micronaut Version: 1.0.4 | JVM Version: 1.8.0_191プロジェクト作成
--profile
をfunction-aws
として、プロジェクトを作成します。$ mn create-app --profile function-aws --build maven hello-function $ cd hello-function指定できる
function
のProfileは、function-aws
のみのようなので…。$ mn list-profiles | Available Profiles -------------------- cli The cli profile federation The federation profile function-aws The function profile for AWS Lambda kafka The Kafka messaging profile profile A profile for creating new Micronaut profiles service The service profile単に
function
とか書いたりすると、「そんなProfileはない」と怒られます。$ mn create-app --profile function --build maven hello-function | Error Profile [function] is designed only for extension and not direct usageできあがったプロジェクトには、テストコードなども含まれています。
$ find -type f ./mvnw.cmd ./.mvn/jvm.config ./.mvn/wrapper/maven-wrapper.properties ./.mvn/wrapper/MavenWrapperDownloader.java ./.mvn/wrapper/maven-wrapper.jar ./.gitignore ./mvnw ./pom.xml ./micronaut-cli.yml ./src/main/java/hello/function/HelloFunctionFunction.java ./src/main/java/hello/function/Application.java ./src/main/resources/application.yml ./src/main/resources/logback.xml ./src/test/java/hello/function/HelloFunctionFunctionTest.java ./src/test/java/hello/function/HelloFunctionClient.javaスケルトンのfunctionは、こんな感じです。
src/main/java/hello/function/HelloFunctionFunction.java
package hello.function; import io.micronaut.function.FunctionBean; import java.util.function.Supplier; @FunctionBean("hello-function") public class HelloFunctionFunction implements Supplier<String> { @Override public String get() { return "hello-function"; } }functionを定義する方法は、
FunctionBean
として作成する方法と、Factory
を使って作成する方法があるようです。今回は、
FunctionBean
を使った方法で実装されているというわけですね。この場合、関数インターフェースを実装する必要があるようですが、利用できるインターフェースは
Supplier
、Consumer
、BiConsumer
、Function
、BiFunction
のようです。
main
メソッドを持ったクラスは、こういう感じで。src/main/java/hello/function/Application.java
package hello.function; import io.micronaut.runtime.Micronaut; public class Application { public static void main(String[] args) { Micronaut.run(Application.class); } }実行するfunctionは、設定ファイルで指定されています。これは、
FunctionBean
の名前ですね。src/main/resources/application.yml
micronaut: function: name: hello-functionドキュメントを見ると、複数のfunctionを含む場合は明示的に設定する必要があるみたいです。
CLIとして実行してみる
パッケージングして実行してみましょう。
結果が返ってきました。
$ java -jar target/hello-function-0.1.jar 12:56:07.817 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [function] hello-function引数を受け取ったり、他のBeanをDIしたりしてみる
ちょっと構成を変えて、引数を受け取ったり他のBeanをDIしたりしてみましょう。
引数のメッセージを加工するだけの、Beanを作成します。
src/main/java/hello/function/MessageService.java
package hello.function; import java.time.LocalDateTime; import javax.inject.Singleton; @Singleton public class MessageService { public String wrap(String message) { return String.format("[%s] ★%s★", LocalDateTime.now(), message); } }もとのfunctionは、このBeanをDIしつつ、実行時に引数を受け取るようにしてみましょう。関数インターフェースは、
Function
を実装しました。src/main/java/hello/function/HelloFunctionFunction.java
package hello.function; import io.micronaut.function.FunctionBean; import java.util.function.Function; import java.util.function.Supplier; import javax.inject.Inject; @FunctionBean("hello-function") public class HelloFunctionFunction implements Function<HelloFunctionFunction.Request, HelloFunctionFunction.Response> { @Inject MessageService messageService; @Override public Response apply(Request request) { String replyMessage = messageService.wrap(request.getMessage()); return new Response(replyMessage); } public static class Request { String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } public static class Response { String message; public Response(String message) { this.message = message; } public String getMessage() { return message; } } }コードが変わってしまったので、今回はテストをスキップしてパッケージング。
$ ./mvnw package -DskipTests=true実行。
$ echo '{"message": "こんにちは、世界"}' | java -jar target/hello-function-0.1.jar 13:00:23.558 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [function] {"message":"[2019-03-05T13:00:24.185] ★こんにちは、世界★"}引数を受け取りつつ、他のBeanをDIして実行できました。
functionをWebアプリケーションとしても実行できるようですが、今回はパスします。
実行環境へのデプロイは、そのうち…。
- 投稿日:2019-03-05T11:30:57+09:00
OpenJDK 11 以降で JavaMail が使えない場合の対処法
概要
OracleJDK 8 から OpenJDK 11 に変更したところ、JavaMail で以下の例外が発生するようになりメール送信が一切できなくなりました。
java.lang.NoClassDefFoundError: javax/activation/DataSource (略) Caused by: java.lang.ClassNotFoundException: javax.activation.DataSource本記事では OpenJDK 11 以降で JavaMail を使うための方法についてご紹介します。
例外発生の原因
JavaMail では内部で
java.activation
パッケージを使用していますが、OpenJDK 11 以降では JEP 320: Remove the Java EE and CORBA Modules によって以下のパッケージが削除されています。
- java.xml.ws
- java.xml.bind
- java.activation
- java.xml.ws.annotation
- java.corba
- java.transaction
java.activation
パッケージが削除されたことにより JavaMail で参照するクラスが見つからなくなり概要で示した例外が発生しています。対処法
java.activation
パッケージとして JavaBeans Activation Framework を使用することで JavaMail が使えるようになります。Maven<!-- https://mvnrepository.com/artifact/com.sun.activation/javax.activation --> <dependency> <groupId>com.sun.activation</groupId> <artifactId>javax.activation</artifactId> <version>1.2.0</version> </dependency>Gradle// https://mvnrepository.com/artifact/com.sun.activation/javax.activation compile group: 'com.sun.activation', name: 'javax.activation', version: '1.2.0'
- 投稿日:2019-03-05T11:11:30+09:00
軽量JREでUnsupportedCharsetExceptionが発生した時の対処法
概要
配布用の軽量JREの作り方の記事でも紹介していますが、Java 9 以降では必要最低限のモジュールで構成された軽量JREを作ることができます。
JDKに付属の
jdeps
コマンドで軽量JREに含めるべき依存モジュールを知ることはできますが、作成した軽量JREでアプリを実行してみると以下の例外に遭遇することがあります。UnsupportedCharsetException: EUC-JPこれはサポート外の文字コードを指定した場合に発生する例外となります。軽量JREではない通常のJDKでは発生していない例外ですが、
jdeps
コマンドで示された必要最低限のモジュールは含んでいるはずですが例外が発生してしまっています。
つまり、jdeps
コマンドだけでは軽量JREに含めるべきモジュールが不十分ということになります。本記事では軽量JREを使う際に上記の例外を回避する方法についてご紹介します。
なぜ例外が発生するのか
EUC-JP
などの拡張文字コードはjava.base
モジュールに含まれていないためです。ちなみに、JDK9 の
jdk.charsets
モジュールの Javadoc には以下のような記載があります。java.base (主に2バイト文字とIBM文字セット)にないcharsetsを提供します。
つまり、日本語の文字コードセットは
jdk.charsets
モジュールを追加で指定する必要があるということです。
Java のソースコード内で以下のようにCharset.forName
メソッドなどを使用して文字コードを指定していると、jdeps
コマンドではjdk.charsets
モジュールは表示されないため、軽量JREを作る際は注意が必要となります。Charset.forName("EUC-JP")対処法
jlink
コマンドで軽量JREを作る際にjdk.charsets
モジュールを含めることで拡張文字コードが扱えるようになります。jlink --compress=2 --module-path ../jmods --add-modules java.base,jdk.charsets --output jre
- 投稿日:2019-03-05T09:20:23+09:00
springで@Import対象は@Configuration扱いになる
springで
@Import
されるjava configクラスを作成していた。このとき、その設定クラスは@Configuration
を付けなくても@Import
すればクラス内の@Bean
が登録されるのが、なんか不思議だったのでその辺を勉強するべくソースコードを見てみた。pom.xml<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent>ソースを追ってみると、ApplicationContextの細かいところは省くが、
@Import
の処理をしているのはこの辺らしい。以下のメソッドではimport候補クラスのコレクションを渡されて、それを一つずつ処理している。ConfigurationClassParserpackage org.springframework.context.annotation; class ConfigurationClassParser { private void processImports(/*...(略)...*/, Collection<SourceClass> importCandidates, /*...(略)...*/) { // ...(略) for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // ...(略) else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // ...(略) else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass));このとき、条件付きimportをする
@ImportSelector
と@ImportBeanDefinitionRegistrar
が付与されていれば、それ専用の処理が行われる。しかし、それらアノテーションではない場合、コード内のコメントにあるように「import候補クラスがImportSelectorないしImportBeanDefinitionRegistrarでは無い場合は@Configuration
扱いで処理する」となる。なので、
@Import
対象クラスは@Configuration
と見なされる、と考えても基本的には良さそうである。もちろん細かくは色々違いはあるだろうけど。
- 投稿日:2019-03-05T07:40:58+09:00
SimpleDateFormatでフォーマットする際のタイムゾーンの扱いでつまった
JmeterでAPIからのResponseを処理するときに詰まったのでメモ。
Fri Apr 4 00:00:00 UTC+0900 1902このような日付の文字列をDateにフォーマットするには
new SimpleDateFormat("EEE MMM dd HH:mm:ss zZ yyyy", Locale.ENGLISH);これです。
z タイムゾーン 一般的なタイムゾーン Pacific Standard Time; PST; GMT-08:00 Z タイムゾーン RFC 822タイムゾーン -0800 と書いていましたが、組み合わせが思いつかずでした。
全体のコードは下記になります。import java.text.SimpleDateFormat; String date = "Fri Apr 4 00:00:00 UTC+0900 1902"; // Original format to convert from SimpleDateFormat formatFrom = new SimpleDateFormat("EEE MMM dd HH:mm:ss zZ yyyy", Locale.ENGLISH); // Target format to convert to SimpleDateFormat formatTo = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss zZ", Locale.ENGLISH); // Parse original string, using original format Date formatDate = formatFrom.parse(date); // Convert to a target format String newDate = formatTo.format(formatDate); System.out.println(newDate);