20191028のJavaに関する記事は15件です。

S3に完全に同じファイルが上がってるか確認するロジックでちょっとハマったのでメモ。

いつもの如く、ブログからの転載です。
https://munchkins-diary.hatenablog.com/entry/2019/10/28/230924
最近あんまり書いてないですが、そろそろ再開したい。

S3上のファイルのチェックサムを取得する方法でハマりやすいとこと、下の方におまけでJavaでfileのチェックサムを計算する方法を書いておきました。

誰かの役に立てば幸いです。
(なおあまり)

S3のチェックサムを比較したい

数GBのファイルをS3に挙げるような処理を書いていて、後続処理の失敗などでリトライしたいというのがあった。

この場合、ファイルをアップロードし直すのはムダだが、移行元ストレージ内の対象ファイルが変更にされている可能性もある。
したがって、すでにS3上に完全に同じファイルがあるときだけアップロードをリトライしたい。

この場合、チェックサムを比較するのが楽なので、S3のgetObjectMetaData APIを利用して以下のようにコードを書いた。

 private boolean shouldSkip(String bucketName, String key, String md5CheckSum) {
      try {
        ObjectMetadata meta = s3Client.getObjectMetadata(bucketName, key);
        if (meta == null || meta.getContentMD5() == null) {
          log.info("meta data not exist for the file {} in bucket {}", key, bucketName);
          return false;
        }
        log.info(
            "Checksum of existing file is {} and present file checksum is {}",
            meta.getContentMD5(),
            md5CheckSum);
        return meta.getContentMD5().equals(md5CheckSum);
      } catch (SdkClientException e) {
        log.error("Exception thrown while validating the checksum of the file {}", key, e);
        return false;
      }
    }

しかし、どうもうまく行かない。
ObjectMetaData#contentMD5がどうしてもNullになってしまうのだ。

調べたところ、S3における既存オブジェクトのチェックサムはcontentMD5ではなく、Etagに付与されるらしい。

じゃあcontentMD5は何に使うかと言うと、更新時にHTTPヘッダに付与されて、S3内での改ざん確認(正しい使い方)に使うため、getでオブジェクトを取得する時は返されないのだとか。

したがって、S3から落として来たファイルのチェックサムを知りたい時はEtagと比較する必要がある。

こんな感じ。

    private boolean shouldSkip(String bucketName, String key, String md5CheckSum) {
      try {
        ObjectMetadata meta = this.s3Client.getObjectMetadata(bucketName, key);
        if (meta == null || meta.getETag() == null) {
          log.info("meta data not exist for the file {} in bucket {}", key, bucketName);
          return false;
        }
        log.info(
            "Checksum of existing file is {} and present file checksum is {}",
            meta.getETag(),
            md5CheckSum);
        return meta.getETag().equals(md5CheckSum);
      } catch (SdkClientException e) {
        log.error("Exception thrown while validating the checksum of the file {}", key, e);
        return false;
      }
    }

これならちゃんと動く。 誰かの役に立てば幸いです。

おまけ Javaでのチェックサム確認方法

チェックサムでググって飛んで来た人のために一応書いておくと、Javaでチェックサムを計算する方法はこんな感じ。

  public static String checkMd5Checksum(File file) {
    try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(file))) {
      return DigestUtils.md5Hex(is);
    } catch (Exception e) {
      // Not likely to occur.
      log.error(
          "ERROR Happened while calculating the check sum for file {}", file.getAbsolutePath(), e);
      return "NOT FOUND";
    }
  }

sha256なら DigestUtils#md5HexDigestUtils#sha256Hexに変えるだけ。

以上、メモでした。

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

Eclipse MicroProfileとは

概要

前回の記事では、Eclipse MicroProfileの始め方をご紹介しました。今記事では、そもそもEclipse MicroProfileとはなにか?を紹介します。

生まれたきっかけ

もともとはJavaEEの仕様策定のプロセスが遅い、リソースを十分に供給できていないと危機感を持った複数のベンダーとJavaコミュニティによって生まれました。

特徴としては、JAX-RSやCDIなど、JavaEEの中で慣れ親しんだ仕様を一部取り込みつつ、マイクロサービスアーキテクチャで必要な機能を独自で取り込んでいくというものとなります。

image.png

※現在の公式サイトのWhitePaparから抜粋

その後、2017年1月ごろ、Eclipse Foundation傘下に正式に加わった物となります。

https://www.publickey1.jp/blog/17/javamicroprofileeclipse.html

仕様に準拠しているプロダクト、実装

これも上述のホワイトペーパーを抜粋すると以下の通りとなっています。

image.png

ここで注目すべきは以下の通りです。

  • JBoss EAPはJavaEEサーバにも関わらず、MicroProfileにも準拠している
  • Open LibertyはJavaEE のWebProfile仕様準拠にも関わらず、MicroProfileにも準拠している
  • 日本国内のJavaEEサーバベンダーで対応しているのは富士通社のみ

Eclipse MicroProfile3.0の仕様一覧

最後に、簡単にではありますが、各種仕様について一言ずつ説明していきます。

Eclipse MicroProfile Config

クラウド上やマイクロサービスとしてアプリケーション設定をしやすくします。
具体的には、アプリ内に設定をハードコードしてしまうと、環境によってアプリを都度ビルドする必要が出てきてしまうため、起動時の引数や、環境変数の内容で設定を上書きできるようにすることができます。SpringBootでも同じような機能がありますね。

Eclipse MicroProfile Fault Tolerance

マイクロサービスとしてアプリケーションを作る際に、別のサービスとの関連と、ビジネスロジックを分離することを目的とした機能です。具体的な機能としては、TimeOut、RetryPolicy、Fallback、Bulkhead、Circuit Breakerなどがあります。

Eclipse MicroProfile Health

マイクロサービスとして呼ばれるサービスとして、そのサービスが応答できる健康な状態かどうかを示す機能を提供する仕様です。Up、Downだけでなく、捕捉情報も含めて返却することができます。

Eclipse MicroProfile JWT Authentication

OpenID Connect (OIDC) と JSON Web Tokens (JWT)を使って認証機能を提供します。
role based access control (RBAC)で作られるマイクロサービスとして提供されることを前提としています。

Eclipse MicroProfile Metrics

運用時に必要なメトリクスを提供する機能を示した仕様です。

Eclipse MicroProfile OpenAPI

マイクロサービスをOpenAPI仕様であるOpenAPI v3 specificationに則るAPIドキュメンテーションを出力できるような機能を提供する仕様です。

Eclipse MicroProfile OpenTracing

