1
Help us understand the problem. What are the problem?

posted at

Java8初期で知識が止まってる化石プログラマーがJava17を触って得た知見

はじめに

Java8初期で知識が止まっている化石プログラマーが書籍『プロになるJava』を読んで、得た知見をメモ書き感覚であげていきます。

初歩的な内容も含まれてますが、温かい目で見守ってください。。

JShell

CUI上でJavaコードを実行できる。Java9より導入された。
参考:https://qiita.com/nowokay/items/e0b9c676567134e4a622

tabで補完、ドキュメント表示なども可能。

/vで型を確認できる

jshell> /v textBlock 
|    String textBlock = "改行あり\n\n文字列です\n"

テキストブロック

Java15から。
"""で囲った文字列は複数行の文字列として宣言できる。

jshell> var textBlock = """
   ...> 改行あり
   ...> の
   ...> 文字列です
   ...> """
textBlock ==> "改行あり\n\n文字列です\n"

また、テキストブロック内ではエスケープ\が不要になる。

jshell> """
   ...> テキストブロック内では"エスケープ"が不要
   ...> """
$16 ==> "テキストブロック内では\"エスケープ\"が不要\n"

BigDecimal

雑に言うと、10進数を扱うための型。

jshell> var ten = BigDecimal.valueOf(10)
ten ==> 10

jshell> var twenty = BigDecimal.valueOf(20)
twenty ==> 20

jshell> ten.subtract(twenty)
$34 ==> -10


# 足し算
jshell> ten.add(twenty)
$33 ==> 30

# 引き算
jshell> ten.subtract(twenty)
$37 ==> -10

# 掛け算
jshell> ten.multiply(twenty)
$35 ==> 200

# 割り算
jshell> ten.divide(twenty)
$36 ==> 0.5

0, 1, 10は定数が用意されている。

jshell> BigDecimal.ZERO
$40 ==> 0

jshell> BigDecimal.ONE
$38 ==> 1

jshell> BigDecimal.TEN
$39 ==> 10

BigDecimalが有用なケースの一つとして、小数計算がある。
有名な話だが、コンピュータは10進数の小数同士の計算が苦手。例えば0.1+0.2なんかは誤差が出てしまう。

jshell> 0.1+0.2
$24 ==> 0.30000000000000004

これは0.1も0.2も10進数→2進数に変換した際に循環小数となってしまうためだ。
参考:http://www.it-license.com/cardinal_number/DecimalToBinary.html

BIgDecimalではこの誤差問題を以下のように回避できる。

jshell> var b1 = new BigDecimal("0.1")
b1 ==> 0.1

jshell> var b2 = new BigDecimal("0.2")
b2 ==> 0.2

jshell> b1.add(b2)
$27 ==> 0.3

BigDecimal(String val)コンストラクタを用いて、"0.1" "0.2"を扱うことが可能になる。2進数がどうとかは関係なく、コンストラクタ引数に指定した文字列をそのまま数値として扱えるのがミソ。

なお、valueOfでもOK

jshell> var b3 = BigDecimal.valueOf(0.1)
b3 ==> 0.1

jshell> var b4 = BigDecimal.valueOf(0.2)
b4 ==> 0.2

jshell> b3.add(b4)
$45 ==> 0.3

switch

switch文の書き方がJava14から変更されている。
変更点は、それぞれのcaseにbreakが不要になったのと、ラムダっぽく->を使える点である。

        var num = 1;

        // Java14〜
        switch (num) {
            case 0 -> System.out.println("ZERO");
            case 1 ->  System.out.println("ONE");
            case 2 ->  System.out.println("TWO");
            default ->  System.out.println("OTHER");
        }

        // 〜Java13
        switch (num) {
            case 0:
                System.out.println("ZERO");
                break;
            case 1:
                System.out.println("ONE");
                break;
            case 2:
                System.out.println("TWO");
                break;
            default:
                System.out.println("OTHER");
                break;
        }

switchに値を返させることも可能。

        var num = 1;

        var numStr = switch (num) {
            case 0 -> "ZERO";
            case 1 ->  "ONE";
            case 2 ->  "TWO";
            default ->  "OTHER";
        };

        System.out.println(numStr); //ONE

record

Java16より、recordを使うことで型の違うデータをまとめて扱うことができる。

jshell>         record Person(String name, int age) {}
   ...>         var p1 = new Person("一郎", 10);
   ...> 
|  次を作成しました: レコード Person
p1 ==> Person[name=一郎, age=10]

jshell> p1.name()
$5 ==> "一郎"

jshell> p1.age()
$6 ==> 10

jshell> p1.name().length()
$7 ==> 2

プロパティへのアクセスはname() age()で可能。
Listにもつめれるので、Streamで色々処理できそうな予感。

jshell>         var p2 = new Person("二郎", 20);
   ...>         var p3 = new Person("三郎", 30);
p2 ==> Person[name=二郎, age=20]
p3 ==> Person[name=三郎, age=30]

jshell>         var persons = List.of(p1, p2, p3);
   ...> 
persons ==> [Person[name=一郎, age=10], Person[name=二郎, age=20], Person[name=三郎, age=30]]

recordの中にメソッドを定義することも可能。

        record Person(String name, int age) {
            public String getUpper(){
                return this.name.toUpperCase();
            }
        }

        var p1 = new Person("ichiro", 10);

        System.out.println(p1.getUpper()); //ICHIRO

もちろん外部クラスとして定義することも可能。

ManRecord.java
public record ManRecord(String name, int age) {
    // メソッドなど・・・
}

DTOクラスとかは今後Recordに置き換わっていくのかな・・・?
と思ったけど、継承ができないので、基底クラスで共通化なんかしてると移行は難しそうな予感。
継承を使わないようなDTO設計が求められるのか?
参考:https://irof.hateblo.jp/entry/2021/09/23/235642

Java17~は既存のDTOクラスは「Recordに置換しますか?」とweak warningを出すらしく、やはりrecordへの移行を促していそう。

メソッド参照の使い所

メソッド参照自体はJava8からあるのですが、IDEに補完してもらわないとなかなか気づけないことが多いワタクシ。メソッド参照を使える条件を再確認すると、以下のような感じ。

引数 -> インスタンス.メソッド(引数)

クラス::メソッド

受け取った引数をstaticメソッドに渡している
→引数を省略して、クラス名とメソッド名だけ書く
※staticメソッドの場合も大体同じ。

<例1>

x -> someInstance.doSomething(x)

SomeInstance::doSomething

<例2>

s -> System.out.println(s)

System.out::println

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
1
Help us understand the problem. What are the problem?