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

【Java8】拡張for文、forEach文のインデックスをimmutableにする

普通に宣言した場合

拡張for文、forEach文を普通に宣言すると以下のようになります。
final宣言していないため、再代入可能です(for文は原理的に再代入が必須なので飛ばします)。

List<Integer> intList = Arrays.asList(1, 2, 3, 4);

for(int i : intList) {
    i = 0; // 書き換えられる
}

intList.forEach(it -> {
    it = 0; // 書き換えられる
});

この記事では、これらの内容を再代入不能な形に書き換えます。

インデックスをimmutableにする

拡張for文の場合

finalで宣言することでimmutableにできます。

for(final int i : intList) {
    i = 0; // final宣言しているため再代入不可でコンパイルエラー
}

forEach文の場合

以下のように、カッコで括って型を指定することで引数をfinalにできます。

intList.forEach((final int it) ->
    it = 0; // final宣言しているため再代入不可でコンパイルエラー
);

別解

一応ですが、無名クラスとして実装する場合も引数をfinalにできます。

Consumer<Integer> finalConsumer = new Consumer<Integer>() {
    @Override
    public void accept(final Integer it) {
        it = 0; // final宣言しているため再代入不可でコンパイルエラー
    }
};

お詫び

この記事は当初公開した際「インデックスをimmutableにできるのはfor文、拡張for文、forEach文の内拡張for文だけ」というタイトル・内容でしたが、@saka1029 様のご指摘の通り、これは誤りでしたので、タイトル・内容共に全面的に書き直しを行いました。

@saka1029 様、ご指摘ありがとうございました。

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

【Java8】インデックスをimmutableにできるのはfor文、拡張for文、forEach文の内拡張for文だけ

内容は(補足の補足に書いた通りちょっと語弊が有りますが)タイトルの通りです。
具体的には以下のようになります。

List<Integer> intList = Arrays.asList(1, 2, 3, 4);

// final int iで宣言するとi++がエラーになる
for (int i = 0; i < intList.size(); i++) {
    i = 0; // 当然書き換えられる
}

for(final int i : intList) {
    i = 1; // final宣言できるので再代入不可
}

intList.forEach(it -> {
    it = 0; // 書き換えられる
});

intList.stream().forEach(it -> {
    it = 0; // 当然streamでも書き換えられる
});

// こう書くとコンパイルエラー
intList.forEach(final Integer it -> {
    it = 0;
});

補足

forEach文でインデックスが書き換えられるのは、これが引数に取る関数型インターフェースConsumerの引数がfinalで定義されていない(というか多分できない)からです。

例えばインターフェースで引数をfinalにしようと思っても以下のようになります。

関数型インターフェース
@FunctionalInterface
public interface FinalConsumer<T> {
    void accept(final T t);
}
実際に使うと上書きできてしまう
FinalConsumer<Integer> finalConsumer = it -> it = 0;
finalConsumer.accept(1); // 実行時エラーにもならない

補足の補足

一応ですが、無名クラスとして実装する場合は引数をfinalにできます。