マイクロサービスでは、どのサービスが遅延しているか、どのサービスがどんな頻度でエラーとなっているかを可視化しておくことが重要です。トレース結果を出力することができます。

Eclipse MicroProfile Rest Client

JavaEEのJAX-RS 2.1 APIのRest Client作成をベースとしてよりtype-safeに実装することができるようにする機能を提供する仕様です。

JavaEEから継承している仕様

  • CDI 2.0
  • JAX-RS 2.1
  • JSON-B 1.0
  • JSON-P 1.1
  • Common Annotations 1.3

 まとめ

今回はコード無しで、Eclipse MicroProfileについて説明しました。
UberJarの話とかすっとばしましたが、なんとなく全体像は分かったのではないでしょうか。

JavaEEで慣れ親しんだ仕様+マイクロサービスで必要な機能ということで有用なものもあったかと思います。個人的にはConfigとかは、マイクロサービス関係なく、どんなアプリでもこの機能があると開発が楽になるものと思うので、他でも楽に使えると良いかと思いました。

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

inteliJのブレークポイントで変数の値を変更する方法

環境

Intelij
Java(Java以外でもできるかもしれないけど未確認)

手順

下のようなコードを書くと、当然"Hello World"と表示されますが、
strに"ハローワールド!"という別の値をデバッグ中は入れたいとします。
スクリーンショット 2019-10-28 22.51.25.png

そんなときはブレークポイントを設定
→右クリック
→More(command + shift + F8)
スクリーンショット 2019-10-28 22.52.01.png

BreakPointsウィンドウが出るので
Evaluate and log にチェック
→strに値を代入
→(ブレークポイントで止めたくない場合)Suspendのチェックを外す
スクリーンショット 2<br>
019-10-28 22.52.47.png

この状態でDebug実行すると
スクリーンショット 2019-10-28 22.53.04.png

"ハローワールド!"と出ました。
二回出てるのはEvaluate and "log"によるログ出力のためです。

値の代入以外にも、メソッドの実行なども可能です。
特別な条件のときにしか実行されないコードのデバッグなどに使えると思います。

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

NLP4J - [005-1] Twitter4J と NLP4J でTwitter分析をしてみる(データ収集)

Indexに戻る : [004]構文解析の統計処理 > [005-1] NLP4J+Twitter4J(データ収集) > 次のページ

データ収集

では次にNLP4JでTwitterのデータを分析してみましょう。

今のところNLP4Jは「お手軽分析」の位置づけですので、お手軽に分析してみます。

分析シナリオとしては自動車各社(トヨタ、日産、ホンダ)の公式Twitterがどのようなツイートをしているのかを分析してみる、というものにしてみます。
https://twitter.com/TOYOTA_PR
https://twitter.com/NissanJP
https://twitter.com/HondaJP

適当にクエリーを作り替えることで様々な切り口とデータでの分析ができそうな”気がします”。

まずはデータ収集から行いましょう。

Twitterのデータ収集には、Twitter API の Java Wrapperとして有名な「Twitter4j」を使ってみることにします。

Twitter4J

http://twitter4j.org/ja/index.html

Maven pom.xml に Twitter4J を追加しましょう。

Maven POM

<dependency>
    <groupId>org.nlp4j</groupId>
    <artifactId>nlp4j</artifactId>
    <version>1.0.0.0</version>
</dependency>
<dependency>
    <groupId>org.twitter4j</groupId>
    <artifactId>twitter4j-core</artifactId>
    <version>[4.0,)</version>
</dependency>

Twitter4J の準備

Twitter アプリの定義

以下にアクセスして、アプリケーションの定義を行います。
https://apps.twitter.com/

キーの取得

アプリケーションの定義をするとapps.twitter.com にて以下の値を取得できますのでコピーしておきます。

Application Settings
Consumer Key (API Key) --> (1)としてメモ
Consumer Secret (API Secret) --> (2)としてメモ

Your Access Token
Access Token --> (3)としてメモ
Access Token Secret --(4)としてメモ

twitter4j.properties の準備 (クラスパスに通す)

以下のプロパティファイルを用意しておき、クラスパスに通しておきます。

debug=false
http.prettyDebug=false

oauth.consumerKey= (1)で取得した値
oauth.consumerSecret= (2)で取得した値
oauth.accessToken= (3)で取得した値
oauth.accessTokenSecret= (4)で取得した値
jsonStoreEnabled=true

Code

収集したツイートを直接NLP4Jに投入してみます。
(もちろんCSVやJSONなどのファイルに保存してもOKです。)

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import nlp4j.DocumentAnnotator;
import nlp4j.Document;
import nlp4j.Index;
import nlp4j.Keyword;
import nlp4j.impl.DefaultDocument;
import nlp4j.index.SimpleDocumentIndex;
import nlp4j.yhoo_jp.YjpAllAnnotator;
import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;

/**
 * 日本語形態素解析とインデックス処理を利用して、共起性の高いキーワードを抽出するサンプルソースコードです。 <br>
 * Sample for Dependency Analysis and Morphological analysis.
 * 
 * @author Hiroki Oya
 *
 */
public class HelloTextMiningTwitter {

    /**
     * メイン関数です。<br>
     * Main Method
     * 
     * @param args 無し
     * @throws Exception 実行時の例外
     */
    public static void main(String[] args) throws Exception {

        String[] accounts = { "NissanJP", "TOYOTA_PR", "HondaJP" };
        List<Document> docs = new ArrayList<Document>();
        for (String account : accounts) {
            docs.addAll(createDocumentTwitter(account));
        }

// 形態素解析アノテーター+構文解析アノテーター
        DocumentAnnotator annotator = new YjpAllAnnotator(); // 形態素解析+構文解析
        {
            System.err.println("形態素解析+構文解析");
            // 形態素解析+構文解析
            annotator.annotate(docs);
        }
// キーワードインデックス(統計処理)の用意
        Index index = new SimpleDocumentIndex();
        {
            System.err.println("インデックス作成");
            // キーワードインデックス作成処理
            index.addDocuments(docs);
        }
        {
            // (略)分析...
        }
    }

