20190627のJavaに関する記事は14件です。

IntelliJのコンソールが文字化けする

自宅WindowsのIntelliJで発生。
会社でも同じようにIntelliJを使っているのだがそちらはちゃんと変換される。

Hoge.java
public class Hoge {
    public static void main(String[] args) {
        System.out.println("あああ");
    }
}
実行結果
あああ

プロセスは終了コード 0 で完了しました

ちゃんと動く方の情報

変換できている方の設定関連を調べてみた。

バージョン情報

image.png

IntelliJ設定

image.png

カスタム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.gradle
plugins {
    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/cb57bb9c942e55ed06d1

intellij-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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windowsでwarファイルを手軽に扱う

エクスプローラーでwarファイルをダブルクリックしてzipファイルのように中身を見ることができるようにするには、コマンドプロンプトを管理者権限で開いて以下のコマンドを実行します。

assoc .war=CompressedFolder

jarファイルをエクスプローラーで開けるようにするコチラの記事を参考にさせていただきました→ https://qiita.com/kitoo/items/6761fd74e8347962171a

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【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、使っていきましょう。


  1. この場面に関しては、パイプライン演算子が有ればCollectors.collectingAndThenを使う必要も無いんですが……。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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();
    }
}


  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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();
    }
}


  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メモ:多次元配列への値の代入と表示、および拡張for文の練習

概要

今まで2次元以下の配列を取り扱う時には、何となく、表、あるいは行列のようなイメージで頭を整理していました。が、3次元になった途端に頭が完全にバグるという事態に発展。

そこで、【初心者からわかる】Javaの多次元配列の使い方と、多次元配列を拡張for文で展開を参考にさせてもらって、頭を整理し直しました。以下は整理に使用したプログラムになります。

Intdealing.java
public 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時間ほどかけてあちこちのサイトを回って、なんとかプログラムを完成させました。今、私の頭の中では、多次元配列はアリの巣のように、あるいはマンションのように縦につながって積み重なる部屋の連なりとして捉えられています。

プログラムを勉強していく中で、今回のように躓くパターンが一番多いように感じられます。そもそもイメージとして捉えるのが間違っているのか、あるいは捉えるイメージが間違っているのかのはよくわかりませんが...

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

浮動小数点数の順序には二種類あるよ(-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 TotalOrdering
trait 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 IeeeOrdering

scala/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 のため TotalOrderingIeeeOrdering も同じ順序となるからです。ふーむ。他のメソッドはどうでしょうか。

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 = NaN
scala> 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 のため TotalOrderingIeeeOrdering は違う順序となるからです。なるほどなー。

ちなみに 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 に移行すると挙動が変わる可能性はあるので、 警告が出たら TotalOrderingIeeeOrdering のどちらが実装したい機能にふさわしいか考慮したうえで明記するのがいいでしょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JAVAの書き方備忘録(複数言語でごっちゃになっちゃう人へ)

はじめに

  • この記事は、claw44を使って書いています。
  • 複数の言語を使っていると、書き方がごっちゃになっちゃうよね!
  • 配列の長さを出す方法とか、pythonとrubyとでどっちか分からなくなっちゃうよね!
  • なので、後からコピペできるように、Javaの書き方をまとめておくことにしました。
  • まだ書きかけです。

参考

内容

▼ 忘れそうなこと

  • 1ファイルにつき、1クラスを記載する。
  • ファイル名とクラス名は、大文字小文字含めて一緒にする。
  • インデントは半角空白4個
MyApp.java
public 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()

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

参考資料

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

配列の長さを指定せずに、要素を追加していく方法

初記事です。来年社会人で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 }

コードの稚拙さはともかく、何とかなりました。普通にリストなどを使えばいいですね。。
今回は企業の研修課題で配列を使わなくてはならないとあったため頑張って考えましたが、、プログラミング難しい。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

配列の長さを指定しないで、要素を追加していく方法

初記事です。来年社会人で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 }

コードの稚拙さはともかく、何とかなりました。普通にリストなどを使えばいいですね。。
今回は企業の研修課題で配列を使わなくてはならないとあったため頑張って考えましたが、、プログラミング難しい。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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
あいうえお

おわりに

入力文字列が短すぎると誤検出をする場合がありますのでご了承ください。

文字コード周りは非常に面倒な上に、マルチバイト語族にしか関係ない話のため英語の情報があまり充実していなかったりします。

本稿が助けになれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[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つだけ持つことになり、メモリが抑えられます。

引用:【Java】private static final とは何ぞやという話 - 16bit!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む