Consumer<Integer> finalConsumer = new Consumer<Integer>() {
    @Override
    public void accept(final Integer it) {
        it = 0; // finalで引数を宣言しているため、これはコンパイルエラー
    }
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メイン・クラスが存在するにもかかわらず「エラー: メイン・クラスXXXが見つからなかったかロードできませんでした」が発生する

事象

まず以下のようなChildクラスが存在するとします。

Child.java
public class Child extends Parent {
    public static void main(String[] args) {
        System.out.println("This class is `Child`");
    }
}

これをchild.jarに格納し、Java8で実行した結果が次の通りになります。

C:\>java -version
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

C:\>java -cp child.jar Child
エラー: メイン・クラスChildが見つからなかったかロードできませんでした

Childクラスは確かに存在するにも関わらず「メイン・クラスChildが見つからなかったかロードできませんでした」というエラーによりJavaの実行が失敗しました。

原因

真因はChildの親クラスParentが読み込めていないためになります。実はParentchild.jarとは別のparent.jarに格納されています。しかし上記のjavaコマンド実行方法では、parent.jarが読み込めていません。

そこでparent.jarもクラスパスに加えて、javaを実行してやると、想定通り動作しました。

C:\>java -version
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

C:\>java -cp child.jar;parent.jar Child
This class is `Child`

「Childが見つからない」という部分だけを見ると、Childが正しくchild.jarに格納できていないように思えますし、実際筆者はこの思いこみのせいでずいぶんと時間を無駄にしました……。エラーメッセージが分かりにくいのが悪いんや(逆ギレ)

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

Java 単体テスト結果報告書の自動作成

目次 ⇒ Java単体テストライブラリ-Artery-サンプル

Javaの単体テストライブラリArteryでは、単体テストの結果をタブ区切りで出力することにより、単体テスト結果報告書とすることができます。

package jp.avaj.lib.test;

/**
Java 単体テスト結果報告書の自動作成

単体テストの結果をエクセルで読込むと、テスト結果報告書の形式にすることができる。
この形式でよければ、テスト結果報告書の作成の手間を省くことができる。

 */
public class Q06_00 {

  public static void main(String[] args) {

    // 単体テスト結果報告書の作成
    // この出力をエクセルで読込むとテスト結果報告書となる
    {
      // エクセル出力の指定
      ArTest.testOutLevel = ArTestOutLevel.EXCEL;
      // テストの名称⇒先頭に表示される
      ArTestExcelEnv.systemName = "QIITAシステム単体テスト結果報告書";
      // テスト実施者⇒指定しなければテスト実施者は表示されない
      ArTestExcelEnv.testerName = "闇雲";
      // テスト実施日⇒指定しなければ yy/mm/dd となる
      ArTestExcelEnv.testDate = "12/31";
      // テスト番号の開始⇒指定しなければ 0 となる
      ArTestExcelEnv.startTestNo = 1;
    }

    // ログ出力ファイルの指定
    ArTest.startUnitTest("unittest","c:/tmp");


    ArTest.startTestCase("うるう年判定");

    boolean result;
    // 2020年はうるう年 ⇒ resultはtrueが正しい
    result = LeapYear.isLeapYear(2020);
    // 結果をチェックする.
    ArTest.isTrue("2020年","result",result);

    // 2100年は平年 ⇒ resultはfalseが正しい
    result = LeapYear.isLeapYear(2100);
    // 結果をチェックする.
    ArTest.isFalse("2100年","result",result);

    // テストケースを終了する
    ArTest.endTestCase();


    ArTest.startTestCase("キム・ベイシンガーの役名⇒映画名の変換");

    // ヴィッキー・ヴェイル ⇒ 正解はバットマン
    String movie = Kim.getMovieTitle("ヴィッキー・ヴェイル");
    // 結果をチェックする
    ArTest.equals("ヴィッキー・ヴェイル","expected","バットマン","movie",movie);

    // キャロル・マッコイ ⇒ 正解はゲッタウェイ
    movie = Kim.getMovieTitle("キャロル・マッコイ");
    // 結果をチェックする
    ArTest.equals("キャロル・マッコイ","expected","ゲッタウェイ","movie",movie);

    // テストケースを終了する
    ArTest.endTestCase();


    // すべてのテストケースの集計の表示
    ArTest.reportTotalSummary();

  }
  //////////// 以下はテスト対象のクラス
  /** うるう年判定クラス(もしかしたらバグがあるかも). */
  static class LeapYear {
    public static boolean isLeapYear(int year) {
      return ((year % 4) == 0);
    }
  }
  /** キム・ベイシンガーの役名⇒映画名の変換クラス(もしかしたらバグがあるかも). */
  static class Kim {
    public static String getMovieTitle(String name) {
      if ("ヴィッキー・ヴェイル".equals(name)) { return "バットマン"; }
      if ("キャロル・マッコイ".equals(name)) { return "ブロンディ"; }
      // その他は省略
      return null;
    }
  }
}

エクセルの出力指定をしない場合の結果は次のとおり

result.txt
**** うるう年判定 start ****
OK 2020年:result=true
NG 2100年:result=true
jp.avaj.lib.test.Q06_00.main(Q06_00.java:44)
**** うるう年判定 summary ****
test count = 2
success    = 1
**** キム・ベイシンガーの役名⇒映画名の変換 start ****
OK ヴィッキー・ヴェイル:expected=バットマン:movie=バットマン
NG キャロル・マッコイ:expected=ゲッタウェイ:movie=ブロンディ
jp.avaj.lib.test.Q06_00.main(Q06_00.java:60)
**** キム・ベイシンガーの役名⇒映画名の変換 summary ****
test count = 2
success    = 1
**** total ****
total test count = 4
total success    = 2

エクセルの出力指定をした場合の結果は次のとおり

result.txt
QIITAシステム単体テスト結果報告書

**** うるう年判定 start ****
TestNo  日付  担当  結果  テスト内容 期待値   実際値
001-001 12/31   闇雲  OK  2020年 TRUE    true
001-002 12/31   闇雲  NG  2100年 FALSE   true
**** うるう年判定 summary ****
test count = 2
success    = 1
**** キム・ベイシンガーの役名⇒映画名の変換 start ****
TestNo  日付  担当  結果  テスト内容 期待値   実際値
002-001 12/31   闇雲  OK  ヴィッキー・ヴェイル  バットマン バットマン
002-002 12/31   闇雲  NG  キャロル・マッコイ ゲッタウェイ  ブロンディ
**** キム・ベイシンガーの役名⇒映画名の変換 summary ****
test count = 2
success    = 1
**** total ****
total test count = 4
total success    = 2

エクセルで読込むと次のようになる。

無題.png

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

Java 8 (OpenJDK: Zulu Community) を Homebrew で macOS にインストールする

概要

  • macOS に Homebrew で Java 8 (OpenJDK をビルドした Zulu Community) をインストールする方法を示す

Zulu Community とは

Zulu Community は Azul Systems が配布している OpenJDK ディストリビューション。

Zulu Community Java OpenJDK無料ダウンロード TCKテスト済

Azulは、2023年7月までOpenJDK7のZulu Communityビルドのアップデートを毎四半期に提供し、OpenJDK 8のビルドは2026年3月までアップデートされ、OpenJDK 11のビルドは2027年9月までアップデートされます。Java 9、10、12、15、16のような中間リリースは、最初のリリースから少なくとも6か月はアップデートされます。
Azulはまた、2014年以降のOpenJDK Zulu Communityビルドのアーカイブを保持します。

Zulu Community 8 は2026年3月までサポートされるとのこと。

Zulu Community 8 をインストールする

Zulu Community 8 は homebrew/cask-versions にあるのでこれを使用してインストールする。

$ brew cask install zulu8

java_home コマンドでインストールされたディレクトリの場所を確認する

$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home

環境変数 JAVA_HOME と PATH を設定する

必要に応じて .bash_profile や .bashrc などに記述する。

$ export JAVA_HOME=`/usr/libexec/java_home -v 1.8`
$ PATH=${JAVA_HOME}/bin:${PATH}

インストールされた Zulu Community を確認する

$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (Zulu 8.40.0.25-CA-macosx) (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (Zulu 8.40.0.25-CA-macosx) (build 25.222-b10, mixed mode)

$ javac -version
javac 1.8.0_222

$ which java
/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/bin/java

$ which javac
/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/bin/javac

不要になったらアンインストールする

$ brew cask uninstall zulu8

参考資料

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

Java 8 (OpenJDK: Amazon Corretto) を Homebrew で macOS にインストールする

概要

  • macOS に Homebrew で Java 8 (OpenJDK をビルドした Amazon Corretto) をインストールする方法を示す

Amazon Corretto とは

Amazon Corretto は Amazon が配布している OpenJDK ディストリビューション。

Amazon Corretto(本番環境に対応したOpenJDKディストリビューション)| AWS

Amazon Corretto は、マルチプラットフォームで本番環境に対応した、無料の Open Java Development Kit (OpenJDK) ディストリビューションです。Corretto は、パフォーマンスの向上とセキュリティの修正などの長期サポートを用意しています。Amazon は、社内において何千もの本番サービスで Corretto を実行しており、Corretto は Java SE 標準と互換性があると認定されています。Corretto を使用することで、Linux、Windows、macOS などの一般的なオペレーティングシステムで Java アプリケーションを開発し、実行できます。

Amazon Corretto 8 は少なくとも2023年6月まではサポートされるとのこと。

よくある質問 - Amazon Corretto | AWS

Amazon Corretto は、マルチプラットフォームで本番環境に対応した、長期サポート (LTS) を含む無料の Open Java Development Kit (OpenJDK) ディストリビューションです。LTS には、最短でも関連するリリースバージョンの指定日 (例: Corretto 8 の場合は 2023 年 6 月) までは、パフォーマンスの向上とセキュリティの更新を無償で提供するという Amazon のコミットメントが含まれています。アップデートは四半期ごとにリリースされる予定です。Amazon では、通常の四半期サイクルの範囲外で、利用可能になった際に緊急で対応できる修正 (セキュリティを含む) を適用することも計画しています。

Amazon Corretto 8 をインストールする

Amazon Corretto 8 は homebrew/cask-versions にあるのでこれを使用してインストールする。

$ brew tap homebrew/cask-versions

$ brew cask install corretto8

java_home コマンドでインストールされたディレクトリの場所を確認する

$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home

環境変数 JAVA_HOME と PATH を設定する

必要に応じて .bash_profile や .bashrc などに記述する。

export JAVA_HOME=`/usr/libexec/java_home -v 1.8`
PATH=${JAVA_HOME}/bin:${PATH}

インストールされた Amazon Corretto を確認する

$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment Corretto-8.222.10.1 (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM Corretto-8.222.10.1 (build 25.222-b10, mixed mode)

$ javac -version
javac 1.8.0_222

$ which java
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home/bin/java

$ which javac
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home/bin/javac

不要になったらアンインストールする

$ brew cask uninstall corretto8

参考資料

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

Java 8 (OpenJDK: AdoptOpenJDK) を Homebrew で macOS にインストールする

概要

  • macOS に Homebrew で Java 8 (OpenJDK をビルドした AdoptOpenJDK) をインストールする方法を示す

AdoptOpenJDK とは

AdoptOpenJDK は Amazon, Azul Systems, IBM, Microsoft, Pivotal, Red Hat などがスポンサーになっていて配布されている OpenJDK ディストリビューション。

AdoptOpenJDK - Open source, prebuilt OpenJDK binaries

Java™ is the world's leading programming language and platform. AdoptOpenJDK uses infrastructure, build and test scripts to produce prebuilt binaries from OpenJDK™ class libraries and a choice of either the OpenJDK HotSpot or Eclipse OpenJ9 VM.

AdoptOpenJDK 8 は少なくとも2023年9月まではサポートされるとのこと。

Support | AdoptOpenJDK - Open source, prebuilt OpenJDK binaries

At Least Sep 2023

AdoptOpenJDK 8 をインストールする

インストール方法が公式リポジトリの README に載っている。

AdoptOpenJDK/homebrew-openjdk: AdoptOpenJDK HomeBrew Tap

brew tap AdoptOpenJDK/openjdk
brew cask install <version>

README には AdoptOpenJDK/openjdk を tap して追加するように書いてあるが、 AdoptOpenJDK は homebrew/cask-versions にも存在する。

今回は homebrew/cask-versions を使用してインストールする。

$ brew tap homebrew/cask-versions

$ brew cask install adoptopenjdk8

java_home コマンドでインストールされたディレクトリの場所を確認する

$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

環境変数 JAVA_HOME と PATH を設定する

必要に応じて .bash_profile や .bashrc などに記述する。

export JAVA_HOME=`/usr/libexec/java_home -v 1.8`
PATH=${JAVA_HOME}/bin:${PATH}

インストールされた AdoptOpenJDK を確認する

$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.222-b10, mixed mode)

$ javac -version
javac 1.8.0_222

$ which java
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java

$ which javac
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/javac

不要になったらアンインストールする

$ brew cask uninstall adoptopenjdk8

参考資料

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

デザインパターン:(23分の1)

過去に教えて頂いたデザインパターンの一つ
テンプレートメソッドパターンをアウトプット
(間違ってるかも)

デザインパターン:TemplateMethod
を参考にJAVAをC#に変えて記述にしております。

Class1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Class1
{
    public abstract class AbstractDisplay
    {
        public abstract void Open();
        public abstract void Print();
        public abstract void Close();

        public void Display()
        {
            Open();
            for (int i = 0; i < 3; i++)
            {
                Print();
            }
            Close();
        }
    }
    public class CharDisplay : AbstractDisplay
    {
        char ch;
        public CharDisplay(char ch)
        {
            this.ch = ch;
        }

        public override void Open()
        {
            Console.Write("***");
        }

        public override void Print()
        {
            Console.Write(ch);
        }

        public override void Close()
        {
            Console.WriteLine("***");
        }
    }
    public class StringDisplay : AbstractDisplay
    {
        private string str;
        private int width;
        public StringDisplay(string str)
        {
            this.str = str;
            this.width = str.Length;
        }
        void PrintLine()
        {
            Console.Write("+");
            for (int i = 0; i < width; i++)
            {
                Console.Write("-");
            }
            Console.WriteLine("+");
        }

        public override void Open()
        {
            PrintLine();
        }

        public override void Print()
        {
            Console.WriteLine("|" + str + "|");
        }
        public override void Close()
        {
            PrintLine();
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            AbstractDisplay cd = new CharDisplay('T');
            cd.Display();
            AbstractDisplay sd = new StringDisplay("Design Pattern");
            sd.Display();

        }
    }
}

23分の1個目

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

デザインパターンC#:TemplateMethod

過去に教えて頂いたデザインパターンの一つ
テンプレートメソッドパターンをアウトプット
(間違ってるかも)

デザインパターン:TemplateMethod
を参考にJAVAをC#に変えて記述にしております。

Class1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Class1
{
    public abstract class AbstractDisplay
    {
        public abstract void Open();
        public abstract void Print();
        public abstract void Close();

        public void Display()
        {
            Open();
            for (int i = 0; i < 3; i++)
            {
                Print();
            }
            Close();
        }
    }
    public class CharDisplay : AbstractDisplay
    {
        char ch;
        public CharDisplay(char ch)
        {
            this.ch = ch;
        }

        public override void Open()
        {
            Console.Write("***");
        }

        public override void Print()
        {
            Console.Write(ch);
        }

        public override void Close()
        {
            Console.WriteLine("***");
        }
    }
    public class StringDisplay : AbstractDisplay
    {
        private string str;
        private int width;
        public StringDisplay(string str)
        {
            this.str = str;
            this.width = str.Length;
        }
        void PrintLine()
        {
            Console.Write("+");
            for (int i = 0; i < width; i++)
            {
                Console.Write("-");
            }
            Console.WriteLine("+");
        }

        public override void Open()
        {
            PrintLine();
        }

        public override void Print()
        {
            Console.WriteLine("|" + str + "|");
        }
        public override void Close()
        {
            PrintLine();
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            AbstractDisplay cd = new CharDisplay('T');
            cd.Display();
            AbstractDisplay sd = new StringDisplay("Design Pattern");
            sd.Display();

        }
    }
}

23/1個目

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

デザインパターン:(23/1)

過去に教えて頂いたデザインパターンの一つ
テンプレートメソッドパターンをアウトプット
(間違ってるかも)

デザインパターン:TemplateMethod
を参考にJAVAをC#に変えて記述にしております。

Class1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Class1
{
    public abstract class AbstractDisplay
    {
        public abstract void Open();
        public abstract void Print();
        public abstract void Close();

        public void Display()
        {
            Open();
            for (int i = 0; i < 3; i++)
            {
                Print();
            }
            Close();
        }
    }
    public class CharDisplay : AbstractDisplay
    {
        char ch;
        public CharDisplay(char ch)
        {
            this.ch = ch;
        }

        public override void Open()
        {
            Console.Write("***");
        }

        public override void Print()
        {
            Console.Write(ch);
        }

        public override void Close()
        {
            Console.WriteLine("***");
        }
    }
    public class StringDisplay : AbstractDisplay
    {
        private string str;
        private int width;
        public StringDisplay(string str)
        {
            this.str = str;
            this.width = str.Length;
        }
        void PrintLine()
        {
            Console.Write("+");
            for (int i = 0; i < width; i++)
            {
                Console.Write("-");
            }
            Console.WriteLine("+");
        }

        public override void Open()
        {
            PrintLine();
        }

        public override void Print()
        {
            Console.WriteLine("|" + str + "|");
        }
        public override void Close()
        {
            PrintLine();
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            AbstractDisplay cd = new CharDisplay('T');
            cd.Display();
            AbstractDisplay sd = new StringDisplay("Design Pattern");
            sd.Display();

        }
    }
}

23/1個目

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

今更だけどぬるぽ

ぬるぽってなんですぞい

Javaと付き合うのであれば一生ついてくるであろうNullPointerExceptionという例外で
海外ではNPE等と略されてる
参照型で参照する値がないときに参照しようとするとおこるやつ

ぬるぽがわかれば参照型がわかる

参照型

参照型とは変数の内部に、実際の値が入っているメモリのアドレスを持っている型で、
例として
String x = "あ"
と定義したとすると、このときにxに実際に格納されているものは "あ" のメモリ上のアドレスとなっている。
つまり
x = 0001
0001 = "あ”
みたいな感じになっている。

住所不定無職

さて、いよいよぬるぽはどうしておこるのかですが
nullという状態はさっきの変数xのアドレスが未定義の状態のことで
x = null
とすると
x = 未定義
0001 = "あ"
みたいにメモリにデータがあってもなくても実際のデータがある場所がわからない状態に、
このときに x を使おうとすると 「ふえぇ、住所わっかんないよぉ〜><」 と言う感じでぬるぽになります。
つまりNullPointerExceptionは住所不定無職の人に会おうとしても住所がなくて会えないって感じです。

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

Effective Java 項目25 具象化不可能型(nonreifiable type)について

E、List<E>、そして、List<String>は、技術的には具象化不可能型(nonreifiable type)として知られています。
直感的に言えば、具象化不可能型は、その実行時の表現がコンパイル時の表現よりも情報が少ない型です。
具象化可能な唯一のパラメータ化された型は、List<?>Map<?, ?>などの非境界ワイルドカード型です。非境界ワイルドカード型の配列の生成は許されていますが、稀にしか有用ではありません。
ジェネリック配列生成の禁止は、煩わしいかもしれません。例えば、一般にジェネリック型は、その要素型の配列を返すことが不可能です。
可変長引数のメソッドをジェネリック型と組み合わせて使用する場合、困惑する警告が出る可能性も意味しています。それは、可変長引数のメソッドを呼び出すと、必ず可変長パラメータを保持するために配列が生成されるからです。
(下記のコードでいうと、argsがそれに該当する)

static int sum(int... args) {
    int sum = 0;
    for (int arg : args) {
        sum += arg;
    }
    return sum;
}

この配列の要素型が具象化可能でなければ、警告が出ます。その警告を抑制することとAPIでジェネリックスと可変長引数を混在させないようにすること以外に、警告に対してできることはほとんどありません。

ジェネリック配列生成エラーとなる場合には、最善の解決策は、配列型E[]よりはコレクション型List<E>を大抵は使用することです。
何らかのパフォーマンスや簡潔さを犠牲にするかもしれませんが、代わりに、より良い型安全性と相互運用性を得ます。

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

Effective Java 項目25 配列よりリストを選ぶ 前半

配列よりリストを選ぶ

配列とジェネリック型の違いとして、

  • 配列は共変であり、ジェネリック型は不変である
  • 配列は具象化(実行時にその要素型を知っていて、強制すること)だが、ジェネリックスはイレイジャ(コンパイル時にのみ型制約を強制し、実行時に型情報を廃棄すること)

E、List<E>、そして、List<String>は、技術的には具象化不可能型(nonreifiable type)として知られています。
直感的に言えば、具象化不可能型は、その実行時の表現がコンパイル時の表現よりも情報が少ない型です。
具象化可能な唯一のパラメータ化された型は、List<?>Map<?, ?>などの非境界ワイルドカード型です。非境界ワイルドカード型の配列の生成は許されていますが、稀にしか有用ではありません。
ジェネリック配列生成の禁止は、煩わしいかもしれません。例えば、一般にジェネリック型は、その要素型の配列を返すことが不可能です。
可変長引数のメソッドをジェネリック型と組み合わせて使用する場合、困惑する警告が出る可能性も意味しています。それは、可変長引数のメソッドを呼び出すと、必ず可変長パラメータを保持するために配列が生成されるからです。
(下記のコードでいうと、argsがそれに該当する)

static int sum(int... args) {
    int sum = 0;
    for (int arg : args) {
        sum += arg;
    }
    return sum;
}

この配列の要素型が具象化可能でなければ、警告が出ます。その警告を抑制することとAPIでジェネリックスと可変長引数を混在させないようにすること以外に、警告に対してできることはほとんどありません。

ジェネリック配列生成エラーとなる場合には、最善の解決策は、配列型E[]よりはコレクション型List<E>を大抵は使用することです。
何らかのパフォーマンスや簡潔さを犠牲にするかもしれませんが、代わりに、より良い型安全性と相互運用性を得ます。

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

AtCoder Programming Guide for beginners (APG4b)のEX25をjavaで書いてみた。

はじめに

この記事は、AtCoder内コンテンツの

AtCoder Programming Guide for beginners (APG4b)

で掲載されている課題EX25 - 集合の操作をJavaで記述してみたので、備忘録としてコードを公開するものです。ご一読いただけたら幸いです。

読みづらい点、間違い、感想等ありましたらコメントにてお伝えいただけると嬉しいです。

尚、bit演算子を用いよう!という気概無く、整数値を直接扱っています...(C++でいうところのbitSetが実装されていればよかったのですが。ありますかね…?)

コード

Main.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        Integer[] A = new Integer[N];
        for(int i = 0;i < N;i++) {
            A[i] = sc.nextInt();
        }
        int M = sc.nextInt();
        Integer[] B = new Integer[M];
        for(int i = 0;i < M;i++) {
            B[i] = sc.nextInt();
        }
        String command = sc.next();
        int x = 0;
        if(command.equals("subtract")) {
            x = sc.nextInt();
        }
        sc.close();
        switch(command) {
        case "intersection":
            printResult(intersection(A, B));
            break;
        case "union_set":
            printResult(unionset(A, B));
            break;
        case "symmetric_diff":
            printResult(symmetricdiff(A, B));
            break;
        case "subtract":
            printResult(subtract(A, x));
            break;
        case "increment":
            printResult(increment(A));
            break;
        case "decrement":
            printResult(decrement(A));
            break;
        default:
            break;
        }
    }
    /**
     * AとBに共通して含まれる要素からなる集合を返す
     * @param A
     * @param B
     * @return 共通要素の配列
     */
    private static Integer[] intersection(Integer[] A,Integer[] B) {
        List<Integer> Alist = Arrays.asList(A);
        List<Integer> Blist = Arrays.asList(B);
        List<Integer> result = new ArrayList<>();
        for(Integer i : Alist) {
            if(Blist.contains(i)) {
                result.add(i);
            }
        }
        if(result.size()==0) return null;
        Collections.sort(result);
        return  result.toArray(new Integer[result.size()]);
    }

    /**
     * AとBのうち少なくとも一方に含まれる要素からなる集合を返す
     * @param A
     * @param B
     * @return 少なくとも一方に含まれる要素の配列
     */
    private static Integer[] unionset(Integer[] A,Integer[] B) {
        Set<Integer> result = new TreeSet<>(Comparator.naturalOrder());
        for(Integer i : A) result.add(i);
        for(Integer i : B) result.add(i);
        return result.size()==0 ? null : result.toArray(new Integer[result.size()]);
    }

    /**
     * AとBのうちどちらか一方にだけ含まれる要素からなる集合を返す
     * @param A
     * @param B
     * @return 一方にのみ含まれる要素の配列
     */
    private static Integer[] symmetricdiff(Integer[] A,Integer[] B) {
        List<Integer> intersection = Arrays.asList(intersection(A, B));
        List<Integer> union = Arrays.asList(unionset(A, B));
        List<Integer> result = new ArrayList<>();
        for(Integer i : union) {
            if(union.contains(i) && !intersection.contains(i)) {
                result.add(i);
            }
        }
        if(result.size()==0) return null;
        Collections.sort(result);
        return result.toArray(new Integer[result.size()]);
    }

    /**
     * 集合Aから値xを除く
     * @param A
     * @param x
     * @return
     */
    private static Integer[] subtract(Integer[] A, int x) {
        List<Integer> list = Arrays.asList(A);
        List<Integer> result = new ArrayList<>();
        for(Integer i : list) {
            if(i != x) {
                result.add(i);
            }
        }
        if(result.size()==0) return null;
        Collections.sort(result);
        return result.toArray(new Integer[result.size()]);
    }

    /**
     * Aの要素すべてに1を加える。
     */
    private static Integer[] increment(Integer[] A) {
        List<Integer> result = new ArrayList<>();
        for(Integer i : A) {
            i++;
            if(i.equals(50)) {
                i = 0;
            }
            result.add(i);
        }
        if(result.size()==0) return null;
        Collections.sort(result);
        return result.toArray(new Integer[result.size()]);
    }

    /**
     * Aの要素すべてから1を引く。
     */
    private static Integer[] decrement(Integer[] A) {
        List<Integer> result = new ArrayList<>();
        for(Integer i : A) {
            i--;
            if(i.equals(-1)) {
                i = 49;
            }
            result.add(i);
        }
        if(result.size()==0) return null;
        Collections.sort(result);
        return result.toArray(new Integer[result.size()]);
    }

    /**
     * 結果出力
     */
    private static void printResult(Integer[] result) {
        if(result==null) {
            System.out.println("");
            return;
        }
        if(result.length > 1) {
            for(int i = 0;i < result.length-1;i++) {
                System.out.print(result[i] + " ");
            }
        }
        System.out.println(result[result.length-1]);
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む