    static List<Document> createDocumentTwitter(String item) {
        ArrayList<Document> docs = new ArrayList<Document>();
        try {
            Twitter twitter = TwitterFactory.getSingleton();
            Query query = new Query("from:" + item);
            query.setCount(10);
            QueryResult result = twitter.search(query);
            for (Status status : result.getTweets()) {
                // System.out.println("@" + status.getUser().getScreenName() + ":" +
                // status.getText());
                Document doc = new DefaultDocument();
                doc.putAttribute("item", item);
                doc.setText(status.getText());
                docs.add(doc);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return docs;
    }
}

簡単ですね!
次のページでは、分析結果を見てみることにします。


Indexに戻る : [004]構文解析の統計処理 > [005-1] NLP4J+Twitter4J(データ収集) > 次のページ

プロジェクトURL

https://www.nlp4j.org/
NLP4J_N_128.png


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

NLP4J [005-1] Twitter4J と NLP4J でTwitter分析をしてみる(データ収集)

Indexに戻る : [004]構文解析の統計処理 > [005-1] NLP4J+Twitter4J(データ収集) > 次のページ

データ収集

では次にNLP4JでTwitterのデータを分析してみましょう。

今のところNLP4Jは「お手軽分析」の位置づけですので、お手軽に分析してみます。

分析シナリオとしては自動車各社(トヨタ、日産、ホンダ)の公式Twitterがどのようなツイートをしているのかを分析してみる、というものにしてみます。
https://twitter.com/TOYOTA_PR
https://twitter.com/NissanJP
https://twitter.com/HondaJP

適当にクエリーを作り替えることで様々な切り口とデータでの分析ができそうな”気がします”。

まずはデータ収集から行いましょう。

Twitterのデータ収集には、Twitter API の Java Wrapperとして有名な「Twitter4j」を使ってみることにします。

Twitter4J

http://twitter4j.org/ja/index.html

Maven pom.xml に Twitter4J を追加しましょう。

Maven POM

<dependency>
    <groupId>org.nlp4j</groupId>
    <artifactId>nlp4j</artifactId>
    <version>1.0.0.0</version>
</dependency>
<dependency>
    <groupId>org.twitter4j</groupId>
    <artifactId>twitter4j-core</artifactId>
    <version>[4.0,)</version>
</dependency>

Twitter4J の準備

Twitter アプリの定義

以下にアクセスして、アプリケーションの定義を行います。
https://apps.twitter.com/

キーの取得

アプリケーションの定義をするとapps.twitter.com にて以下の値を取得できますのでコピーしておきます。

Application Settings
Consumer Key (API Key) --> (1)としてメモ
Consumer Secret (API Secret) --> (2)としてメモ

Your Access Token
Access Token --> (3)としてメモ
Access Token Secret --(4)としてメモ

twitter4j.properties の準備 (クラスパスに通す)

以下のプロパティファイルを用意しておき、クラスパスに通しておきます。

debug=false
http.prettyDebug=false

oauth.consumerKey= (1)で取得した値
oauth.consumerSecret= (2)で取得した値
oauth.accessToken= (3)で取得した値
oauth.accessTokenSecret= (4)で取得した値
jsonStoreEnabled=true

Code

収集したツイートを直接NLP4Jに投入してみます。
(もちろんCSVやJSONなどのファイルに保存してもOKです。)

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import nlp4j.DocumentAnnotator;
import nlp4j.Document;
import nlp4j.Index;
import nlp4j.Keyword;
import nlp4j.impl.DefaultDocument;
import nlp4j.index.SimpleDocumentIndex;
import nlp4j.yhoo_jp.YjpAllAnnotator;
import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;

public class HelloTextMiningTwitter {
    public static void main(String[] args) throws Exception {
        String[] accounts = { "NissanJP", "TOYOTA_PR", "HondaJP" };
        List<Document> docs = new ArrayList<Document>();
        for (String account : accounts) {
            docs.addAll(createDocumentTwitter(account));
        }
// 形態素解析アノテーター+構文解析アノテーター
        DocumentAnnotator annotator = new YjpAllAnnotator(); // 形態素解析+構文解析
        {
            System.err.println("形態素解析+構文解析");
            // 形態素解析+構文解析
            annotator.annotate(docs);
        }
// キーワードインデックス(統計処理)の用意
        Index index = new SimpleDocumentIndex();
        {
            System.err.println("インデックス作成");
            // キーワードインデックス作成処理
            index.addDocuments(docs);
        }
        {
            // (略)分析...
        }
    }

    static List<Document> createDocumentTwitter(String item) {
        ArrayList<Document> docs = new ArrayList<Document>();
        try {
            Twitter twitter = TwitterFactory.getSingleton();
            Query query = new Query("from:" + item);
            query.setCount(10);
            QueryResult result = twitter.search(query);
            for (Status status : result.getTweets()) {
                // System.out.println("@" + status.getUser().getScreenName() + ":" +
                // status.getText());
                Document doc = new DefaultDocument();
                doc.putAttribute("item", item);
                doc.setText(status.getText());
                docs.add(doc);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return docs;
    }
}

簡単ですね!
次のページでは、分析結果を見てみることにします。


Indexに戻る : [004]構文解析の統計処理 > [005-1] NLP4J+Twitter4J(データ収集) > 次のページ

プロジェクトURL

https://www.nlp4j.org/
NLP4J_N_128.png


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

JUnitでMockWebServerを使ってリクエスト送受信ロジックのテスト

Javaアプリケーションに外部APIを使った機能を実装する機会があったのでその時の話を。

やりたいこと

リクエスト送受信処理を新たに実装した場合、固定レスポンスで期待した動作をするのか確かめたい気持ちになります。
そこで、MockWebServerというライブラリを使って固定レスポンスを返すことにしました。これにより、リクエスト送受信の部分のロジック検証を簡易化できます。

mockserver.png

開発環境

今回試すJava環境は下記の通りです。

$ java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

ビルドツールはmaven(3.6.0)を使っている想定です。

利用方法

pom.xmlに必要なライブラリを追記します。

<dependency>
  <groupId>com.squareup.okhttp</groupId>
  <artifactId>mockwebserver</artifactId>
  <version>2.7.5</version>
  <scope>test</scope>
</dependency>

実装するにはMockWebServerとMockResponseをimportする必要があります。

MockWebServerがリクエストを受けてレスポンスを返す仕組みを提供するクラスで、MockResponseは専用のレスポンス内容を定義するために使うクラスです。

最低限MockWebServerを動かすためには下記のような実装になります。

import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;

public class QiitaTest {

    private MockWebServer mockWebServer;

    @Before
    public void setup() throws IOException {
        this.mockWebServer = new MockWebServer();
        this.mockWebServer.start();
    }

    @Test
    public void qiitaTest() {
        String json = "{\"message\": \"qiita用テスト\"}";
        MockResponse mockResponse = new MockResponse();
        mockResponse.setBody(json);
        mockResponse.setResponseCode(200);
        this.mockWebServer.enqueue(mockResponse);

        String mockServerUrl = mockWebServer.url("/").toString();
        // mockServerUrl = http://localhost:59690/

        // リクエスト送信処理を書いてレスポンスを受け取ってテスト内容を書く
    }
}

ダミーサーバを立ち上げるためにはMockWebServerのインスタンスを生成し、startメソッドを呼び出します。
ここでは使っていないですが、コンストラクタの引数にポートを指定することが可能です。
mockWebServer.start() は IOException が throws で指定されているため、前処理として定義したsetup()も同様にしています。

これにより、Jacksonなどを使ってレスポンス内容をオブジェクトにマッピングする処理を固定レスポンスで検証できたりします。
※具体的にリクエストを送信する処理は割愛します

上記の様に正常系処理も試せますが、 setBodyDelay を使うとレスポンスを恣意的に遅延させることが可能です。

import import java.util.concurrent.TimeUnit;
...
    @Test
    public void qiitaDelayTest() {
        String json = "{\"message\": \"10秒遅れて来ます\"}";
        MockResponse mockResponse = new MockResponse();
        mockResponse.setBody(json);
        mockResponse.setBodyDelay(10, TimeUnit.SECONDS);
        mockResponse.setResponseCode(200);
        this.mockWebServer.enqueue(mockResponse);
        ...        
    }

リクエスト送信処理の中でタイムアウトの設定をして、わざと閾値を超えた時のエラーハンドリングを試すことができます。

Unitテストではこの様に明示的にjsonを作ってリクエストを送信する方法でテストを実行していますが、MockServerを裏で立ち上げておいて、リクエストの送信先をMockServerに向けたアプリケーションを動かして、動作を確認することも可能です。

最後に

MockWebServerのおかげで簡単にresponse指定で動作確認ができました。
テストコード自体が不慣れだったので間違いもあるかもしれないですが、外部APIを経由するロジックの動作を自分なりに検証した時の方法でした。

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

【Java】JDBCをインストールして、servlet + MySQL で接続してみた。( DAO / Bean を使用バージョンあり)

◆ 目次

◇ ディレクトリ構成
◇ 【画像】出力内容 & DB内容

  1. JDBC ドライバ導入
  2. context.xml を作成する
  3. 実行(複数パターン)
    1. 【実行】servlet(サーブレット)
    2. 【実行】DAO ~Beanを使わない~
    3. 【実行】DAO ~Beanを使用~

◇ ディレクトリ構成

:file_folder: book
 ┣━ :file_folder: src
 ┃  ┣━ :file_folder: sample
 ┃  ┃  ┣━ :page_facing_up: All.java
 ┃  ┃  ┣━ :page_facing_up: ProductList.java
 ┃  ┃  ┗━ :page_facing_up: ProductList2.java
 ┃  ┃
 ┃  ┣━ :file_folder: dao
 ┃  ┃  ┣━ :page_facing_up: DAO.java
 ┃  ┃  ┗━ :page_facing_up: ProductDAO.java
 ┃  ┃
 ┃  ┗━ :file_folder: bean
 ┃     ┗━ :page_facing_up: Product.java
 ┃
 ┗━ :file_folder: WebContent
    ┣━ :file_folder: META-INF
    ┃  ┗━ :page_facing_up: context.xml
    ┃
    ┗━ :file_folder: WEB-INF
       ┗━ :file_folder: lib
          ┗━ :page_facing_up: mysql-connector-java-5.1.48-bin.jar

◇ 【画像】出力内容 & DB内容

・表示イメージ(左)
・DBの内容(右)
スクリーンショット 2019-10-28 16.04.19.png

1. JDBC ドライバ導入

  1. 公式サイトからmysql-connector-java-8.0.18.zipダウンロード
  2. 解凍するしてmysql-connector-java-5.1.48-bin.jarを取り出す
  3. /WebContent/WEB-INF/lib/mysql-connector-java-5.1.48-bin.jarに入れる

2. context.xml を作成する

/WebContent/META-INF/context.xmlに作成する

context.xml
<?xml version="1.0" encoding="UTF-8" ?>
<Context>
    <Resource name = "jdbc/book"
              auth = "Container"
              type = "javax.sql.DataSource"
              driverClassName = "com.mysql.jdbc.Driver"
              url      = "jdbc:mysql://localhost/book"
              username = "username"
              password = "password">
    </Resource>
</Context>

3. 実行(複数パターン)

  1. 【実行】servlet(サーブレット)
  2. 【実行】DAO ~Beanを使わない~
  3. 【実行】DAO ~Beanを使用~

1. 【実行】servlet(サーブレット)

/src/sample/All.javaに作成する

All.java
package sample;

import java.io.*;
import java.sql.*;

import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import javax.sql.*;

/**
 * Servlet implementation class All
 */
@WebServlet("/All")
public class All extends HttpServlet {


    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        PrintWriter out = response.getWriter();

        try {
            // コネクション取得
            InitialContext ic = new InitialContext();
            DataSource ds = (DataSource) ic.lookup("java:/comp/env/jdbc/book");
            Connection con = ds.getConnection();

            // SQL文送信
            PreparedStatement st = con.prepareStatement("select * from product");
            // 実行&結果受け取り
            ResultSet rs = st.executeQuery();

            // データの表示
            while (rs.next()) {
                out.println(
                    rs.getInt("id")      + ":" + 
                    rs.getString("name") + ":" + 
                    rs.getInt("price")
                );
            }

            // データベース切断
            st.close();
            con.close();

        } catch (Exception e) {
            // 接続・SQL文エラー
            e.printStackTrace(out);

        } // try
    }

}

2. 【実行】DAO ~Beanを使わない~

DAO(Data Access Object)を作成!!!!( ^ω^ )
上記、1. 【実行】servlet(サーブレット)の内容をライブラリ化する

1 ) DAO.java を作成する(コネクション取得)
2 ) ProductList.java を作成する(DAO取得 & 処理 & 表示)

1 ) DAO.java を作成する(コネクション取得)

