- 投稿日:2019-06-27T22:47:49+09:00
IntelliJのコンソールが文字化けする
自宅WindowsのIntelliJで発生。
会社でも同じようにIntelliJを使っているのだがそちらはちゃんと変換される。Hoge.javapublic class Hoge { public static void main(String[] args) { System.out.println("あああ"); } }実行結果あああ プロセスは終了コード 0 で完了しましたちゃんと動く方の情報
変換できている方の設定関連を調べてみた。
バージョン情報
IntelliJ設定
カスタムVM
.IdeaIC2019.1/config/idea64.exe.vmoptions# Custom VM options (Generated by Pleiades Installer) # See https://pleiades.io/pages/pleiades_jetbrains_manual.html #-Xms128m #-Xmx750m -XX:ReservedCodeCacheSize=240m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -Djdk.http.auth.tunneling.disabledSchemes="" -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Xverify:none -javaagent:C:\Users\*******\.IdeaIC2019.1\config\jp.sourceforge.mergedoc.pleiades\pleiades.jar -Dconsole.encoding=UTF-8 -Dfile.encoding=UTF-8設定ファイルらしきモノ
JetBrains\IntelliJ IDEA Community Edition 2019.1.2\bin\idea64.exe.vmoptions
bin\idea64.exe.vmoptions-Xms128m -Xmx750m -XX:ReservedCodeCacheSize=240m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -Djdk.http.auth.tunneling.disabledSchemes="" -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow調べる
ユーザフォルダに何やら怪しそうなやつがいる。
C:\Users\*****\.IdeaIC2019.1\config
キャッシュの削除も検討する。
Qiita - IntelliJ Ideaのキャッシュを消す方法試した結果
ここまでやってもだめ。
なんで???同じじゃん。ビルド方法が違った
ふとコンソールに目をやると
> Task :compileJava > Task :processResources NO-SOURCE > Task :classes …こんなのが出力されていた。
(これgradleプロジェクトで作ったなあ…。会社のは普通のプロジェクトだったなあ…。)ググってみたら以下のサイトにあたった。
Gradleで文字エンコーディングを指定する方法build.gradleに以下を追記。
build.gradleplugins { id 'java' } group 'com_tutorial' version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { // https://mvnrepository.com/artifact/org.projectlombok/lombok compile group: 'org.projectlombok', name: 'lombok', version: '1.18.8' testCompile group: 'junit', name: 'junit', version: '4.12' } // 以下の行を記載 tasks.withType(AbstractCompile)*.options*.encoding = tasks.withType(GroovyCompile)*.groovyOptions*.encoding = 'UTF-8'ビンゴ。変換された!
実行結果あああ プロセスは終了コード 0 で完了しました参考になりそうなリンク集
結局全部違ったけど。IntelliJ IDEA でコンソールのTomcatログが文字化けしたときに設定した3点
https://qiita.com/qurage/items/cb57bb9c942e55ed06d1intellij-ideaのコンソールでの文字化けの原因について
https://ja.stackoverflow.com/questions/42721/intellij-idea%E3%81%AE%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%81%A7%E3%81%AE%E6%96%87%E5%AD%97%E5%8C%96%E3%81%91%E3%81%AE%E5%8E%9F%E5%9B%A0%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6公式ヘルプ
https://pleiades.io/help/idea/configuring-individual-file-encoding.html
- 投稿日:2019-06-27T21:42:06+09:00
Windowsでwarファイルを手軽に扱う
エクスプローラーでwarファイルをダブルクリックしてzipファイルのように中身を見ることができるようにするには、コマンドプロンプトを管理者権限で開いて以下のコマンドを実行します。
assoc .war=CompressedFolderjarファイルをエクスプローラーで開けるようにするコチラの記事を参考にさせていただきました→ https://qiita.com/kitoo/items/6761fd74e8347962171a
- 投稿日:2019-06-27T19:09:35+09:00
【Java】Collectors.collectingAndThenを使う
Collectors.collectingAndThenとは
Collect
後の値を処理した値を返すCollector
です。使い方
以下のような状況があったとします。
リストに一時的に格納→処理を呼び出すList<Integer> mappedList = /* Stream */ ./* mapなど、stream処理 */ .collect(Collectors.toList()); return hogeFunc(mappedList);このような処理は、
Collectors.collectingAndThen
を使うことで以下のように書けます。Collectors.collectingAndThenを使った形return /* Stream */ ./* mapなど、stream処理 */ .collect( Collectors.collectingAndThen( Collectors.toList(), mappedList -> hogeFunc(mappedList) // mappedListを使った処理 ) );何が嬉しいのか?
一時変数が減る
Collect結果を一時変数に一々格納する必要が無いので、一時変数が減らせます。
一時変数を置くことは可読性やコード品質の低下に繋がるので、それが減るのは嬉しいです。直渡しより可読性が上がる
一番初めに挙げたコード例は、以下のように書くこともできます。
直で関数に引数を渡す形式で書いた場合return hogeFunc( /* Stream */ ./* mapなど、stream処理 */ .collect(Collectors.toList()) );しかし、これでは特に関数がネストしていく場合の可読性が低い1です。
また、これだとデバッガで引っ掛けて中身を読めないという欠点が有ります。まとめ
Collectors.collectingAndThen
、使っていきましょう。
この場面に関しては、パイプライン演算子が有れば
Collectors.collectingAndThen
を使う必要も無いんですが……。 ↩
- 投稿日:2019-06-27T18:02:49+09:00
Azure Cosmos DB に Java SDK からSelect*
Maven
<dependency> <groupId>com.microsoft.azure</groupId> <artifactId>azure-documentdb</artifactId> <version>2.4.0</version> </dependency>Java
import java.util.List; import com.google.gson.GsonBuilder; import com.google.gson.JsonParser; import com.microsoft.azure.documentdb.ConnectionPolicy; import com.microsoft.azure.documentdb.ConsistencyLevel; import com.microsoft.azure.documentdb.Document; import com.microsoft.azure.documentdb.DocumentClient; import com.microsoft.azure.documentdb.FeedOptions; public class HelloDocumentDb002QueryDocument { static String DATABASE_ID = "youdatabase"; static String COLLECTION_ID = "yourcontainer"; public static void main(String[] args) throws Exception { FeedOptions queryOptions = new FeedOptions(); queryOptions.setEnableCrossPartitionQuery(true); String host = "yourhost"; // read only String key = "youkey-readonly"; DocumentClient client = new DocumentClient("https://" // + host // + ".documents.azure.com:443", key, // new ConnectionPolicy(), ConsistencyLevel.Session); String q = "SELECT * FROM c"; List<Document> results = client .queryDocuments("dbs/" + DATABASE_ID + "/colls/" + COLLECTION_ID, q, queryOptions).getQueryIterable() .toList(); for (Document doc : results) { System.err.println(doc); String json = doc.toString(); System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(new JsonParser().parse(json))); } client.close(); } }
- 投稿日:2019-06-27T17:57:30+09:00
Azure Cosmos DB に Java SDK からUpsert
Maven
<dependency> <groupId>com.microsoft.azure</groupId> <artifactId>azure-documentdb</artifactId> <version>2.4.0</version> </dependency>Java
import java.util.Date; import java.util.List; import com.google.gson.GsonBuilder; import com.google.gson.JsonParser; import com.microsoft.azure.documentdb.ConnectionPolicy; import com.microsoft.azure.documentdb.ConsistencyLevel; import com.microsoft.azure.documentdb.Document; import com.microsoft.azure.documentdb.DocumentClient; import com.microsoft.azure.documentdb.FeedOptions; public class HelloDocumentDb001UpsertDocument { static String DATABASE_ID = "sandbox1"; static String COLLECTION_ID = "container1"; public static void main(String[] args) throws Exception { // Azure Cosmos DB Libraries for Java // https://docs.microsoft.com/ja-jp/java/api/overview/azure/cosmosdb?view=azure-java-stable FeedOptions queryOptions = new FeedOptions(); queryOptions.setEnableCrossPartitionQuery(true); String host = "yourhost"; // Get key from Azure Web Console // read write key String key = "xxx"; DocumentClient client = new DocumentClient("https://" // + host // + ".documents.azure.com:443", key, // new ConnectionPolicy(), ConsistencyLevel.Eventual); // 適当なクラスを用意するとJSONに変換してくれる Doc d = new Doc("002", new Date(), "Hello", "Hello"); // Nameなのか、IDなのか、ドキュメントをみてもはっきりしない。 String collectionLink = String.format("/dbs/%s/colls/%s", DATABASE_ID, COLLECTION_ID); int response = client.upsertDocument(collectionLink, d, null, true).getStatusCode(); System.err.println(response); client.close(); } }
- 投稿日:2019-06-27T15:59:17+09:00
メモ:多次元配列への値の代入と表示、および拡張for文の練習
概要
今まで2次元以下の配列を取り扱う時には、何となく、表、あるいは行列のようなイメージで頭を整理していました。が、3次元になった途端に頭が完全にバグるという事態に発展。
そこで、【初心者からわかる】Javaの多次元配列の使い方と、多次元配列を拡張for文で展開を参考にさせてもらって、頭を整理し直しました。以下は整理に使用したプログラムになります。
Intdealing.javapublic class Intdealing{ public static void main(String[] args){ int[][] nums = new int[3][4]; System.out.printf("0階層の部屋数:%d\n",nums.length); System.out.printf("1階層の部屋数:%d×%d\n",nums.length,nums[0].length); int[][][] nums2 = new int[8][18][2]; System.out.printf("0階層の部屋数:%d\n",nums2.length); System.out.printf("1階層の部屋数%d×%d\n",nums2.length,nums2[0].length); System.out.printf("2階層の部屋数%d×%d×%d\n",nums2.length,nums2[0].length,nums2[0][0].length); //要素番号を使用して値を代入 for(int i=0; i<nums2.length; i++){ for(int j=0; j<nums2[i].length; j++){ nums2[i][j][0] = 2*i; nums2[i][j][1] = 2*j; } } //拡張for文を使用して値を表示 for(int[][] dimension1 : nums2){ for(int[] dimension2 : dimension1){ for(int dimension3 : dimension2){ System.out.println(dimension3); } } } } }余談
4時間ほどかけてあちこちのサイトを回って、なんとかプログラムを完成させました。今、私の頭の中では、多次元配列はアリの巣のように、あるいはマンションのように縦につながって積み重なる部屋の連なりとして捉えられています。
プログラムを勉強していく中で、今回のように躓くパターンが一番多いように感じられます。そもそもイメージとして捉えるのが間違っているのか、あるいは捉えるイメージが間違っているのかのはよくわかりませんが...
- 投稿日:2019-06-27T15:45:20+09:00
浮動小数点数の順序には二種類あるよ(-0.0, +0.0, NaN を比較すると?)
Scala 2.13 がリリースされましたね。
ここで、おもむろにSeq(3.0, 1.0, 2.0).sorted
などと実行すると、warning: object DeprecatedDoubleOrdering in object Ordering is deprecated (since 2.13.0): There are multiple ways to order Doubles (Ordering.Double.TotalOrdering, Ordering.Double.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it explicitly. See the documentation for details.
という警告が出るようになりました。
Double
の順序型クラスとしてTotalOrdering
IeeeOrdering
の二つが用意されているので明示的にどちらか一つを選びなさい、と言っていますね。
これは何でしょうか。なぜ順序に種類があるのでしょうか……?Java
まずは Java で
Double
の比較について確認してみましょう。jshell> 1.0 == 1.0 // true jshell> 1.0 != 1.0 // false jshell> Double.compare(1.0, 1.0) // 0 jshell> 2.0 > 1.0 // true jshell> Double.compare(2.0, 1.0) // 1 jshell> 1.0 > 2.0 // false jshell> Double.compare(1.0, 2.0) // -1それはそう、という感じです。ここに紛れはありません。
それではみんな大好き NaN (Not a Number) を比較してみます。
jshell> 0.0 / 0.0 // NaN jshell> Double.NaN == Double.NaN // false jshell> Double.NaN != Double.NaN // true jshell> Double.compare(Double.NaN, Double.NaN) // 0 jshell> Double.NaN > 0.0 // false jshell> Double.compare(Double.NaN, 0.0) // 1 jshell> 0.0 > Double.NaN // false jshell> Double.compare(0.0, Double.NaN) // -1おやおや。等号・不等号と
Double.compare
に意見の相違が見られますね?
等号・不等号はDouble.Nan
を食ったらそれはまともな数ではないので!=
以外ではfalse
を吐くと言っています。
対してDouble.compare
は、Double.Nan
とは0.0
よりも大きい数であると言っているのです。等号・不等号の扱いの方が自然な気もしますが、これが問題になることもあって、
static boolean check(double d1, double d2) { return (d1 <= d2) || (d2 <= d1 }という必ず
true
を返すことを期待したい関数が、jshell> check(1.0, 2.0) // true jshell> check(2.0, 1.0) // true jshell> check(Double.NaN, 1.0) // false
false
を返してしまうことがあるのですね。こうなるとアルゴリズムによっては、ソートが終わらなかったりします。これはいわゆる全順序律「任意の元 a, b について a ≦ b または b ≦ a」が成り立たない状況です。対して
Double.compare
は、static boolean checkCompare(double d1, double d2) { return (Double.compare(d1, d2) <= 0) || (Double.compare(d2, d1) <= 0 }jshell> checkCompare(1.0, 2.0) // true jshell> checkCompare(2.0, 1.0) // true jshell> checkCompare(Double.NaN, 1.0) // trueと
Double.NaN
を含めて全順序律が成り立っています。
※ ちなみに、これは IEEE 754 の totalOrder とは異なるようです。詳しくはコメント欄を読んでください。この違いはどこから来るのか
Double.compare
の実装を確認してみると、public static int compare(double d1, double d2) { if (d1 < d2) return -1; // Neither val is NaN, thisVal is smaller if (d1 > d2) return 1; // Neither val is NaN, thisVal is larger // Cannot use doubleToRawLongBits because of possibility of NaNs. long thisBits = Double.doubleToLongBits(d1 long anotherBits = Double.doubleToLongBits(d2 return (thisBits == anotherBits ? 0 : // Values are equal (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN) 1) // (0.0, -0.0) or (NaN, !NaN) }openjdk/jdk/src/java.base/share/classes/java/lang/Double.java
となっていて、なるほどなーというわけですが NaN 以外にも特別な場合がコメントされていますね。こちらも確認してみると、
jshell> -0.0 == +0.0 // true jshell> -0.0 < +0.0 // false jshell> Double.compare(-0.0, +0.0) // -1ということで、等号は
-0.0
と+0.0
が同じ数と言っていますが、Double.compare
は-0.0
より+0.0
の方が大きい数と言っています。
え、-0.0
と+0.0
を違う数として判定できるの?と驚くかもしれませんが、jshell> Long.toBinaryString(Double.doubleToLongBits(-0.0)) // 1000000000000000000000000000000000000000000000000000000000000000 jshell> Long.toBinaryString(Double.doubleToLongBits(+0.0)) // 0この通り
-0.0
と+0.0
は異なるビット表現がされています。他に
Double
の特殊な値として -∞ を表すDouble.NEGATIVE_INFINITY
と +∞ を表すDouble.POSITIVE_INFINITY
があるので合わせてまとめると、 Java の等号・不等号が定める順序では、-∞ < -1.0 < -0.0 == +0.0 < 1.0 < +∞
Double.compare
が定める順序では、-∞ < -1.0 < -0.0 < +0.0 < 1.0 < +∞ < NaNということになります。
Scala
さて、ここまで来れば Scala の方も理解できます。
TotalOrdering
IeeeOrdering
の実装を覗いてしまうと、trait TotalOrdering extends Ordering[Double] { def compare(x: Double, y: Double) = java.lang.Double.compare(x, y) } implicit object TotalOrdering extends TotalOrderingtrait IeeeOrdering extends Ordering[Double] { def compare(x: Double, y: Double) = java.lang.Double.compare(x, y) override def lteq(x: Double, y: Double): Boolean = x <= y override def gteq(x: Double, y: Double): Boolean = x >= y override def lt(x: Double, y: Double): Boolean = x < y override def gt(x: Double, y: Double): Boolean = x > y override def equiv(x: Double, y: Double): Boolean = x == y override def max[U <: Double](x: U, y: U): U = math.max(x, y).asInstanceOf[U] override def min[U <: Double](x: U, y: U): U = math.min(x, y).asInstanceOf[U] } implicit object IeeeOrdering extends IeeeOrderingscala/scala/src/library/scala/math/Ordering.scala
となっていて
TotalOrdering
はその名の通り Java のDouble.compare
の全順序に従うのですが、IeeeOrdering
はメソッドによって異なる順序に従うことが分かります。ややこしいですね。さて
IeeeOrdering
TotalOrdering
で挙動がどう異なるか確認してみましょう。scala> import Ordering.Double.TotalOrdering scala> val seq = Seq(+0.0, Double.PositiveInfinity, Double.NaN, -0.0, Double.NegativeInfinity) scala> seq.sorted res0: Seq[Double] = List(-Infinity, -0.0, 0.0, Infinity, NaN)scala> import Ordering.Double.IeeeOrdering scala> val seq = Seq(+0.0, Double.PositiveInfinity, Double.NaN, -0.0, Double.NegativeInfinity) scala> seq.sorted res0: Seq[Double] = List(-Infinity, -0.0, 0.0, Infinity, NaN)おや、同じ結果ですね。
これはSeq.sorted
が依存しているのはOrdering.compare
のためTotalOrdering
もIeeeOrdering
も同じ順序となるからです。ふーむ。他のメソッドはどうでしょうか。scala> import Ordering.Double.TotalOrdering scala> val seq = Seq(+0.0, Double.PositiveInfinity, Double.NaN, -0.0, Double.NegativeInfinity) scala> seq.min res0: Double = -Infinity scala> seq.max res1: Double = NaNscala> import Ordering.Double.IeeeOrdering scala> val seq = Seq(+0.0, Double.PositiveInfinity, Double.NaN, -0.0, Double.NegativeInfinity) scala> seq.min res0: Double = NaN scala> seq.max res1: Double = NaNおや、
min
が違う結果ですね。
これはSeq.min
が依存しているのはOrdering.min
のためTotalOrdering
とIeeeOrdering
は違う順序となるからです。なるほどなー。ちなみに
Double
の順序型クラスを明示しなかった場合、Scala 2.13 ではTotalOrdering
と同等のものが参照されますが、Scala 2.13 より前のバージョンで参照されるのはIeeeOrdering
と同等のものなので、なんと挙動が変わっています。一応、確認してみると、// Welcome to Scala 2.12.8 (OpenJDK 64-Bit Server VM, Java 11.0.2). scala> val seq = Seq(+0.0, Double.PositiveInfinity, Double.NaN, -0.0, Double.NegativeInfinity) scala> seq.sorted res0: Seq[Double] = List(-Infinity, -0.0, 0.0, Infinity, NaN) scala> seq.min res1: Double = -Infinity scala> seq.max res2: Double = -0.0// Welcome to Scala 2.13.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_181). scala> val seq = Seq(+0.0, Double.PositiveInfinity, Double.NaN, -0.0, Double.NegativeInfinity) scala> seq.sorted ^ ^ // warning: object DeprecatedDoubleOrdering in object Ordering is deprecated (since 2.13.0): There are multiple ways to order Doubles (Ordering.Double.TotalOrdering, Ordering.Double.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it explicitly. See the documentation for details. res0: Seq[Double] = List(-Infinity, -0.0, 0.0, Infinity, NaN) scala> seq.min ^ ^ // warning: object DeprecatedDoubleOrdering in object Ordering is deprecated (since 2.13.0): There are multiple ways to order Doubles (Ordering.Double.TotalOrdering, Ordering.Double.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it explicitly. See the documentation for details. res1: Double = -Infinity scala> seq.max ^ // warning: object DeprecatedDoubleOrdering in object Ordering is deprecated (since 2.13.0): There are multiple ways to order Doubles (Ordering.Double.TotalOrdering, Ordering.Double.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it explicitly. See the documentation for details. res2: Double = NaNあれ、今度は
max
が違う結果ですね。
これはさらにややこしいことに Scala 2.13 ではSeq.min
Seq.max
の実装も変更されているためです。
ともかく Scala 2.13 に移行すると挙動が変わる可能性はあるので、 警告が出たらTotalOrdering
とIeeeOrdering
のどちらが実装したい機能にふさわしいか考慮したうえで明記するのがいいでしょう。
- 投稿日:2019-06-27T10:11:01+09:00
[Java] 参照型を親クラス、インスタンス化を子クラスで行う場合の注意点
Parent p = new Child()
とChild c = new Child()
で何が異なるのか備忘録注意点
- 変数はstaticかどうかにかかわらず、参照型のクラス("="の左側)が優先される。
- メソッドは、staticであれば、参照型のクラス("="の左側)が優先される。
想定ケース
- Childクラスの親クラスがParentクラス
- staticと非staticなメンバとメソッドが定義それぞれ各クラスで定義されている。
class Parent{ int a = 1; static int b = 2; String medhod1() { return "parent method1"; } static String medhod2() { return "parent method2"; } } class Child extends Parent{ int a = 10; int b = 20; @Override String medhod1() { return "child method1"; } static String medhod2() { return "child method2"; } }実行結果
Parent parent = new Child(); System.out.println(parent.a); // => 1 ・・・★ System.out.println(parent.b); // => 2 ・・・★ System.out.println(parent.medhod1()); // => child method1 ・・・★ System.out.println(parent.medhod2()); // => parent method2 Child child = new Child(); System.out.println(child.a); // => 10 System.out.println(child.b); // => 20 System.out.println(child.medhod1()); // => child method1 System.out.println(child.medhod2()); // => child method1
- 投稿日:2019-06-27T09:54:56+09:00
JAVAの書き方備忘録(複数言語でごっちゃになっちゃう人へ)
はじめに
- この記事は、claw44を使って書いています。
- 複数の言語を使っていると、書き方がごっちゃになっちゃうよね!
- 配列の長さを出す方法とか、pythonとrubyとでどっちか分からなくなっちゃうよね!
- なので、後からコピペできるように、Javaの書き方をまとめておくことにしました。
- まだ書きかけです。
参考
内容
▼ 忘れそうなこと
- 1ファイルにつき、1クラスを記載する。
- ファイル名とクラス名は、大文字小文字含めて一緒にする。
- インデントは半角空白4個
MyApp.javapublic class MyApp{ public static void main(String[] args){ // 処理 } }▼ クォーテーションの使い分けについて
'
は、1文字に使う"
は、文字列に使う▼ 変数の種類
データ型
- char型は1文字
- String型は文字列。Stringだけ、最初の文字が大文字。
- long型は、容量の大きいint型みたいなもの。値の最後に"L"をつける。
- float型は、容量の大きいdouble型みたいなもの。値の最後に"F"をつける。
char a = 'a'; String s = "hello world!"; int i = 10; long l = 10000000L; double d = 234.222; float f = 234.987F;
参照型
配列
int[] array; array = new int[3];int[] array; array = new int[] {100, 200, 300};int[] array = {100, 200, 300};配列の長さを調べる
int i = array.length;▼ コマンドラインに出力
System.out.println();▼ インクリメント・デクリメント演算子
存在する。(rubyには存在しなかった…)
x++; x--; x += 1; x -= 1;▼ 型変換
数字 ⇒ 文字列
String s = String.valueOf(i);
文字列 ⇒ 数字
int i = Integer.parseInt(s);
整数 ⇔ 浮動小数点
double d = (double)i; int i = (int)d;▼ 制御文
if
if
と条件の括弧の間は半角空白分空ける。
- いわゆる普通の書き方
if (条件){ // 処理 } else if (条件){ // 処理 } else { }
switch
switch(変数){ case 値1: // 処理 // 変数の値が”値1”の時に処理する。 break; case 値2: case 値3: // 処理 // 変数の値が”値2”か”値3”の時に処理する。 break; default: // 処理 break; }▼ 三項演算子
条件 ? 正のときの戻り値 : 誤のときの戻り値; 例: String msg = i > 80 ? "good" : "so so...";▼ 繰り返し文 (loop)
共通
break;
⇒ loopを抜ける。continue;
⇒ 現loop回を抜けて次のloop回に進む。
while
while (条件){ // 処理 }
do while
do { // 処理 } while (条件)
for
for (int i = 0; i < 10; i++){ // 処理 }▼ メゾット
宣言の仕方
修飾子 (static) 戻り値の型 メソッド名(引数){ メソッドの処理 } 例: public static void SayHello(){ // 処理 }修飾子
- public
- protected
- private
- 指定なし(デフォルト)
static
static
をつけると、クラスメゾットになる。
static
無しだと、インスタンスメゾットとなる。戻り値
メゾットが戻り値を返す場合は、戻り値の型をここに記載。
戻り値を返さない場合は、void
と記載。インスタンス変数の呼び出し
メゾット内でインスタンス変数を呼び出したい場合は
this.変数名
を使う
メゾットのオーバーロード
同じメゾット名でも、引数の数、型が異なれば複数定義できる。
システムは、引数の数と型を見て、どっちのメゾット定義を使えばいいか判断する。public class MyApp{ public static void sayHi(String name){ System.out.println("Hi! " +name); } public static void sayHi(){ System.out.println("Hi! Nobody"); } public static void main(String[] args){ sayHi("Jones"); // Hi! Jones sayHi(); // Hi! Nobody } }▼ クラス
宣言
class User { }
インスタンス化
User jones = new User();
コンストラクタ
クラスをインスタンス化するときに呼ばれる。
クラス名と同じ名前にする。class User { String name; User(String name) { this.name = name; } User jones = new User("Jones");
this
this
は、インスタンスを表す。
this.name
と書いたら、インスタンス変数のname
ということ。
普通にname
書いたら、それはメゾットのローカル変数となる。また、コンストラクタ内で使用した場合は、他(引数の型・数が違う)コンストラクタを呼び出すことができる。
class User { String name; User(String name) { this.name = name; } User() { this("noname"); } User a_person = new User(); System.out.println(a_person.name); // noname
継承
オーバーライド
super()
- 投稿日:2019-06-27T07:57:22+09:00
Spring Boot の application.properties と @Profile アノテーションで環境を切り替える
概要
- Spring Boot でプロファイルを切り替えて実行する
- プロファイルの指定がない場合は Spring Framework では default プロファイルが使われる
- 自前のプロファイルとして development, test, production の3つを用意する
- test と production は一部で同じ要素を使うように構成する
- プロファイルごとの application-*.properties を用意して、記述した値を使用する
- @Profile アノテーションを使用して、指定したプロファイルに対応する bean クラスのオブジェクトを DI (Dependency injection) する
- 複数のプロファイルに対応する bean クラスを用意する
- 複数のプロファイルを指定した場合に対応する
ソースコード一覧
$ tree src src ├── main │ ├── java │ │ └── info │ │ └── maigo │ │ └── lab │ │ └── sample │ │ └── profiles │ │ ├── MyData.java │ │ ├── MyDataForDefault.java │ │ ├── MyDataForDevelopment.java │ │ ├── MyDataForTestAndProduction.java │ │ ├── MyRestController.java │ │ └── ProfilesApplication.java (←今回は中身を省略) │ └── resources │ ├── application-development.properties │ ├── application-production.properties │ ├── application-test.properties │ └── application.properties基本部分のソースコード
MyRestController.java
Spring Framework の DI 機能で MyData のオブジェクトをインジェクションする。
@Autowired アノテーションをインスタンス変数 myData に記述する。
http://localhost:8080/ へアクセスした際に MyData の情報を JSON で返すようにする。package info.maigo.lab.sample.profiles; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyRestController { @Autowired private MyData myData; @RequestMapping("/") public MyData index() { return myData; } }MyData.java
MyData オブジェクトの interface 定義。今回は特にメソッドは用意しない。
package info.maigo.lab.sample.profiles; public interface MyData { }MyDataForDefault.java
default プロファイルで使用する MyData の実装クラス。
@Profile アノテーションで DI するときのプロファイルを指定できる。ここでは default を指定している。
インスタンス変数 profile には文字列 "default" を代入。
インスタンス変数 message には application.properties の message.value を代入。package info.maigo.lab.sample.profiles; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; @Component @Profile("default") public class MyDataForDefault implements MyData { public String profile = "default"; @Value("${message.value}") public String message; }application.properties
default プロファイルで使用するプロパティファイル。
message.value=Hello, default!default プロファイルで起動する
ビルドして作った JAR ファイルを指定して起動する。プロファイルを指定するパラメータは付けない。
$ java -jar target/profiles-0.0.1-SNAPSHOT.jar起動したサーバにアクセスすると default プロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/ {"profile":"default","message":"Hello, default!"}development プロファイルで使用するソースコード
MyDataForDevelopment.java
development プロファイルで使用する MyData の実装クラス。
@Profile アノテーションにて develop プロファイルを指定。
インスタンス変数 profile に文字列 "development" を代入。
インスタンス変数 message に application-development.properties の message.value を代入。package info.maigo.lab.sample.profiles; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; @Component @Profile("development") public class MyDataForDevelopment implements MyData { public String profile = "development"; @Value("${message.value}") public String message; }application-development.properties
development プロファイルで使用するプロパティファイル。
message.value=Hello, development!development プロファイルを指定して起動する
JVM パラメータ -Dspring.profiles.active に development を指定する。
$ java -Dspring.profiles.active=development -jar target/profiles-0.0.1-SNAPSHOT.jar起動したサーバにアクセスすると development プロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/ {"profile":"development","message":"Hello, development!"}test プロファイルと production プロファイルで使用するソースコード
MyDataForTestAndProduction.java
test プロファイルと production プロファイルで使用する MyData の実装クラス。
@Profile アノテーションに test と production を指定している。指定したいずれかのプロファイルが指定されたときにこのクラスのオブジェクトが DI 対象となる。
@RestController にて返却する JSON の profile は、このクラスの getProfile メソッドにて生成する。Environment#getActiveProfiles で複数指定されたプロファイル名が取得できる。package info.maigo.lab.sample.profiles; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Component @Profile({"test", "production"}) public class MyDataForTestAndProduction implements MyData { @Autowired private Environment env; public String getProfile() { return String.join(",", env.getActiveProfiles()); } @Value("${message.value}") public String message; }application-test.properties
test プロファイルで使用するプロパティファイル。
message.value=Hello, test!application-production.properties
production プロファイルで使用するプロパティファイル。
message.value=Hello, production!test プロファイルを指定して起動する
JVM パラメータ -Dspring.profiles.active に test を指定する。
$ java -Dspring.profiles.active=test -jar target/profiles-0.0.1-SNAPSHOT.jar起動したサーバにアクセスすると test プロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/ {"message":"Hello, test!","profile":"test"}production プロファイルを指定して起動する
JVM パラメータ -Dspring.profiles.active に production を指定する。
$ java -Dspring.profiles.active=production -jar target/profiles-0.0.1-SNAPSHOT.jar起動したサーバにアクセスすると production プロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/ {"message":"Hello, production!","profile":"production"}複数のプロファイル test と production を指定して起動する
JVM パラメータ -Dspring.profiles.active にカンマ区切りで複数のプロファイルを指定する。
$ java -Dspring.profiles.active=test,production -jar target/profiles-0.0.1-SNAPSHOT.jar起動したサーバにアクセスすると test と production 両方のプロファイルの情報が読み込まれているのがわかる。
application-test.properties と application-production.properties に定義した message.value の値は、競合した結果 application-production.properties の値が優先された (競合すべき値を設定すべきではないと考えられる)。$ curl http://localhost:8080/ {"message":"Hello, production!","profile":"test,production"}今回の環境
- OpenJDK 11
- Spring Boot 2.2.0.M4
参考資料
- 投稿日:2019-06-27T04:29:07+09:00
配列の長さを指定せずに、要素を追加していく方法
初記事です。来年社会人でIT企業へ入ることが決まり、独学でJavaの勉強をしています。。
超初心者のため、コードなどは参考にならない(汚すぎてよくない)と思います。
配列(
int[]
など)を使用してArrayListのadd()
メソッドのようなことをできないか調べました。配列の長さを逐一変更していくしかない
みたいです。。
配列の長さを変えるには
System.arraycopy()
を使って配列のコピーをつくる必要があり、
例えばint[3]
からint[5]
に変更する場合、class Hairetsu { public static void main(String args[]) { int[] a = new int[3]; //コピー元 a[0] = 1; a[1] = 2; a[2] = 3; int[] b = new int[5]; //コピー先 System.arraycopy( a, 0, b, 0, a.length ); //( 配列aを, aの0から, 配列bへ, bの0から, aの要素全ての数分)コピー! for ( int i = 0 ; i < b.length ; i++ ){ System.out.println( b[i] ); } } }実行結果
1 2 3 0 0といったコードになります。
なので、これを応用し、リストにあるadd()
メソッド的なものを作ろうとすると、、、class HairetsuList { static int[] list; public static void add(int a){ int i = list.length; int[] copy = new int[i+1]; //元より要素数が1おおきい配列を作成 System.arraycopy( list , 0 , copy , 0 , i ); copy[i] = a ; list = copy; //配列の長さ違うけど、これありなんだ。。 } }こんな感じになり、一応テスト、、
class Test { public static void main(String args[]) { HairetsuList test = new HairetsuList(); test.list = new int[3]; test.list[0] = 1; test.list[1] = 2; test.list[2] = 3; test.add(4); System.out.print("{ "); for (int i=0 ; i < test.list.length; i++){ System.out.print( test.list[i]+" "); } System.out.print("}"); } }実行結果
{ 1 2 3 4 }コードの稚拙さはともかく、何とかなりました。普通にリストなどを使えばいいですね。。
今回は企業の研修課題で配列を使わなくてはならないとあったため頑張って考えましたが、、プログラミング難しい。。
- 投稿日:2019-06-27T04:29:07+09:00
配列の長さを指定しないで、要素を追加していく方法
初記事です。来年社会人でIT企業へ入ることが決まり、独学でJavaの勉強をしています。。
超初心者のため、コードなどは参考にならない(汚すぎてよくない)と思います。
配列(
int[]
など)を使用してArrayListのadd()
メソッドのようなことをできないか調べました。配列の長さを逐一変更していくしかない
みたいです。。
配列の長さを変えるには
System.arraycopy()
を使って配列のコピーをつくる必要があり、
例えばint[3]
からint[5]
に変更する場合、class Hairetsu { public static void main(String args[]) { int[] a = new int[3]; //コピー元 a[0] = 1; a[1] = 2; a[2] = 3; int[] b = new int[5]; //コピー先 System.arraycopy( a, 0, b, 0, a.length ); //( 配列aを, aの0から, 配列bへ, bの0から, aの要素全ての数分)コピー! for ( int i = 0 ; i < b.length ; i++ ){ System.out.println( b[i] ); } } }実行結果
1 2 3 0 0といったコードになります。
なので、これを応用し、リストにあるadd()
メソッド的なものを作ろうとすると、、、class HairetsuList { static int[] list; public static void add(int a){ int i = list.length; int[] copy = new int[i+1]; //元より要素数が1おおきい配列を作成 System.arraycopy( list , 0 , copy , 0 , i ); copy[i] = a ; list = copy; //配列の長さ違うけど、これありなんだ。。 } }こんな感じになり、一応テスト、、
class Test { public static void main(String args[]) { HairetsuList test = new HairetsuList(); test.list = new int[0]; test.add(4); test.add(5); test.add(3); System.out.print("{ "); for (int i=0 ; i < test.list.length; i++){ System.out.print( test.list[i]+" "); } System.out.print("}"); } }実行結果
{ 4 5 3 }コードの稚拙さはともかく、何とかなりました。普通にリストなどを使えばいいですね。。
今回は企業の研修課題で配列を使わなくてはならないとあったため頑張って考えましたが、、プログラミング難しい。。
- 投稿日:2019-06-27T02:31:50+09:00
Javaで文字コードを推測する
はじめに
本稿ではjuniversalchardetを使用して、
- ファイルの文字コードを推測・デコード・コンソールへの表示を行う
- URLエンコードされた文字列をデコードする
の2つのサンプルプログラムを作成します。
juniversalchardetとはMozillaによって提供されているライブラリで、バイト列のパターンの出現頻度をもとに文字コードを推測する機能を提供します。現在日本語ではISO-2022-JP, SHIFT-JIS, EUC-JPに対応しています。
開発環境
- OpenJDK 11
- Maven 3.6
下準備
以下をpom.xmlのdependenciesに追加します
<dependency> <groupId>com.googlecode.juniversalchardet</groupId> <artifactId>juniversalchardet</artifactId> <version>1.0.3</version> </dependency>サンプル1. ファイル読み込み
Detectorクラス
今回は汎用性のためにInputStreamを引数としてみます。
引数に渡されたInputStreamインスタンスはオフセットが進んでしまう事に注意が必要です。
UniversalDetectorは入力データが全てシングルバイト文字の場合は文字コード判定結果がnullとなります。今回はそのような場合は環境デフォルト値を返すようにしました。import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import org.mozilla.universalchardet.UniversalDetector; public class Detector { public static Charset getCharsetName(InputStream is) throws IOException { //4kbのメモリバッファを確保する byte[] buf = new byte[4096]; UniversalDetector detector = new UniversalDetector(null); //文字コードの推測結果が得られるまでInputStreamを読み進める int nread; while ((nread = is.read(buf)) > 0 && !detector.isDone()) { detector.handleData(buf, 0, nread); } //推測結果を取得する detector.dataEnd(); final String detectedCharset = detector.getDetectedCharset(); detector.reset(); if (detectedCharset != null) { return Charset.forName(detector.getDetectedCharset()); } //文字コードを取得できなかった場合、環境のデフォルトを使用する return Charset.forName(System.getProperty("file.encoding")); } }Mainクラス
ファイルの文字コードを判別し、コンソールに出力します。
FileInputStreamはmask/resetをサポートしていないため、文字コード判別とコンソール出力で別のインスタンスを生成します。import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; public class Main { public static void main(String[] args) throws IOException { final String path = "./test.txt"; Charset cs; try (FileInputStream fis = new FileInputStream(path)) { cs = Detector.getCharsetName(fis); System.out.println("charset:" + cs); } try (BufferedReader br =new BufferedReader(new InputStreamReader(new FileInputStream(path), cs))) { br.lines().forEach(s -> System.out.println(s)); } } }実行例
charset:SHIFT-JIS あいうえおサンプル2. URLのデコード
追加でApache commons codecを使用します。
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.12</version> </dependency>Detectorクラス
import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import org.mozilla.universalchardet.UniversalDetector; public class Detector { public static Charset getCharsetName(byte[] bytes) { UniversalDetector detector = new UniversalDetector(null); //入力文字列が短すぎると推測ができないため、入力を繰り返す while (!detector.isDone()) { detector.handleData(bytes, 0, bytes.length); detector.dataEnd(); } final String charsetName = detector.getDetectedCharset(); detector.reset(); if (charsetName != null) { return Charset.forName(charsetName); } return Charset.forName(System.getProperty("file.encoding")); } }Mainクラス
import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.net.URLCodec; public class Main { public static void main(String[] args) throws DecoderException, UnsupportedEncodingException { final String str= "%82%a0%82%a2%82%a4%82%a6%82%a8"; //URLエンコード文字列をパースし、バイト配列にする byte[] bytes = new URLCodec() .decode(str, StandardCharsets.ISO_8859_1.name()) .getBytes(StandardCharsets.ISO_8859_1.name()); Charset cs = Detector.getCharsetName(bytes); System.out.println("charset:"+cs); //バイト配列を検出したcharsetを用いて文字列にする final String s = new String(bytes,cs); System.out.println(s); } }実行例
charset:SHIFT-JIS あいうえおおわりに
入力文字列が短すぎると誤検出をする場合がありますのでご了承ください。
文字コード周りは非常に面倒な上に、マルチバイト語族にしか関係ない話のため英語の情報があまり充実していなかったりします。
本稿が助けになれば幸いです。
- 投稿日:2019-06-27T01:17:47+09:00
[Java] メンバ変数におけるstatic finalとfinalの違い
クラスの定数としてよく使われる
private static final
でstaticをつけることにどのような意味があるのか調査結果。インスタンスごとに名前を付けたい場合などに有用。メンバ変数におけるstatic finalとfinalの違い
- staticをつけないと、コンストラクタでの初期化を許すことになる。(=インスタンスごとの定数を意味する)
- staticをつけると、インスタンスではなく、クラスで固有な定数となる。
public class Sample { private static final String A1 = "A1"; // private static final String A1; はコンパイルエラー private final String A2; Sample() { this.A2 = "A2"; } public static void main(String[] args) { new Sample(); } }
- クラスに一つだけ生成される変数なので、メモリの使用量が抑えられる?
定数などはstaticにしておくことでインスタンスごとではなくクラスに1つだけ持つことになり、メモリが抑えられます。