DAO.java
package dao;

import java.sql.Connection;

import javax.naming.InitialContext;
import javax.sql.DataSource;

public class DAO {
    static DataSource ds;

    public Connection getConnection() throws Exception {

        // 初期コンテキスト構築
        InitialContext ic = new InitialContext();

        // DBの接続先情報を取得(context.xmlの内容)
        ds = (DataSource) ic.lookup("java:/comp/env/jdbc/book");

        return ds.getConnection();
    }
}

2 ) ProductList.java を作成する(DAO取得 & 処理 & 表示)

ProductList.java
package sample;

import dao.DAO;

import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet("/sample/productList")
public class ProductList extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        PrintWriter out = response.getWriter();

        try {
            // DB接続
            DAO dao = new DAO();
            Connection con = dao.getConnection();

            // SQL作成
            PreparedStatement st = con.prepareStatement("SELECT * FROM product");

            // SQL実行
            ResultSet rs = st.executeQuery();

            // データをセット
            while (rs.next()) {
                out.println(
                        rs.getInt("id")      + ":" + 
                        rs.getString("name") + ":" + 
                        rs.getInt("price")   + "<br>"
                    );
            }

            // 接続解除
            st.close();
            con.close();

        } catch (Exception e) {
            e.printStackTrace(out);
        }

    }
}

3. 【実行】DAO ~Beanを使用~

1 ) DAO.java を作成する(コネクション取得)
2 ) Product.java を作成する(Bean)
3 ) ProductDAO.java を作成する(DAO取得 & 処理)
4 ) ProductList2.java を作成する(ProductDAO取得 & 表示)

1 ) DAO.java を作成する(コネクション取得)

上記、2 ) 【実行】DAO ~Beanを使わない~と同じ為
!!!!! 割愛 !!!!!

2 ) Product.java を作成する(Bean)

Product.java
package bean;

public class Product implements java.io.Serializable {
    private int id;
    private String name;
    private int price;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

3 ) ProductDAO.java を作成する(DAO取得 & 処理)

ProductDAO.java
package dao;

import java.sql.*;
import java.util.*;
import bean.Product;

public class ProductDAO extends DAO {
    public List<Product> listAll() throws Exception {

        List<Product> list = new ArrayList<>();

        // DB接続
        Connection con = getConnection();

        // SQL作成
        PreparedStatement st = con.prepareStatement("SELECT * FROM product");

        // SQL実行
        ResultSet rs = st.executeQuery();

        // データをセット
        while (rs.next()) {
            Product p = new Product();
            p.setId(rs.getInt("id"));
            p.setName(rs.getString("name"));
            p.setPrice(rs.getInt("price"));

            list.add(p);
        }

        // 接続解除
        st.close();
        con.close();

        return list;
    }
}

4 ) ProductList2.java を作成する(ProductDAO取得 & 表示)

ProductList2.java
package sample;

import java.io.*;
import java.sql.*;
import java.util.List;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import javax.sql.*;
import bean.Product;
import dao.ProductDAO;

@WebServlet("/sample/productList2")
public class Search2 extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        PrintWriter out = response.getWriter();

        try {
            ProductDAO dao = new ProductDAO();

            List<Product> list = dao.listAll();

            for (Product p : list) {
                out.println(
                        p.getId()    + ":" + 
                        p.getName()  + ":" + 
                        p.getPrice() + "<br>"
                );
            }

        } catch (Exception e) {
            e.printStackTrace(out);
        }

    }

}

参考サイト

※ めちゃくちゃ参考になった!!!
Java で MySQL に 接続する 方法
https://garafu.blogspot.com/2016/05/how-to-connect-mysql.html#con-svlt1

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

WindowsでJavaを複数インストールしたらビルドできなくなった話

はじめに

kotlinの勉強をしようとして、java11をインストールしたところ、今まで通ってたjavaのbuildが通らなくなって焦った話

JAVAの使い分け

環境変数のJAVA_HOMEによって使い分けることができます。

VSCODEで環境変数の使い分け

プロジェクトの.vscodeフォルダに以下のファイルを置きましょう。

settings.json
{
        "terminal.integrated.env.windows": {
            "JAVA_HOME": "C:\\Program Files\\Java\\jdk1.8.0_211"
        }
}

これで、このプロジェクトはjava8専用になります。

タスクでも有効です。

Windows以外の場合には、末尾のwindowsをそれ以外にしましょう。

環境変数でうまくいかない場合は、dockerにしちゃうほうがいいかもしれません。

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

画像名を文字列で指定してImageViewに貼り付けるコード(android)

swiftだと画像名で画像を指定して貼り付けられるのですが、そういえばandroidではなかったなと(あるんですかね)

見つからなかった、というか大して探してないのですが何となく作りました。

手順は
①画像名からリソースIDを取得
②リソースIDを使って画像をセット
これだけです。

Util.java
public void setBackgroundResourceByString(Context context, String imgName, View view){
    int resourceId = context.getResources().getIdentifier(imgName, "drawable", context.getPackageName());
    view.setBackgroundResource(resourceId);
}

第一引数にgetContext()などで得たcontextを代入、
第二引数はdrawableに入れられた画像名をストリング型で代入、
第三引数はその画像を貼り付けたimageViewやViewを代入してください
※Viewを継承したクラスなら使えます

ちょっと気持ちが悪いので

Util.java
public int getResourceIdByString(Context context, String imgName){
    return context.getResources().getIdentifier(imgName, "drawable", context.getPackageName());
}

このくらいのメソッドが無難かもですね

ちなみに多分ですが、drawableはcolorやstringとして登録されている色や文字のリソースIDを取得することもできるかと

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

java Spring-boot

Controller

■ 宣言型

  • リクエストマッピング
  • リクエストデータの取得
  • 入力チェックの実行

■ 関数型

  • ビジネスロジックの呼び出し
  • レスポンスデータ(リソース)の取得
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

java.lang.Mathのメソッドを使ってみる

はじめに

 本記事は、筆者のアウトプット練習の一環として、数学的計算で用いられるAPIであるjava.lang.Mathのメソッドをメモしようと思います。説明等おかしいところがありましたら指摘してもらえると助かります。
参考:公式 java.lang.Math

abs

 引数にとった整数の絶対値を求める。

  int num1 = Math.abs(-1); //num1 = 1

max, min

 二つの引数のうち大きい方(小さい方)を返す。

  int num2 = Math.max(1,2); //num2 = 2
  int num3 = Math.min(1,2); //num3 = 1

random

 0.0以上で1.0より小さい、正の符号の付いたdouble値を返す。整数値にしたい場合は任意の倍数をかけてからキャストする。
※キャストした後乗算した場合、キャスト時に小数点以下が切り捨てられるため 0 のみ返却されてしまう。

  //0~1000の範囲でランダムな値をとる
  int num4 = (int)(Math.random()*1000); 

log, log10

 logは自然対数、log10は常用対数の値を返す。
Math.E : 自然対数の底$e$。定数として定義されている。Math.PI(円周率$π$)も定義されている。

  double num5 = Math.log(Math.E); //num5 = 1.0
  double num6 = Math.log10(100);  //num6 = 2.0

sin, cos, tan

 三角関数のメソッド。引数にはラジアンを入力する。弧度法の引数を入力したい場合は$\frac{π}{180}$を掛けることで変換できる。
※逆三角関数(asinなど)・双曲線関数(sinhなど)も用意されている。
(追記 10/29)弧度法で入力したい場合、Math.toRadians(double angdeg) メソッドを用いればラジアンに変換してくれる。

  double num7 = Math.sin(Math.PI/4); //1/√2 の近似値
  double num8 = Math.cos(Math.PI/4); //1/√2 の近似値
  double num9 = Math.tan(Math.toRadians(45));//1(0.9999999999999999)

pow

 第一引数を第二引数で累乗したdouble値を返す。整数値として扱う場合はキャストする。

  double num10 = Math.pow(10, 4); //num10 = 10000.0

exp, expm1

前者は自然対数の底$e$の累乗値を返し、後者は前者から1引いた数を返す。物理系や統計学で使いそう...?

  double num11 = Math.exp(2);  // e^2
  double num12 = Math.expm1(2);// e^2 -1

sqrt, cbrt

 平方根・立方根を返す。

  double num13 = Math.sqrt(9);  //num13 = 3.0
  double num14 = Math.cbrt(64); //num14 = 4.0

あとがき

...使いそうなものがまた発見出来たら更新します。

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

Collectionの要素の包含判定

目次 ⇒ Javaアルゴリズムライブラリ-Artery-サンプル

Q01_15.java
package jp.avaj.lib.algo;

import java.util.Collection;
import java.util.List;

import jp.avaj.lib.test.ArTest;
import jp.avaj.lib.test.L;

/**
ArValidatorを使用したCollectionの要素の包含判定

・ArValidatorで要素を判定しCollectionが以下の条件を満たしているかを判定する.それぞれ専用のArValidatorが用意されている
  ・条件を満足する要素が一つだけ存在する.
    ⇒ ArValidatorCollectionContainsOnlyOne
  ・条件を満足する要素が一つ以上存在する
    ⇒ ArValidatorCollectionContains
  ・すべての要素が条件を満足する.
    ⇒ ArValidatorCollectionContainsAll
  ・条件を満足する要素がまったく存在しない.
    ⇒ ArValidatorCollectionContainsNone

・本サンプルでは、List<String>に対して要素の先頭が"a"でかつ末尾が"z"であるかをチェックする.

 */
public class Q01_15 {
  public static void main(String[] args) {
    // テストケースを開始する、集計がいらなければ不必要
    ArTest.startTestCase("Q01_15");

    // テストデータ
    List<String> listZero = ArList.construct("abc0,abc1,abc2,abc3");
    List<String> listOne = ArList.construct("abc0,abc1,abc2,abc3z");
    List<String> listTwo = ArList.construct("abc0,abc1z,abc2,abc3z");
    List<String> listAll = ArList.construct("abc0z,abc1z,abc2z,abc3z");

    // 個々の要素のArValidator
    ArValidator<String> itemValidator = new ArValidator<String>() {
      @Override
      public boolean check(String value) {
        return value.startsWith("a") && value.endsWith("z");
      }
    };

    boolean result;
    // List全体をチェックするArValidator
    ArValidator<Collection<String>> validator;

    L.p("条件を満足する要素が一つだけ存在する");
    {
      validator = new ArValidatorCollectionContainsOnlyOne<String>(itemValidator);
      //
      result = validator.check(listZero);
      ArTest.isFalse("listZero","result",result);
      //
      result = validator.check(listOne);
      ArTest.isTrue("listOne","result",result);
      //
      result = validator.check(listTwo);
      ArTest.isFalse("listTwo","result",result);
      //
      result = validator.check(listAll);
      ArTest.isFalse("listAll","result",result);
    }
    L.p("条件を満足する要素が一つ以上存在する");
    {
      validator = new ArValidatorCollectionContains<String>(itemValidator);
      //
      result = validator.check(listZero);
      ArTest.isFalse("listZero","result",result);
      //
      result = validator.check(listOne);
      ArTest.isTrue("listOne","result",result);
      //
      result = validator.check(listTwo);
      ArTest.isTrue("listTwo","result",result);
      //
      result = validator.check(listAll);
      ArTest.isTrue("listAll","result",result);
    }
    L.p("すべての要素が条件を満足する");
    {
      validator = new ArValidatorCollectionContainsAll<String>(itemValidator);
      //
      result = validator.check(listZero);
      ArTest.isFalse("listZero","result",result);
      //
      result = validator.check(listOne);
      ArTest.isFalse("listOne","result",result);
      //
      result = validator.check(listTwo);
      ArTest.isFalse("listTwo","result",result);
      //
      result = validator.check(listAll);
      ArTest.isTrue("listAll","result",result);
    }
    L.p("条件を満足する要素がまったく存在しない");
    {
      validator = new ArValidatorCollectionContainsNone<String>(itemValidator);
      //
      result = validator.check(listZero);
      ArTest.isTrue("listZero","result",result);
      //
      result = validator.check(listOne);
      ArTest.isFalse("listOne","result",result);
      //
      result = validator.check(listTwo);
      ArTest.isFalse("listTwo","result",result);
      //
      result = validator.check(listAll);
      ArTest.isFalse("listAll","result",result);
    }
    //
    // テストケースを終了する、集計がいらなければ不要
    ArTest.endTestCase();
  }
}

結果は次のとおり

result.txt
**** Q01_15 start ****
条件を満足する要素が一つだけ存在する
OK listZero:result=false
OK listOne:result=true
OK listTwo:result=false
OK listAll:result=false
条件を満足する要素が一つ以上存在する
OK listZero:result=false
OK listOne:result=true
OK listTwo:result=true
OK listAll:result=true
すべての要素が条件を満足する
OK listZero:result=false
OK listOne:result=false
OK listTwo:result=false
OK listAll:result=true
条件を満足する要素がまったく存在しない
OK listZero:result=true
OK listOne:result=false
OK listTwo:result=false
OK listAll:result=false
**** Q01_15 summary ****
test count = 16
success    = 16

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

staticの有無での処理速度

static

staticって共有財産的なイメージがあるので
常にメモリの片隅に居座ってるなら、staticを使ったほうが処理速いんじゃねってイメージから試しました.

やってみよう

処理速度測定用クラス.java
package mk42;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

public class StreamProcessingTest {
    private static final List<String> list = Arrays.asList("a", "s", "k");
    public static void main(String[] args) {
        Long start = System.nanoTime();
        test();
        Long end = System.nanoTime();
        Mk42.echo.accept("Processing TIme : " + (end - start) + "ns");
        /** ----------not static---------- */
        Mk42.echo.accept("next test");
        NotStaticProcessingTest no = new NotStaticProcessingTest();
        Long start2 = System.nanoTime();
        no.test2();
        Long end2 = System.nanoTime();
        Mk42.echo.accept("Processing TIme : " + (end2 - start2) + "ns");
    }
    private static void test() {
        // twice
        list.stream().forEach(v -> execute());
        list.stream().filter(v -> !v.equals("a")).forEach(v -> qwe());
        // 終端操作内部で複数処理しても、分けても、処理時間はたいして変わらない.
    }
    private static void execute() {
        List<Integer> a = new ArrayList<Integer>();
        IntStream.range(0, 10).forEach(v -> a.add(2));
    }
    private static void qwe() {
        List<Integer> a = new ArrayList<Integer>();
        IntStream.range(0, 10000000).forEach(v -> a.add(2));
    }
}

staticでない実験用のメソッドまとめたクラス.java
package mk42;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

public class NotStaticProcessingTest {
    private static final List<String> list = Arrays.asList("a", "s", "k");
    public void run() {
        System.out.println("qwe");
    }
    public void test() {
        // onece
        list.stream().forEach(v -> {
            execute();
            if(!v.equals("a"))
                qwe();
        });
        // 終端操作内部で複数処理しても、分けても、処理時間はたいして変わらない.
    }
    public void test2() {
        // twice
        list.stream().forEach(v -> execute());
        list.stream().filter(v -> !v.equals("a")).forEach(v -> qwe());
        // 終端操作内部で複数処理しても、分けても、処理時間はたいして変わらない.
    }
    private void execute() {
        List<Integer> a = new ArrayList<Integer>();
        IntStream.range(0, 10).forEach(v -> a.add(2));
    }
    private void qwe() {
        List<Integer> a = new ArrayList<Integer>();
        IntStream.range(0, 10000000).forEach(v -> a.add(2));
    }
}

結果

static -> Processing TIme : 222787700ns
非static -> Processing TIme : 176494000ns

あっれー?と思いましたけど、複数回実験すると

static.
Processing TIme : 225677500ns
Processing TIme : 223625900ns
Processing TIme : 223150400ns
Processing TIme : 228877000ns
Processing TIme : 223187400ns
非static.
Processing TIme : 178923100ns
Processing TIme : 167760600ns
Processing TIme : 190593300ns
Processing TIme : 180728700ns
Processing TIme : 216358400ns

ちょっと平均だすのめんどくさいんでやらないですけど、そうでなく
ブレが少ないような気がしますね

staticは早いのではなく、処理速度のブレが少ないのが強みなんですかね...?

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

配列を返すメソッド-java

配列を返すメソッド(例としてint型)

int[]addArray
public static int[] addArray(int x,int y) {
        int[] array = new int[2];
            array[0] = x;
            array[1] = y;
            return array;

addArrayメソッド内で配列を宣言する。
宣言した配列をreturnで返す。

int[]addArray
            int[] array = addArray(100,200);
            for(int all:array) {
            System.out.println(all);
        }

arrayの出力

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

Java bronze試験のひっかけ問題パターン一覧!短い試験時間を奪われないための対策が大事

試験時間は短い。ひっかけに早く気づければ、さっさと次の問題に進める!

Java Bronze試験に合格しました!!
これから受けようという方にお伝えしたいのが、この試験はひっかけ問題…というか、長々コードを読ませておいて、最後の1行で「え、これコンパイルエラーになるじゃん!コード読んでた時間無駄だったじゃん!!」となる問題がけっこうあるということ。
ただでさえ65分で60問を解かなければならない厳しい試験なので、複雑なコードの問題にたっぷり時間をかけられるように、ひっかけ問題のあるあるパターンを掴んで「あ、これエラーになるやつだ」と素早く判断できれば良い結果になると思います。
実際に試験で出たものと問題集で出たもののなかから、ひっかけ問題のパターンの一覧を作ってみました。

※コメント大歓迎です!Java初心者のため、内容が間違っていないかとても心配しています。なにか気になる点があれば何でも指摘していただきたいです。

byte型、short型のひっかけ

・byte型に128より大きい整数が、short型に32767より大きい整数が代入されている

byte_short.java
byte a = 200;    //大きすぎてダメ!
short b = 50000;  //大きすぎてダメ!

byte型で扱える値は-128~127、short型で扱える値は-32768~32767です。
扱える範囲にない整数が代入されるとコンパイルエラーになります。
出題コードでは何食わぬ顔で代入されていたりするので、そんな問題を見たら迷わず「コンパイルエラーになるな」と判断しましょう。

long型、float型のひっかけ

・long型でしか扱えないリテラルの最後にlやLがない
「リテラル」というのは変数の中身のことで、多くの場合イコールの右側にあるものです。「a = 100;」だったら100がリテラルです。
long型は最後に大文字のLまたは小文字のlをつけるルールがありますが、全ての場合に付けなければいけないわけではありません。
たとえば、

Sample.java
class Sample {
  public static void main(String[] args) {
    long l = 1000;
   }
}

これはLやlが付いていなくてもOKで、

Sample.java
class Sample {
  public static void main(String[] args) {
    long l = 100000000000;
   }
}

これはコンパイルエラーになってしまいます。

違いは「リテラルがint型で扱える範囲内ならばLやlをつけなくてOK、int型で扱える範囲外ならばLやlをつけなければならない」ということです。
末尾にLやlがついていない整数は(long型と宣言していようと)最初に自動的にint型として扱われるため、int型の範囲を超えているとエラーになってしまいます。
int型で扱える範囲は-2,147,483,648 〜 2,147,483,647。「だいたいプラスマイナス21億くらい」と覚えておけば大丈夫だと思います。

・float型の小数リテラルの最後にfやFがない

Sample.java
class Sample {
  public static void main(String[] args) {
    float f = 3.14;
   }
}

float f = 3.14の部分でコンパイルエラーになってしまいます。
float型で小数を扱う場合に関しては、絶対に末尾にFかfをつけなければなりません。

if文のひっかけ

・条件式のなかに「==」ではなく「=」(※boolean型は除く)
条件式:if文で、最初の「if」の次にある括弧部分

Sample.java
class Sample {
  public static void main(String[] args) {
    int a = 1, b = 2;
    if(a = 1)                     //単体のイコールはダメ
     System.out.println("a = 1"); 
   }
}

if(a = 1)の部分でコンパイルエラーになります。
a = 1 という式は「変数aに1を代入する」という意味ですが、
a == 1 という式は「aと1は等しいかどうか比較する」という意味で、式の値がtrueかfalseに必ず定まるというものです。if文は代入ではなく比較をすることでその後の処理を判断するものなので、==を使わなければいけません。

ただしboolean型の場合は特殊で、

boolean.java
boolean b = true;
if(b = false)
  System.out.println("b is false");

という風に単独の「=」を使って代入もできるし、

boolean.java
boolean b = true;
if(b == false)
  System.out.println("b is false");

という風に「==」を使って、すでに宣言された変数とtrue,falseを比較することもできます。

↑初投稿時、「boolean型では『=』しか使わない」という誤った説明をしていましたが、コメントでご指摘をいただき訂正いたしました。申し訳ございません。
正しくは、代入の場合「=」、比較の場合は「==」と両方使えます。

演算子のひっかけ

・ありえない演算子が使われている(and,orなど)

Sample.java
class Sample {
  public static void main(String[] args) {
    int x = 10, y = 20:
    if (x == 10 and y == 20) {}
    if (x == 10 or  y == 20) {}
  }
}

上の例の2つのif文はどちらもコンパイルエラーになります。
Javaの関係演算子のなかに、英単語の「and」や「or」はありません。

elseのひっかけ

・elseのあとに条件式がついている

Sample.java
class Sample {
  public static void main(String[] args) {
    int x = 0, y = 5;
    if (x++ < 0)
      System.out.println("1 ");
    else if (x < y)
      System.out.println("2 ");
    else (y == 5)               //ここでエラーになる
      System.out.println("3 ");
  }
}

else(y == 5)の部分でコンパイルエラー
elseは「if文の条件がどれも当てはまらない場合」という意味なので、そこに条件式をつけることはできません。if文が問題に出てきたら、まず最後のelseの部分を確認すると良いと思います。

文字列に「-=」(引き算)が使われている

Sample.java
class Sample {
  public static void main(String[] args) {
    String str = "Hi!";
    String str2 = "How are you?";
    str += str2;
    str -= str2;      //ここでエラーになる
  System.out.println(str);
  }
}

str -= str2 の部分でコンパイルエラー
String型には+演算子を使うことはできますが、-演算子は使えません。

for文のひっかけ

・スコープ範囲外にSystem.out.println()がある

Sample.java
class Sample {
  public static void main(String[] args) {
    for (int i = 0; i < 5; i++) {
      if (i > 3) break;
    }
   System.out.println(i);
  }
}

これはコンパイルエラーになってしまいます。
最後に変数iの値を出力する命令(System.out.println)が出てきますが、
for文内で宣言された変数は、for文の外から参照することができません。
よって、「System.out.println(i);」は宣言されていない変数を出力する命令になってしまうのでコンパイルエラーとなってしまうのです。

なお、変数をfor文の外で宣言している場合、エラーにはなりません。

Sample.java
class Sample {
  public static void main(String[] args) {
    int num = 1;
    for (num = 0; num < 3; ++num) {
       num *= 2;
    }
    System.out.println(num);
  }
}

この場合は、for文以外のところ(3行目)で「int num = 1;」として変数numをしっかり宣言しています。for文の中でnumに対して行われた値の変更は、3行目のnumにも保存されます。なのでSystem.out.println(num)を実行し、3という出力を得ることができます。

do-while文のひっかけ

・「do while (条件式) {処理内容}」というありえない文法が使われている
do-while文の定義は、
do {処理内容} while (条件式);です。do whileと単語が連なることはあり得ません。

switch文のひっかけ

・式にlong型が指定されている(ほかのパターンもあるかも)
式というのは、switch文の最初の「switch」の直後の括弧部分です。

Sample.java
class Sample {
  public static void main(String[] args) {
    long i = 0;
    switch(i){
       case 0:  System.out.println("case0 ");
       case 10: System.out.println("case10 ");
    }
  }
}

式に入れられる値は、byte,char,short,int,String,enum の型のものしか認められません。上の例では適用できないlong型の値を式に入れているためコンパイルエラーになります。long型に限らず、上で挙げた6種類の型以外のものはすべてコンパイルエラーになるので、switch文が出たら注意してください。

staticメソッドのひっかけ

・staticなメソッドが、非staticなメソッドを呼び出している

Sample.java
class Sample {
  static int num;
  void methodA() {num++;}
  public static void main(String[] args) {
    methodA();
    System.out.println(num);
  }
}

宣言時にstatic修飾子がついたメソッドをstaticメソッドと言います。
staticメソッドは、非staticメソッド(または非static変数)を呼び出すことができません。
上の例では、2行目にあるmethodAメソッドは宣言に「static」という言葉がないため非staticメソッド、4行目にあるmainメソッドは宣言に「public static void」とあるためstaticメソッドです。
5行目でmainメソッド(staticメソッド)からmethodAメソッド(非staticメソッド)を呼び出しているためコンパイルエラーになります。

thisのひっかけ

・コンストラクタ定義の中で、先頭行ではない場所で記述されている

Constructure.java
//コンストラクタ部分のみ記述
Foo(int b) {
   this.b = b;
}
Foo(int a, int b) {
   this.a = a++;
   this(++b);
   //先頭行にないのでコンパイルエラー
}
public static void main(String[] args) {
   int a = 3;
   int b = 5;
   Foo obj = new Foo(a,b);
}

コンストラクタ内で「this(引数)」とすると、その引数の個数やデータ型に応じてまた別のコンストラクタを呼び出して処理をすることができます。そのときのルールとして、「this(引数)」はコンストラクタ定義の{}内の先頭行に書かなければいけません
たとえば上の例では、インスタンス変数objが持つaとbという二つの引数に対して、aに関しては4行目から始まるコンストラクタの処理を、bに関しては1行目から始まるコンストラクタの処理をしたいのでthis(++b)としていますが、このように他のコンストラクタに渡してしまいたい引数がある場合は先頭行で真っ先に宣言しなければいけません。
よって、

Constructure.java
Foo(int a, int b) {
   this(++b);
   //入れ替えて先頭行にしたのでOK
   this.a = a++;
}

このように入れ替えればコンパイルに成功し、正しく実行されます。

以上です。
添削・意見を大歓迎していますので、記載内容に間違いがあればご指摘ください!
受験を考えていらっしゃる方の助けになれれば幸いです。

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