- 投稿日:2019-07-07T23:53:39+09:00
Java SE 8 Silver 資格取得に向けての日記
Java SE 8 Silver 資格取得に向けて
シンプルにまとめますと
自分の足元を固めていきたいと思い、また会社から報酬金が出ると聞き、
資格取得しようと決めました。なぜ投稿する?
先日、ITパスポートを取得しましたが、(625点、ギリギリでした、、)
モチベーションの維持がなかなか難しく、
人の目に触れるようにするとできるかな、と思い投稿を決めました。
⇒モチベーション維持のため!よろしければアドバイスや激励のおことばいただけますと嬉しいです。
取得したい時期
2019年8月中
その時点でむずかしそうであればまた考えようと思っています。学習方法
会社での研修
・Javaの道
Javaの道:先輩社員のおすすめのサイト
この基本の読解
・北ソフト工房の練習問題
北ソフト工房のJava練習問題集自分での学習
・いわゆる黒本の読解
黒本とは?(Amazonへのリンク)
・progate(無料でできる範囲まで)
progate
- 投稿日:2019-07-07T23:19:28+09:00
【Java】Fizz Buzz問題を解いてみる
はじめに
仕事でJavaを触る機会がすっかり無くなってきたので、Javaを使って様々な方法で「Fizz Buzz問題」を解く方法を考えてみました。
Fizz Buzzとは
- 英語圏で長距離ドライブ中や飲み会の時に行われる言葉遊びのこと。
- 最初のプレイヤーは「1」と数字を読み上げる。
- 以降のプレイヤーは、次の数字を読み上げる。
- ただし、3で割り切れる場合は「Fizz」、5で割り切れる場合は「Buzz」、3と5の両方で割り切れる場合は「Fizz Buzz」と発言する。
For文を用いた一般的な方法
FizzBuzz.java/** * for文を使った一般的な方法。 * @param end FizzBuzzを終える数。 */ public static void useForLoop(int end) { for (int i=1; i<=end; i++) { if (i%3==0 && i%5==0) { System.out.println("Fizz Buzz"); } else if (i%3==0) { System.out.println("Fizz"); } else if (i%5==0) { System.out.println("Buzz"); } else { System.out.println(i); } } }For文+三項演算子を用いた方法
FizzBuzz.java/** * 三項演算子を活用した方法。 * @param end FizzBuzzを終える数。 */ public static void useForLoopWithTertiaryOperator(int end) { for (int i=1; i<=end; i++) { System.out.println( (i%3==0 && i%5==0) ? "Fizz Buzz" : (i%3==0) ? "Fizz" : (i%5==0) ? "Buzz" : i ); } }Stream APIを用いた方法
FizzBuzz.javaimport java.util.stream.IntStream; ... /** * Stream APIを活用した方法。 * @param end FizzBuzzを終える数。 */ public static void useStreamAPI(int end) { IntStream.rangeClosed(1, end) .mapToObj(i -> (i%3==0 && i%5==0) ? "Fizz Buzz" : (i%3==0) ? "Fizz" : (i%5==0) ? "Buzz" : i) .forEach(msg -> System.out.println(msg)); }まとめ
- 一番古臭い書き方である「For文を用いた一般的な方法」が、一番見やすく理解しやすい感じ。
- 三項演算子を重ねると、どうしても見づらくなってしまうのが難点。
- Java Silver SE 8の試験では、「多重の三項演算子」に関する問題が出てきましたが、実際に使おうとすると可読性に問題があると改めて感じました。
- ちょっとした頭の体操をしつつ、さらにStream APIの復習になって一石二鳥。
- 最近は業務でJavaから離れているので、Stream APIを触る機会もどんどん減っている気が...
- 少し前に調べた、rangeClosedメソッドの情報も役立ちました。
- 投稿日:2019-07-07T22:46:36+09:00
Nginx+SpringBootのオウム返しLineBotをVPSで作る
VPS環境でNginx + SpringBootの、オウム返しするLineBotを作成しました。
環境構成
・VPS:Conoha(https://www.conoha.jp/)
・OS:CentOS7
・SSL証明書:Let’s Encrypt
・Nginx 1.12.2
・SpringBoot 2.1.6https化
LineBotのWebhookは、httpsのURLのみ有効です。
VPSはConohaで、独自ドメインは別ドメインサイトで取得しました。
ここでは独自ドメインの取得方法や設定方法は割愛します。SSL証明書は以下を参考に取得しました。
また以下の記事の中でNginxをインストールしました。Let’s EncryptのSSL証明書で、安全なウェブサイトを公開
https://knowledge.sakura.ad.jp/5573/Line Developersの設定と確認
Line Developersでチャンネル基本設定を開き、WebHookなどの設定を行います。
ChannnelSecretは後の手順で使用するので、メモを控えておいてください。
アクセストークンは再発行をしておき、表示されたアクセストークンは、後の手順で使用するためメモに控えておいてください。
Webhook送信は「利用する」に変更
Webhook URLのグレーで隠れている部分は取得したドメイン名を指定してください。
自動応答メッセージは「利用しない」を選択し、
友だち追加時のあいさつは「利用しない」を選択してください。
SpringBootプロジェクト作成
1.Spring Initializrにてプロジェクトを作成
https://start.spring.io/
・Project:Gradle Poject
・Language:Java
・Spring Boot:2.1.6
・Project Metadata
・Group:com.example
・Artifact:linebot
2.STSにて、作成したプロジェクトをインポートし、line-bot-javaのサンプル(echo)をLinebotApplication.javaにコピペします。
この時点で、linebotのライブラリが入っていないため、コンパイルエラーが発生しますが、あとの手順で解消します。com/example/linebot/LinebotApplication.java@SpringBootApplication @LineMessageHandler public class LinebotApplication { public static void main(String[] args) { SpringApplication.run(LinebotApplication.class, args); } @EventMapping public Message handleTextMessageEvent(MessageEvent<TextMessageContent> event) { System.out.println("event: " + event); final String originalMessageText = event.getMessage().getText(); return new TextMessage(originalMessageText); } @EventMapping public void handleDefaultMessageEvent(Event event) { System.out.println("event: " + event); } }3.build.gradleを編集。初期の状態から下記に変更し、Jarにビルドするようにしています。
build.gradleplugins { id 'org.springframework.boot' version '2.1.6.RELEASE' id 'java' } apply plugin: 'io.spring.dependency-management' apply plugin: 'java' group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter' testImplementation 'org.springframework.boot:spring-boot-starter-test' compile 'com.linecorp.bot:line-bot-spring-boot:2.7.0' } jar { manifest { attributes 'Main-Class': 'LinebotApplication' } }4.Gradle Projectをリフレッシュ
前手順で、「line-bot-spring-boot:2.7.0」をGradleに追加したので、GradleProjectをリフレッシュして、Jarを取り込みます。(これでJavaのコンパイルエラーがなくなります。)プロジェクトを右クリック -> Gradle -> Refresh Gradle Projectをクリック
5.Spring Bootのapplication.propertiesに下記3行を追加
※channelSecretとchannelTokenはシングルクォーテーションで囲まないことsrc/main/resources/application.propertiesline.bot.channelSecret = XXX(Line DevelopersのChannnelSecret) line.bot.channelToken = XXX(Line Developersのアクセストークン) line.bot.handler.path = /callback次の手順「NginxとSpringBootの連携」でもapplication.propertiesを編集するため、まだビルドは行いません
NginxとSpringBootの連携
NginxとSpringBootと連携します。
連携方法は以下を参考しました。Spring bootでSSL(HTTPS)を有効にするならnginxを使え
https://qiita.com/keigohtr/items/5b2b423fe0e9da027db61.記事内のssl.confは下記のように変更しました。
※example.comは独自ドメインに変更してください。/etc/nginx/conf.d/ssl.confserver { listen 80; listen [::]:80; return 301 https://$host$request_uri; } upstream spring-boot { server 127.0.0.1:8443; } server { listen 443 ssl; listen [::]:443 ssl; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl on; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/ssl/dhparam.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!DSS; ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem; resolver 8.8.8.8; add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;'; server_name example.com; location / { proxy_pass http://spring-boot; } }2.上記記事内のapplication.propertiesの内容を追記しています。
最終的にapplication.propertiesは以下となります。src/main/resources/application.propertiesline.bot.channelSecret = XXX line.bot.channelToken = XXX line.bot.handler.path = /callback server.port=8443 #server.ssl.key-store=keystore.p12 #server.ssl.key-store-password=mypassword #server.ssl.keyStoreType=PKCS12 #server.ssl.keyAlias=tomcat endpoints.enabled=false management.add-application-context-header=falseSpringBootをGradleでJarにビルド
プロジェクトを右クリック -> Run As -> Gradle Buildを行えなかったため、以下の方法でSTSからJarへのビルドを行いました
1プロジェクトを右クリック -> Run As -> Run Configuration...をクリック
2.Gradle Projectをダブルクリック -> New_configrationを選択し、Gradle Tasks:に「build」を入力、Workspalce...をクリック
3.Select Projectでビルド対象プロジェクトを選択
4.Working Directoryにパスを設定されたらRunをクリック
5.ビルドが成功したら、build/libsにjarが生成されます。
SpringBootをVPS上で起動
作成したjarをサーバの場所はユーザディレクトリ(/home/[user名])にアップロードして、下記コマンドを実行し、Spring Bootを立ち上げします
sudo java -jar linebot-0.0.1-SNAPSHOT.jar接続確認
Line Developersにて、設定したWebhook URLの接続確認を行います。
「成功しました。」と表示されれば、これまでの設定が正しく行われて、LineBotからVPSへの接続が確立されています。
Lineアプリで確認
Lineアプリから作成したチャンネルあてにメッセージを送信すると、送信したメッセージと同じメッセージが返ってきます。
これでオウム返しbotができました。
- 投稿日:2019-07-07T16:31:51+09:00
SquashTMのビルドの方法と日本語対応の仕方
SquashTMとは
SquashTMはWebベースのテスト管理ツールです。
多言語化対応はしてますが、残念ながら日本語対応はしてません。
また、当然の権利のように、文字化けしたりします。今回はSquashTMをビルドして文字化けを修正したり日本語対応の方法を調べたりします。
ビルドの方法
公式にいくつか文章はありますが、古いです。
すごく古い
https://sites.google.com/a/henix.fr/wiki-squash-tm/developer/how-to-install-squashtm-project-into-eclipse
※1.13以降はOSGi Frameworkはいらない。代りにSpringIDEがいるちょっと古い
https://bitbucket.org/nx/squashtest-tm/wiki/devguide/HowToInstallInIDE.md#!install-in-eclipse
※1.19になるとJDK7はサポートしていないが、JDK7で動くような記載になっている。事前準備
下記を用意します。
・Java8以上
・eclipse
・mvn3.3以上
・ToroiseHg (Gitのような分散構成管理ツール)eclipceに入れるプラグインは以下の通り
・springIDE
ビルドと実行方法
ソースコードの取得からmvn installまで
cd myeclipseworkspace hg clone https://bitbucket.org/nx/squashtest-tm cd squashtest-tm mvn clean install -DskipTests -DskipITs # 以下は不要の可能性がある cd provision mvn clean install -DskipTestscom.mycila:license-maven-pluginでエラーが出る場合
以下のようなエラーが発生する場合がある。
Failed to execute goal com.mycila:license-maven-plugin:2.11:check"この場合はルートフォルダで以下のコマンドを実行する。
mvn license:formatprovisionでエラーがでる場合
provisionのmvn installで以下のエラーが発生する場合がある。
Non-resolvable parent POM for org.squashtest.tm:squash-tm-provision:[unknown-version]: Could not find artifact org.squashtest.tm:squash-tm:pom:1.19.0.RC3-SNAPSHOT and 'parent.relativePath' points at no local POMこれはprovisionフォルダのpom.xml中のparentと親フォルダのpom.xmlの整合性が取れていない場合に発生する。
2019/7/6時点では以下のような修正が必要だったparent/pom.xml<parent> <groupId>org.squashtest.tm</groupId> <artifactId>squash-tm</artifactId> <version>1.19.0.RELEASE</version> <<<<<< ここのVersionが親と食い違っていた <relativePath>../pom.xml</relativePath> </parent>eclipseでの操作
eclipseで下記の操作を行う
プロジェクトのインポート
1 メニューから[ファイル]>[インポート]を選択
2 [Maven]>[既存のMavenプロジェクト]を背くん炊く
3 「hg clone」で作成したフォルダを選択provisionモジュールをEclipseに導入
この作業は最新では不要の可能性がある。
1 メニューから[ウィンドウ]>[設定]を選択する。
2 [プラグイン開発]>[ターゲット・プラットフォーム]を選択して「追加」ボタンを押下
3 「空のターゲット定義で開始」を選択
4 ターゲットコンテンツにて「追加」ボタンを押下
5 ディレクトリーを選択する。
6 ロケーションに「squashtest-tm/provision/target/eclipse-provision/bundles」を入力する。
7 ターゲットコンテンツが追加されるので、引数タブでそれぞれ下記の値を入力する。
プログラム引数 :-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -consoleVM 引数 :
-Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dorg.osgi.framework.system.packages.extra=com.sun.org.apache.xalan.internal.res,com.sun.org.apache.xml.internal.utils, com.sun.org.apache.xpath.internal,com.sun.org.apache.xpath.internal.jaxp,com.sun.org.apache.xpath.internal.objects,com.sun.javadoc, com.sun.tools.javadoc,javax.xml.namespace -Dbundles.configuration.location="${workspace_loc}/squashtest-tm/provision/target/config" -Dorg.osgi.service.http.port=9090 -Dorg.osgi.service.http.port.secure=9443
- 完了後、今追加したターゲット定義にチェックを付ける
Spring IDEプラグインの設定
1 メニューから[実行]>[実行構成]を選択する
2 実行構成画面にて[Spring Bootアプリケーション]を右クリックして「新規」ボタンを押下
3 それぞれのタブで値を入力する
SpringBoot タブ
・プロジェクト:tm.web
・メイン型:org.squashtest.tm.SquashTm
・プロファイル:h2,devプログラム引数:-XX:MaxPermSize=256m -Xmx1024m
①「ユーザ・エントリー」を選択後、「拡張ボタン」を押下
②「フォルダの追加」を選択
③「tm.web/target/wro4j-spring-boot」を入力する実行方法
Spring IDEの設定で実行構成を設定しているので、そこで実行ボタンを押下する。
その後、ブラウザから以下にアクセスする。
(http://localhost:8080/squash起動中にエラーになる場合の対応
起動が失敗することがあった。この場合は以下を試してみた。
なお、ログで例外が出ていても動作はしている模様
データベースを一回消してみる
・tm\data\squash-tm.mv.db
・tm\data\squash-tm.trace.db「mvn clean install」を行ってみる。
色々修正してみる
「Attach Test Cases」画面での文字化けの修正をしてみる
テストスィートでテストケースを関連付ける際、日本語文字が文字化けする。
原因はjspにcontentTypeが設定していないため。
以下のように修正する。tm\tm.web\src\main\webapp\WEB-INF\jsp\page\campaign-workspace\show-test-suite-test-plan-manager.jsp<%@ taglib prefix="authz" tagdir="/WEB-INF/tags/authz"%> ↓これを追加 <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <c:url var="testSuiteUrl" value="/test-suites/${ testSuite.id }" />結構化けているページがあるのでjspについてencodeが明示されているか見直した方がいいが、error.jspだけは、文字コードが明示されていたので、そのままのエンコードにしておいた。
なお、全体的に日本語文字が化ける場合は、データベースを作成時にミスをしていてutf8に対応していないと考えられる。
日本語メッセージを追加してみる。
SquashTMはメッセージリソースをコピーすることで多言語対応が可能である。
1.tm\tm.web\src\main\webapp\WEB-INF\messages\tm\messages.properties をコピーして、messages_ja.propertiesを作成する。
2.Limyプロパティエディターで開く
3.日本語に置き換える
修正したら「tm-web」を「mvn install」したのち再起動。なお、言語の切り替えはブラウザの規定の言語によって行われる。
CentOS7の場合の置き換えと再起動方法
作成したwarをサーバーに配置する方法は以下の通り
1 tm/tm.web/target/tm.webXXXXXXX.warをsquash-tm.warに改名
2 「sudo service squash-tm stop」でサービスをとめる
3 CentOS7の場合は「 /usr/lib/squash-tm/bundles/」にコピー
4 「sudo service squash-tm stop」でサービスを再開ちなみにログは以下にあるのでtail -f あたりで監視しとくといい。
/var/log/squash-tm/squash-tm.logさいごに
これでSquashTMでバグがでても自力で直せるようになりました。
バグがでても安心だな!(慢心)
- 投稿日:2019-07-07T15:59:49+09:00
Project EulerをJava解いてみる
はじめに
取り急ぎ投下
Project Eulerへのリンク
日本語のリンクはこっちProblem 1
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
Problem1.javapublic class Problem1{ public static void main(String[] args){ int sum = 0; for(int i=3; i<=1000; i++){ if(i%3 == 0 || i%5 == 0){ sum += i; } } System.out.printf("The answer is %d.\n", sum); } }実行結果The answer is 233168.Problem 2
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Problem2.javapublic class Problem2 { public static void main(String[] args){ final int MAX_VALUE = 4000000; int value1 = 1; int value2 = 1; int currentValue = value1 + value2; int sumOfValues = 0; // initialized by zero while(currentValue < MAX_VALUE){ if(currentValue % 2 == 0) { sumOfValues += currentValue; } value1 = value2; value2 = currentValue; currentValue = value1 + value2; } System.out.printf("The answer is %d.\n", sumOfValues); } }実行結果The answer is 4613732.Problem 3
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
Problem3.javapublic class Problem3 { public static void main(String[] args) { Long num = 600851475143L; for(int divisor=2; divisor<=Math.sqrt(num); divisor++) { while(true) { if(num%divisor == 0) { num /= divisor; }else{ break; } } } System.out.printf("The answer is %d.\n", num); } }実行結果The answer is 6857.Problem 4
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers.
Problem4.javapublic class Problem4 { public static void main(String[] args) { final int MAX_NUM = 999; int numberOfLargestPalindrome = 0; for(int i=MAX_NUM; i>0; i--) { for(int j=MAX_NUM; j>i; j--) { if(checkPalindrome(String.valueOf(i*j))){ numberOfLargestPalindrome = Math.max(i*j, numberOfLargestPalindrome); break; } } } System.out.printf("The answer is %d.\n", numberOfLargestPalindrome); } public static boolean checkPalindrome(String str) { for(int i=0; i<str.length()/2; i++) { if(str.charAt(i) != str.charAt(str.length() - 1 - i)) { return false; } } return true; } }実行結果The answer is 906609.Problem 5
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
Problem5.javapublic class Problem5 { public static void main(String[] args) { int minNum = 2; int maxNum = 20; int commonMul = 1; for(int i=minNum; i<=maxNum; i++) { commonMul = getLCM(commonMul, i); } System.out.printf("The answer is %d.\n", commonMul); } /* * 2つの値の最小公倍数を出力するメソッド * 最小公倍数(LCM: Latest common multiple) */ public static int getLCM(int x, int y) { return x*(y/getGCD(x, y)); // overflow taisaku... } /* * 2つの値の最大公約数を出力するメソッド * ユークリッドの互除法を用いて求める * 最大公約数(GCD: Greatest common divisor) */ public static int getGCD(int x, int y) { while(y != 0) { int temp = x; x = y; y = temp%y; } return x; } }実行結果The answer is 232792560.Problem 6
The sum of the squares of the first ten natural numbers is,
$$1^2 + 2^2 + ... + 10^2 = 385$$
The square of the sum of the first ten natural numbers is,
$$(1 + 2 + ... + 10)^2 = 55^2 = 3025$$
Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 − 385 = 2640.
Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.
Problem6.javapublic class Problem6 { public static void main(String[] args) { final int MAX_NUM = 100; int sumOfSquares = 0; int squareOfSum = 0; for(int i=1; i<=MAX_NUM; i++) { sumOfSquares += i*i; squareOfSum += i; } squareOfSum *= squareOfSum; System.out.printf("The answer is %d.\n", squareOfSum-sumOfSquares); } }実行結果The answer is 25164150.Problem 7
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
What is the 10 001st prime number?
Problem7.javaimport java.util.ArrayList; public class Problem7 { public static void main(String[] args) { final int NUM = 10001; ArrayList<Integer> primeNumbers = new ArrayList<Integer>(); primeNumbers.add(2); int number = 3; while(primeNumbers.size() < NUM) { if(checkPrimeNumber(number, primeNumbers)) { primeNumbers.add(number); } number += 2; } System.out.printf("The answer is %d.\n", primeNumbers.get(NUM-1)); } public static boolean checkPrimeNumber(int target, ArrayList<Integer> divisors) { for(int divisor: divisors) { if(target%divisor == 0) { return false; } } return true; } }実行結果The answer is 104743.Problem 8
The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?
Problem8.javapublic class Problem8 { public static void main(String[] args) { String src = "73167176531330624919225119674426574742355349194934\r\n" + " 96983520312774506326239578318016984801869478851843\r\n" + " 85861560789112949495459501737958331952853208805511\r\n" + " 12540698747158523863050715693290963295227443043557\r\n" + " 66896648950445244523161731856403098711121722383113\r\n" + " 62229893423380308135336276614282806444486645238749\r\n" + " 30358907296290491560440772390713810515859307960866\r\n" + " 70172427121883998797908792274921901699720888093776\r\n" + " 65727333001053367881220235421809751254540594752243\r\n" + " 52584907711670556013604839586446706324415722155397\r\n" + " 53697817977846174064955149290862569321978468622482\r\n" + " 83972241375657056057490261407972968652414535100474\r\n" + " 82166370484403199890008895243450658541227588666881\r\n" + " 16427171479924442928230863465674813919123162824586\r\n" + " 17866458359124566529476545682848912883142607690042\r\n" + " 24219022671055626321111109370544217506941658960408\r\n" + " 07198403850962455444362981230987879927244284909188\r\n" + " 84580156166097919133875499200524063689912560717606\r\n" + " 05886116467109405077541002256983155200055935729725\r\n" + " 71636269561882670428252483600823257530420752963450"; final int NUM = 13; final int DIGIT = 1000; long greatestProduct = 0; // initialize by zero src = src.replace("\r\n ", ""); String[] strAry = src.split(""); int[] intAry = new int[DIGIT]; for(int i=0; i<DIGIT; i++) { intAry[i] = Integer.valueOf(strAry[i]).intValue(); } for(int startIndex=0; startIndex<DIGIT-NUM; startIndex++) { long prod = 1L; for(int offset=0; offset<NUM; offset++) { prod *= intAry[startIndex + offset]; } greatestProduct = Math.max(prod, greatestProduct); } System.out.printf("The answer is %d.\n", greatestProduct); } }実行結果The answer is 23514624000.Problem 9
A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,
a2 + b2 = c2
For example, 3^2 + 4^2 = 9 + 16 = 25 = 5^2 .
There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc.Problem9.javapublic class Problem9 { public static void main(String[] args) { for(int a = 1; a < 333; a++) { for(int b = a+1; b < 1000-a; b++) { int c = 1000 - a - b; if (Math.pow(c, 2) == Math.pow(a, 2) + Math.pow(b, 2)) { System.out.printf("The answer is %d.\n", (a*b*c)); break; } } } } }実行結果The answer is 31875000.Problem 10
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.
Problem10.javaimport java.util.Arrays; public class Problem10 { public static void main(String[] args) { int MAX_NUM = 2000000; printPrimeNumber(maxNum); } public static void printPrimeNumber(int maxNum) { boolean[] numAry = new boolean[maxNum+1]; Arrays.fill(numAry, true); numAry[0] = false; numAry[1] = false; double sqrt = Math.sqrt(maxNum); for(int i=2; i<=sqrt; i++){ if(numAry[i]){ for(int j=i*2; j<=maxNum; j+=i) { numAry[j] = false; } } } long sum = 0L; for(int i=2; i<=maxNum; i++) { if(numAry[i]) { //System.out.println(i); sum += i; } } System.out.printf("The answer is %d.\n", sum); } }実行結果The answer is 142913828922.Problem 11
In the 20×20 grid below, four numbers along a diagonal line have been marked in red.
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48The product of these numbers is 26 × 63 × 78 × 14 = 1788696.
What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in the 20×20 grid?
Problem11.javapublic class Problem11 { public static void main(String[] args) { String src = "08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08\r\n" + " 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00\r\n" + " 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65\r\n" + " 52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91\r\n" + " 22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80\r\n" + " 24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50\r\n" + " 32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70\r\n" + " 67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21\r\n" + " 24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72\r\n" + " 21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95\r\n" + " 78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92\r\n" + " 16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57\r\n" + " 86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58\r\n" + " 19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40\r\n" + " 04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66\r\n" + " 88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69\r\n" + " 04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36\r\n" + " 20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16\r\n" + " 20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54\r\n" + " 01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48"; final int ROW = 20; final int COLUMN = 20; final int NUM = 4; int greatestProduct = 0; // initialize by zero src = src.replace("\r\n", ""); // convert String type to String[] array (one-dimensional array of String type) String[] strAry = src.split(" "); // convert String[] array to int[][] array (two-dimensional array of integer type) int[][] intAry = new int[ROW][COLUMN]; for(int i=0; i<strAry.length; i++) { intAry[i/ROW][i%COLUMN] = Integer.valueOf(strAry[i]).intValue(); } /* * calculate greatest product *** rightProd: product of NUM numbers from intAry[currentRow][currenCol] to right. *** downProd: ~ to downward. *** ldProd: ~ to left downward. *** rdProd: ~ to right downward. */ for(int currentRow=0; currentRow<ROW; currentRow++) { for(int currentCol=0; currentCol<COLUMN; currentCol++) { int rightProd = 1, downProd = 1, rdProd = 1, ldProd = 1; for(int offset=0; offset<NUM; offset++) { if(currentRow + NUM < ROW) { rightProd *= intAry[currentRow + offset][currentCol]; } if(currentCol + NUM < COLUMN) { downProd *= intAry[currentRow][currentCol + offset]; } if(currentRow + NUM < ROW && currentCol + NUM < COLUMN) { rdProd *= intAry[currentRow + offset][currentCol + offset]; } if(currentRow - NUM >= 0 && currentCol + NUM < COLUMN) { ldProd *= intAry[currentRow - offset][currentCol + offset]; } } greatestProduct = calcMaxValueInFiveInteger(rightProd, downProd, rdProd, ldProd, greatestProduct); } } // display the answer System.out.printf("The answer is %d.\n", greatestProduct); } // Method for returning the greatest value in five values public static int calcMaxValueInFiveInteger(int a, int b, int c, int d, int e) { int[] ary = {a, b, c, d, e}; int maxValue = 0; for(int n: ary) { maxValue = Math.max(maxValue, n); } return maxValue; } }実行結果The answer is 70600674.Problem 12
The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number >would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
Problem12.javapublic class Problem12 { public static void main(String[] args) { final int NUM = 500; int triangularNum = 1; int term = 2; while(countDivisor(triangularNum) <= NUM) { triangularNum += term; term++; } System.out.printf("The answer is %d.\n", triangularNum); } public static int countDivisor(int target) { double sqrt = Math.sqrt(target); int count = 0; for(int div=1; div<sqrt; div++) { if(target%div == 0) count++; } return count*2; } }実行結果The answer is 76576500.Problem 13
Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.
37107287533902102798797998220837590246510135740250
46376937677490009712648124896970078050417018260538
74324986199524741059474233309513058123726617309629
...
53503534226472524250874054075591789781264330331690Problem13.javaimport java.math.BigInteger; public class Problem13 { public static void main(String[] args) { String src = getSrc(); src = src.replace("\r\n", ""); String[] strAry = src.split(" "); BigInteger sum = new BigInteger("0"); for(String str: strAry) { sum = sum.add(new BigInteger(str)); } String answer = String.valueOf(sum).substring(0, 10); System.out.printf("The answer is %s.\n", answer); } // Too long!! public static String getSrc() { return "37107287533902102798797998220837590246510135740250\r\n" + " 46376937677490009712648124896970078050417018260538\r\n" + " 74324986199524741059474233309513058123726617309629\r\n" + .............. " 53503534226472524250874054075591789781264330331690"; } }実行結果The answer is 5537376230.Problem 14
The following iterative sequence is defined for the set of positive integers:
n → n/2 (n is even)
n → 3n + 1 (n is odd)Using the rule above and starting with 13, we generate the following sequence:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.
Which starting number, under one million, produces the longest chain?
NOTE: Once the chain starts the terms are allowed to go above one million.
Problem14.javaimport java.util.HashMap; public class Problem14 { public static void main(String[] args) { final int MAX_NUM = 1000000; Long numWithLongestChain = 1L; //initialized by one HashMap<Long, Long> step = new HashMap<Long, Long>(); step.put(1L, 1L); for(Long startNum=2L; startNum<MAX_NUM; startNum++) { if(step.get(startNum) == null){ calcCollatzSeq(startNum, step); } if (step.get(numWithLongestChain) < step.get(startNum)) { numWithLongestChain = startNum; } } System.out.printf("The answer is %d.\n", numWithLongestChain); } public static void calcCollatzSeq(Long currentNum, HashMap<Long, Long> step){ Long nextNum = calcNextNum(currentNum); if(step.get(nextNum) == null) { calcCollatzSeq(nextNum, step); } step.put(currentNum, step.get(nextNum)+1L); } public static Long calcNextNum(Long num) { if(num%2 == 0) { return num/2; }else{ return num*3+1; } } }実行結果The answer is 837799.Problem 15
Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 routes to the bottom right corner.
How many such routes are there through a 20×20 grid?
Problem15.javaimport java.math.BigInteger; public class Problem15 { public static void main(String[] args) { int hGrid = 20; int vGrid = 20; BigInteger numRoutes = new BigInteger("1"); for(int i=hGrid+vGrid; i>1; i--) { String sInt = String.valueOf(i); numRoutes = numRoutes.multiply(new BigInteger(sInt)); if (i <= hGrid) { numRoutes = numRoutes.divide(new BigInteger(sInt)); } if (i <= vGrid) { numRoutes = numRoutes.divide(new BigInteger(sInt)); } } System.out.printf("The answer is %d.\n", numRoutes); } }実行結果The answer is 137846528820.Problem 16
$2^{15}$ = 32768 and the sum of its digits is $3 + 2 + 7 + 6 + 8 = 26$.
What is the sum of the digits of the number $21000$?
Problem16import java.math.BigInteger; public class Problem16 { public static void main(String[] args) { final int NUM = 2; final int POWER = 1000; int sumOfDigit = 0; // initialized by zero BigInteger src = new BigInteger(String.valueOf(NUM)); src = src.pow(POWER); String[] strAry = src.toString().split(""); for(String s: strAry) { sumOfDigit += Integer.valueOf(s); } System.out.printf("The answer is %d.\n", sumOfDigit); } }実行結果The answer is 1366.Problem 17
If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.
If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?
NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage.
Problem17.javaimport java.util.HashMap; public class Problem17 { public static void main(String[] args) { HashMap<Integer, String> words = new HashMap<>(); words.put(0, ""); words.put(1, "one"); words.put(2, "two"); words.put(3, "three"); words.put(4, "four"); words.put(5, "five"); words.put(6, "six"); words.put(7, "seven"); words.put(8, "eight"); words.put(9, "nine"); words.put(10, "ten"); words.put(11, "eleven"); words.put(12, "twelve"); words.put(13, "thirteen"); words.put(14, "fourteen"); words.put(15, "fifteen"); words.put(16, "sixteen"); words.put(17, "seventeen"); words.put(18, "eighteen"); words.put(19, "nineteen"); words.put(20, "twenty"); words.put(30, "thirty"); words.put(40, "forty"); words.put(50, "fifty"); words.put(60, "sixty"); words.put(70, "seventy"); words.put(80, "eighty"); words.put(90, "ninety"); int sumOfLetterCounts = "onethousand".length(); //initialization for(int i=1; i<1000; i++) { int digit1 = i%10; // 1の位 int digit2 = i%100/10; // 10の位 int digit3 = i/100; // 100の位 // 1, 2桁目の計算 if(digit2 < 2) { sumOfLetterCounts += words.get(digit1+digit2*10).length(); } else { sumOfLetterCounts += words.get(digit2*10).length(); sumOfLetterCounts += words.get(digit1).length(); } // 3桁目の計算 if(digit3 > 0) { sumOfLetterCounts += words.get(digit3).length(); sumOfLetterCounts += "hundred".length(); if(digit1 != 0 || digit2 != 0) { sumOfLetterCounts += "and".length(); } } } System.out.printf("The answer is %d.\n", sumOfLetterCounts); } }実行結果The answer is 21124.Problem 18
By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.
3 7 4 2 4 6 8 5 9 3That is, 3 + 7 + 4 + 9 = 23.
Find the maximum total from top to bottom of the triangle below:
75 95 64 17 47 82 18 35 87 10 20 04 82 47 65 19 01 23 75 03 34 88 02 77 73 07 63 67 99 65 04 28 06 16 70 92 41 41 26 56 83 40 80 70 33 41 48 72 33 47 32 37 16 94 29 53 71 44 65 25 43 91 52 97 51 14 70 11 33 28 77 73 17 78 39 68 17 57 91 71 52 38 17 14 91 43 58 50 27 29 48 63 66 04 68 89 53 67 30 73 16 69 87 40 31 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23NOTE: As there are only 16384 routes, it is possible to solve this problem by trying every route. However, Problem 67, is the same challenge with a triangle containing one-hundred rows; it cannot be solved by brute force, and requires a clever method! ;o)
Problem18.javapublic class Problem18 { public static void main(String[] args) { String src = "75\r\n" + " 95 64\r\n" + " 17 47 82\r\n" + " 18 35 87 10\r\n" + " 20 04 82 47 65\r\n" + " 19 01 23 75 03 34\r\n" + " 88 02 77 73 07 63 67\r\n" + " 99 65 04 28 06 16 70 92\r\n" + " 41 41 26 56 83 40 80 70 33\r\n" + " 41 48 72 33 47 32 37 16 94 29\r\n" + " 53 71 44 65 25 43 91 52 97 51 14\r\n" + " 70 11 33 28 77 73 17 78 39 68 17 57\r\n" + " 91 71 52 38 17 14 91 43 58 50 27 29 48\r\n" + " 63 66 04 68 89 53 67 30 73 16 69 87 40 31\r\n" + " 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23"; String[] strAry = src.split("\r\n "); final int HEIGHT = strAry.length; Integer[][] intAry = new Integer[HEIGHT][HEIGHT]; // convert String one-dimentional array to Integer two-dimentional array for(int i=0; i<HEIGHT; i++) { String[] tempStrAry = strAry[i].split(" "); for(int j=0; j<HEIGHT; j++) { if (j < tempStrAry.length) { intAry[i][j] = Integer.parseInt(tempStrAry[j]); } else { intAry[i][j] = null; } } } // debug System.out.println("===== Before ====="); print2DArray(intAry); // calculate the largest sum from the top for(int i=1; i<HEIGHT; i++) { for(int j=0; j<=i; j++) { if(j < 1) { intAry[i][j] += intAry[i-1][j]; // leftmost element } else if(j == i) { intAry[i][j] += intAry[i-1][j-1]; // rightmost element } else { intAry[i][j] += Math.max(intAry[i-1][j-1], intAry[i-1][j]); // internal element } } } // debug System.out.println("\n===== After ====="); print2DArray(intAry); // caluculate the maximum number in the numbers of bottoms int maxNum = intAry[HEIGHT-1][0]; for(int i=1; i<HEIGHT; i++) { maxNum = Math.max(maxNum, intAry[HEIGHT-1][i]); } System.out.printf("The answer is %d.\n", maxNum); } // method to display two-dimentional array public static void print2DArray(Integer[][] ary) { for(Integer[] row : ary) { for(Integer num : row) { if(num != null) { System.out.printf("%5d", num); } else { System.out.print(""); } } System.out.println(""); } } }実行結果===== Before ===== 75 95 64 17 47 82 18 35 87 10 20 4 82 47 65 19 1 23 75 3 34 88 2 77 73 7 63 67 99 65 4 28 6 16 70 92 41 41 26 56 83 40 80 70 33 41 48 72 33 47 32 37 16 94 29 53 71 44 65 25 43 91 52 97 51 14 70 11 33 28 77 73 17 78 39 68 17 57 91 71 52 38 17 14 91 43 58 50 27 29 48 63 66 4 68 89 53 67 30 73 16 69 87 40 31 4 62 98 27 23 9 70 98 73 93 38 53 60 4 23 ===== After ===== 75 170 139 187 217 221 205 252 308 231 225 256 390 355 296 244 257 413 465 358 330 332 259 490 538 472 421 397 431 397 494 566 544 488 491 489 472 472 520 622 649 584 571 561 522 513 520 592 655 696 681 621 587 655 551 566 591 636 720 721 739 772 673 752 706 565 636 602 669 748 798 812 789 850 791 820 723 622 727 707 721 786 815 826 903 893 908 870 847 752 670 790 793 725 854 904 879 970 933 981 924 939 934 792 701 794 855 891 881 927 913 1040 1068 1054 1074 977 992 994 796 724 The answer is 1074.Problem 19
You are given the following information, but you may prefer to do some research for yourself.
・1 Jan 1900 was a Monday.
・Thirty days has September,
April, June and November.
All the rest have thirty-one,
Saving February alone,
Which has twenty-eight, rain or shine.
And on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a century unless >it is divisible by 400.
・How many Sundays fell on the first of the month during the twentieth century (1 >Jan 1901 to 31 Dec 2000)?Problem19.javapublic class Problem19 { public static void main(String[] args) { final int START_YEAR = 1901; final int END_YEAR = 2000; int sumOfDays = 0; // initialized by zero int count = 0; // initialized by zero for(int currentYear=1900; currentYear<=END_YEAR; currentYear++) { for(int currentMonth=1; currentMonth<=12; currentMonth++) { if(currentYear >= START_YEAR && sumOfDays%7 == 6) { count++; } if(currentMonth==4 || currentMonth==6 || currentMonth==9 || currentMonth==11) { sumOfDays += 30; } else if(currentMonth == 2) { if(currentYear%4 != 0 || (currentYear%400 != 0 && currentYear%100 == 0)) { sumOfDays += 28; } else { sumOfDays += 29; } } else { sumOfDays += 31; } } } System.out.printf("The answer is %d.\n", count); } }実行結果The answer is 171.Problem 20
n! means n × (n − 1) × ... × 3 × 2 × 1
For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800,
and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.Find the sum of the digits in the number 100!
Problem20.javaimport java.math.BigInteger; public class Problem20 { public static void main(String args[]) { final int N = 100; BigInteger factorial = new BigInteger("1"); // initialized by one int sum = 0; // initialized by zero for(int i=2; i<=N; i++) { factorial = factorial.multiply(new BigInteger(String.valueOf(i))); } for(String s: factorial.toString().split("")) { sum += Integer.parseInt(s); } System.out.printf("The answer is %d.\n", sum); } }実行結果The answer is 648.Problem 21
Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n).
If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and each of a and b are called amicable numbers.For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.
Evaluate the sum of all the amicable numbers under 10000.
java.Problem21.javaimport java.util.HashMap; public class Problem21 { public static void main(String[] args) { final int MAX_NUM = 10000; HashMap<Integer, Integer> sumOfDiv = new HashMap<Integer, Integer>(); int sumOfAmicableNum = 0; // initilized by zero sumOfDiv.put(1, 0); for(int num=2; num<MAX_NUM; num++) { if(sumOfDiv.get(num) == null) { sumOfDiv.put(num, calcSumOfProperDivisors(num)); } Integer partnerNum = sumOfDiv.get(num); if(sumOfDiv.get(partnerNum) == null) { sumOfDiv.put(partnerNum, calcSumOfProperDivisors(partnerNum.intValue())); } if(num == sumOfDiv.get(partnerNum) && num != partnerNum) { sumOfAmicableNum += sumOfDiv.get(num); } } System.out.printf("The answer is %d.\n", sumOfAmicableNum); } public static Integer calcSumOfProperDivisors(int num) { Integer sum = 1; for(int divisor=2; divisor<=Math.sqrt(num); divisor++) { if(num%divisor == 0) { if(divisor*divisor != num) { sum += divisor + num/divisor; } else { sum += divisor; } } } return sum; } }実行結果The answer is 31626.Problem 22
Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.
For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.
What is the total of all the name scores in the file?
Problem22.javaimport java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Arrays; public class Problem22 { public static void main(String[] args) { String filePath = "names.txt"; String[] names = readFile(filePath); Arrays.sort(names); long sumOfScores = 0L; // initialized by zero for(int i=0; i<names.length; i++) { for(int j=0; j<names[i].length(); j++) { sumOfScores += ((long)names[i].charAt(j) - (long)'A' + 1L) * (i+1); } } System.out.printf("The answer is %d.\n", sumOfScores); } public static String[] readFile(String path) { String[] target = null; try (BufferedReader br = new BufferedReader(new FileReader(path))){ String src = br.readLine(); src = src.replace("\"", ""); target = src.split(","); } catch (FileNotFoundException e){ e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } return target; } }実行結果The answer is 871198282.Problem 23
A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
Problem23import java.util.ArrayList; import java.util.Arrays; public class Problem23 { public static void main(String[] args) { final int MAX_NUM = 28123; ArrayList<Integer> abundantNumbers = new ArrayList<Integer>(); Boolean[] SumsOfTwoAbundantNumbers = new Boolean[MAX_NUM+1]; int sum = 0; // initialized by zero Arrays.fill(SumsOfTwoAbundantNumbers, false); // calc abundant numbers for(int i=2; i<=MAX_NUM; i++) { if(isAbundantNumber(i)) { abundantNumbers.add(i); } } // calc sums of the two abundant numbers for(int i=0; i<=abundantNumbers.size()/2; i++) { for(int j=i; j<=abundantNumbers.size(); j++) { if(MAX_NUM >= abundantNumbers.get(i) + abundantNumbers.get(j)) { SumsOfTwoAbundantNumbers[abundantNumbers.get(i)+abundantNumbers.get(j)] = true; } else { break; } } } // calc non-sum of sums of the two abudndant numbers for(int i=1; i<SumsOfTwoAbundantNumbers.length; i++) { if(!SumsOfTwoAbundantNumbers[i]) { sum += i; } } System.out.printf("The answer is %d.\n", sum); } public static boolean isAbundantNumber(int num) { int sum = 1; // initialized by one double sqrt = Math.sqrt(num); for(int divisor=2; divisor<sqrt; divisor++) { if(num%divisor == 0) { sum += divisor + num/divisor; } } if(sqrt == Math.floor(sqrt)) { sum += sqrt; } return num < sum; } }実行結果The answer is 4179871.Problem 24
A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4. If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:
012 021 102 120 201 210
What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?
Problem24.javaimport java.util.ArrayList; public class Problem24 { public static void main(String[] args) { final int NUM = 1000000; ArrayList<String> srcList = new ArrayList<String>(); String target = ""; for(int i=0; i<=10; i++) { srcList.add(String.valueOf(i)); } int numberOfCases = 0; for(int currentDigit=10; currentDigit>0; currentDigit--) { int factorial = 1; int srcIndex = 0; for(int i=1; i<currentDigit; i++) { factorial *= i; } while(numberOfCases + factorial < NUM) { numberOfCases += factorial; srcIndex++; } target += srcList.get(srcIndex); srcList.remove(srcIndex); } System.out.printf("The answer is %s.\n", target); } }実行結果The answer is 2783915460.Problem 25
The Fibonacci sequence is defined by the recurrence relation:
$F_n = F_{n−1} + F_{n−2}$, where $F_1 = 1$ and $F_2 = 1$.
Hence the first 12 terms will be:$F_1 = 1$
$F_2 = 1$
$F_3 = 2$
$F_4 = 3$
$F_5 = 5$
$F_6 = 8$
$F_7 = 13$
$F_8 = 21$
$F_9 = 34$
$F_{10} = 55$
$F_{11} = 89$
$F_{12} = 144$
The 12th term, $F_{12}$, is the first term to contain three digits.What is the index of the first term in the Fibonacci sequence to contain 1000 digits?
Problem25.javaimport java.math.BigInteger; public class Problem25{ public static void main(String[] args){ final int MAX_DIGIT = 1000; BigInteger term1 = new BigInteger("1"); BigInteger term2 = new BigInteger("1"); BigInteger targetTerm = new BigInteger("2"); int index = 3; while(targetTerm.toString().length()<MAX_DIGIT){ term1 = term2; term2 = targetTerm; targetTerm = term1.add(term2); index++; } System.out.printf("The answer is %d.\n", index); } }実行結果The answer is 4782.Problem 26
A unit fraction contains 1 in the numerator. The decimal representation of the unit fractions with denominators 2 to 10 are given:
1/2 = 0.5
1/3 = 0.(3)
1/4 = 0.25
1/5 = 0.2
1/6 = 0.1(6)
1/7 = 0.(142857)
1/8 = 0.125
1/9 = 0.(1)
1/10 = 0.1
Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can be seen that 1/7 has a 6-digit recurring cycle.Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part.
Problem26.javaimport java.util.ArrayList; import java.util.HashMap; public class Problem26 { public static void main(String[] args){ final int MAX_NUM = 1000; int longestRecurringCycle = 0; int divisorWithLongestRecurringCycle = 0; for(int divisor=2; divisor<MAX_NUM; divisor++){ ArrayList<Integer> remainders = new ArrayList<Integer>(); int remainder = 1; while(true){ remainder = remainder*10%divisor; if(remainders.contains(remainder)){ break; }else{ remainders.add(remainder); } } if(longestRecurringCycle < remainders.size() - remainders.indexOf(remainder)){ longestRecurringCycle = remainders.size() - remainders.indexOf(remainder); divisorWithLongestRecurringCycle = divisor; } } System.out.printf("The answer is %d.\n", divisorWithLongestRecurringCycle); } }実行結果The answer is 983.Problem 27
Euler discovered the remarkable quadratic formula:
$n^2+n+41$
It turns out that the formula will produce 40 primes for the consecutive integer values $0≤n≤39$. However, when $n=40,40^2+40+41=40(40+1)+41$ is divisible by $41$, and certainly when $n=41,41^2+41+41$ is clearly divisible by $41$.The incredible formula $n^2−79n+1601$ was discovered, which produces $80$ primes for the consecutive values $0≤n≤79$. The product of the coefficients, $−79$ and $1601$, is $−126479$.
Considering quadratics of the form:
$n^2+an+b$, where $|a|<1000$ and $|b|≤1000$
where $|n|$ is the modulus/absolute value of $n$
e.g. $|11|=11$ and $|−4|=4$
Find the product of the coefficients, $a$ and $b$, for the quadratic expression that produces the maximum number of primes for consecutive values of $n$, starting with $n=0$.Problem27.javaimport java.util.Arrays; import java.util.HashMap; public class Problem27 { public static void main(String[] args){ boolean[] primeNumbers = calcPrimeNumbers(100000); HashMap<Character, Integer> answer = new HashMap<Character, Integer>(); answer.put('n', 0); // initialized for(int a=-999; a<1000; a++){ for(int b=2; b<=1000; b++){ if(primeNumbers[b]){ int n = 0; while(true){ int num = n * n + a * n + b; if(num > 1 && primeNumbers[num]){ n++; }else{ break; } } if(answer.get('n') < n){ answer.put('a', a); answer.put('b', b); answer.put('n', n); } } } } System.out.printf("The answer is %d.\n", answer.get('a') * answer.get('b')); } public static boolean[] calcPrimeNumbers(int maxNum) { boolean[] primeNumbers = new boolean[maxNum + 1]; Arrays.fill(primeNumbers, true); primeNumbers[0] = false; primeNumbers[1] = false; for (int i = 2; i <= Math.sqrt(maxNum); i++) { if (primeNumbers[i]) { for (int j = i * 2; j <= maxNum; j += i) { primeNumbers[j] = false; } } } return primeNumbers; } }実行結果The answer is -59231.
- 投稿日:2019-07-07T13:49:57+09:00
Android(JAVA)でTensorFlowLiteを使って画像分類をやってみる
初めに
今回は、Android(Java)でTensorFlowLiteを使って、画像分類をしようと思います!
もし、コード等に間違え、改善点があれば、教えてください!TensorFlowLiteとは
TensorFlowLiteのガイドによると、、、
TensorFlowLiteはスマートフォンやIotデバイスなどでTensorFlowモデルを使用するためのツールセットです。
TensorFlow Liteのインタプリタ携帯電話、組み込みLinuxデバイス、およびマイクロコントローラを含む多くの異なるハードウェアの種類、に特別に最適化されたモデルを実行します。
TensorFlowライトコンバータインタプリタによって使用するための効率的な形式にTensorFlowモデルを変換し、バイナリサイズとパフォーマンスを向上させるために最適化を導入することができます。
⇒つまり、PCだけじゃなくて、スマートフォンやIotデバイスなどでも簡単に実行できる、TensorFlowの軽量版的なやつか!
将来的には、スマートフォンだけで学習までできるとか!
すごい!TensorFlowLiteを使用した開発手順
1.TensorFlowモデルを用意する
TensorFlowで学習済みのモデルを用意します。
今回は、ホストされたモデルを使用するので、割愛します!2.TensorFlowのモデルを変換する
TensorFlowLiteではTensorFlowのモデルをそのまま使用することができないので、専用の形式(tflite)に変換します。
変換方法等はこちらの記事がわかりやすいので、参考にしてください。3.組み込む!
今回は、Android(Java)の組み込み方法を解説します!
組み込む!
新規プロジェクトの作成
プロジェクト名等は任意の名前にしてください!
今回は、AndroidXを使用します。
「Use androidx.* artifacts」にチェックすれば、OKです。
AndroidXの使用については任意なので、使わなくても大丈夫です。依存関係の追加
appディレクトリ下のbuild.gradleに
build.gradle(app)dependencies { implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly' implementation 'org.tensorflow:tensorflow-lite-gpu:0.0.0-nightly' }を追加します。
このままだと、すべてのCPUと命令セット用のABIが含まれていますが、「armeab-v7a」と「arm64-v8a」が含まれていれば、ほとんどのAndroidデバイスをカバーできるので、ほかのABIは含めいないように設定します。
含まれていても問題はないですが、アプリのサイズが減るので、おすすめです。build.gradle(app)android { defaultConfig { ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' } } }ABIについてはこちらの記事がわかりやすいので参考にしてください。
Androidではassetフォルダーに入れられたものを圧縮してしまうので、モデルをassetフォルダーに入れると、圧縮されて読み込むことができなくなってしまいます。そこで、tfliteファイルを圧縮しないように指定してあげます。
build.gradle(app)android { defaultConfig { aaptOptions { noCompress "tflite" } } }クラスのコピー&カスタマイズ
TensorFlowLiteのAndroidSampleの3つのクラスと、こちらのLogger.javaをコピーします。
コピーしただけだと、エラーが発生します。
Classifier.javaでLoggerクラスのインポート先を書き換えます。Classfier.javaimport org.tensorflow.lite.Interpreter; //ここを削除するimport org.tensorflow.lite.examples.classification.env.Logger; import org.tensorflow.lite.gpu.GpuDelegate; /** A classifier specialized to label images using TensorFlow Lite. */ public abstract class Classifier { private static final Logger LOGGER = new Logger();
削除すると、AndroidStudioがこんなことを聞いてくるので、「Alt+Enter」を押せば、自動でインポートしてくれます。
インポートする際に、
2種類出てくると思いますので、(android.jar)と書かれていないほうを選択します。
これで、エラーがすべて消えたと思います。
モデルの設置
モデルとlabel_textをassetフォルダーに設置します。
こちらよりモデルをダウンロードしてください。
まずは、assetフォルダーフォルダーを作成します。
解凍したフォルダの中から、ファイルをコピーします。
コピーしたら、名前を「model.tflite」と「labels.txt」に変更します。
これでモデルの設置は完了です。Viewの配置
こんな感じにTextView,Button,ImageViewを配置します。
ButtonにはonClickを設定押しておきます。
↑ onClickを設定する方法ってリスナーのほうがいいのかな。詳しい人おしえてくださいな
activity_main.xml<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="TextView" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="select" android:text="画像を選択" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" tools:srcCompat="@tools:sample/avatars" /> </LinearLayout> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>コードを書く
まず、使用する変数を宣言しましょう!
MainActivity.javaImageView imageView; TextView textView; Classifier classifier; private static final int RESULT_IMAGEFILE = 1001; //画像取得時に使用するリクエストコードonCreate内でtextview,ImageViewの紐づけを行います。
MainActivity.javaimageView = findViewById(R.id.imageView); textView = findViewById(R.id.textView);次に、Classfierの呼び出しを行います。
MainActivity.javatry { classifier = Classifier.create(this,QUANTIZED,CPU,2); } catch (IOException e) { e.printStackTrace(); }引数は、Acritivy、Modelの種類、演算に使用するデバイスの指定、使用するスレッド数を指定します。
基本はこの設定で動くと思いますが、臨機応変に変更しましょう。ボタンの動作を書く
ボタンを押したら、ギャラリーを開いて画像が選択できるようにIntentを飛ばします。
MainAcritivy.javapublic void image(View V){ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); startActivityForResult(intent, RESULT_IMAGEFILE); }これについて詳しくはこちら
ギャラリーから戻ってきてからの処理
ギャラリーから戻て来たら、画像を取得して、処理します。
MainAcritivty.java@Override public void onActivityResult(int requestCode, int resultCode, Intent resultData) { super.onActivityResult(requestCode, resultCode, resultData); if (requestCode == RESULT_IMAGEFILE && resultCode == Activity.RESULT_OK) { if (resultData.getData() != null) { ParcelFileDescriptor pfDescriptor = null; try { Uri uri = resultData.getData(); pfDescriptor = getContentResolver().openFileDescriptor(uri, "r"); if (pfDescriptor != null) { FileDescriptor fileDescriptor = pfDescriptor.getFileDescriptor(); Bitmap bmp = BitmapFactory.decodeFileDescriptor(fileDescriptor); pfDescriptor.close(); int height = bmp.getHeight(); int width = bmp.getWidth(); while (true) { int i = 2; if (width < 500 && height < 500) { break; } else { if (width > 500 || height > 500) { width = width / i; height = height / i; } else { break; } i++; } } Bitmap croppedBitmap = Bitmap.createScaledBitmap(bmp, width, height, false); imageView.setImageBitmap(croppedBitmap); List<Classifier.Recognition> results = classifier.recognizeImage(croppedBitmap,classfier); String text; for (Classifier.Recognition result : results) { RectF location = result.getLocation(); Float conf = result.getConfidence(); String title = result.getTitle(); text += title + "\n"; } textView.setText(text); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (pfDescriptor != null) { pfDescriptor.close(); } } catch (Exception e) { e.printStackTrace(); } } } } }長いので、区切って説明します。
このコードは、アクティビティに戻ってきたときに呼ばれ、戻ってきたのが、ギャラリーからのものかを判定しています。
MainAcrivity.java@Override public void onActivityResult(int requestCode, int resultCode, Intent resultData) { super.onActivityResult(requestCode, resultCode, resultData); if (requestCode == RESULT_IMAGEFILE && resultCode == Activity.RESULT_OK) { } }このコードは、戻り値からURIを取得し、ParceFileDescriptorでファイルデータをとっています。
こんなURI「content://com.android.providers.media.documents/document/image%3A325268」が取得できるので、ここから画像を取得しています。MainAcrivity.javaif (resultData.getData() != null) { ParcelFileDescriptor pfDescriptor = null; try { Uri uri = resultData.getData(); pfDescriptor = getContentResolver().openFileDescriptor(uri, "r"); if (pfDescriptor != null) { FileDescriptor fileDescriptor = pfDescriptor.getFileDescriptor();このコードは先ほど取得した画像をbitmapに変換し、画像のサイズを300より小さくなるようにしています。
300よりでかい画像だと、正常に判定することができず、エラーで落ちてしまいます。
Caused by: java.lang.ArrayIndexOutOfBoundsException
そのため、縦横比を維持しつつ、縦横が300以内に収まるようにしています。MainAcrivity.javaBitmap bmp = BitmapFactory.decodeFileDescriptor(fileDescriptor); pfDescriptor.close(); if (!bmp.isMutable()) { bmp = bmp.copy(Bitmap.Config.ARGB_8888, true); } int height = bmp.getHeight(); int width = bmp.getWidth(); while (true) { int i = 2; if (width < 300 && height < 300) { break; } else { if (width > 300 || height > 300) { width = width / i; height = height / i; } else { break; } i++; } } Bitmap croppedBitmap = Bitmap.createScaledBitmap(bmp, width, height, false);いよいよ判別です。
このコードでは、加工した画像で判別をし、独自のリストで受け取っています。
そして、リストをforで回して、結果を取得し、textViewに表示させています。
今回は、判別された品目名のみ出力していますが、品目である可能性がどれくらいかなども取得することができます。MainAcrivity.javaList<Classifier.Recognition> results = classifier.recognizeImage(croppedBitmap); String text=""; for (Classifier.Recognition result : results) { /* RectF location = result.getLocation(); Float conf = result.getConfidence(); */ String title = result.getTitle(); text += title + "\n"; } textView.setText(text);以上で完成です!!
実際に動かしてみる
それでは、実際に動かしてみたいと思います!
まずは、犬の画像
公園のベンチ、、
爪、、、
アメリカンカメレオン、、、
んー
精度は微妙ですね
次は、美しい景色の画像。
デルフトの街並みですウィンドウスクリーン、、、
ドアマット、、、
ブラインド、、、
んー
ダメやん!まとめ
精度は微妙でしたが、うまく?画像を分類することができました!
今度は、リアルタイムで分類をしてみたいと思います!
ではでは!
- 投稿日:2019-07-07T13:19:29+09:00
【Java】Java 10で拡張された型推論について注意すべきこと
SwiftやScala、Kotlin、Go、Rustで開発している方はいわゆる「型推論」を普段使い慣れていることでしょう。型推論は、静的型付け言語における言語機能であり、明示的に型を記述しなくてもコンパイラが自動的に型を決定してくれる機能ですので、Kotlinの型推論のように、
var a = 1と記載するだけで、コンパイラが右辺の型から自動的に左辺の変数aが整数型であると推論してくれるわけです。ついにJavaでもJava 10から型推論が導入されたことは記憶に新しい出来事でもありました。
たとえば、Java 10よりも前では以下のように変数の型を明示的に書く必応がありました。
String name = "tamito0201";Java 10 になるとvarキーワードを付けることによって、次のようにローカル変数の宣言で必須の明示的な型を削除することができます。
var name = "tamito0201";上記の場合は、ただStringがvarに置き換わっただけなので、あまりメリットを感じないかもしれません。しかし、Javaの場合コレクションAPIを使用する際に、うんざりするほど冗長なコードを書かなくてはいけませんよね。
HashMap<Integer, String> map = new HashMap<Integer, String>();Java10以降ではこれを、
var map = new HashMap<Integer, String>();のように記載することができます。なんてエレガントなのでしょう。
ただし、型推論は便利な反面思わぬバグを生んでしまう諸刃の剣でもあります。ですので、プロジェクトによってはコーディング規約によりvarの仕様を禁じ、明示的に型を指定するプロジェクトも存在します。大規模プロジェクトになればなるほど、思わぬバグを生むリスクを考えて、旧来通りの明示的な型指定を行うプロジェクトも多いのです。
なぜか?たとえば以下のコードが記述されているとしましょう。
var distance = getDistance(); System.out.println(distance * 100);関数getDistanceの戻り値はなんでしょうか。ここで感の鋭い方は気づいたかもしれませんね。そうです。ラッパーオブジェクトであるIntegerを返却する可能性があるのであれば、nullが返ってくることもあります。その結果次の
distance * 100でヌルポが発生するのは自明ですので、nullチェックを入れる必要があります。Integer distance = getDistance(); if (distance != null) { System.out.println(distance * 100); }Java 8以降ではOptionalを返せばよいですね。
Optional<Integer> distance = Optional.ofNullable(getDistance()); distance.ifPresent(d -> System.out.println(d * 100));つまりそのプロジェクトやチームでvarを使いわけるため、コーディング指針を決めておく必要があります。
- varを使わない
- ローカル変数は原則varを使用する。
- 右辺に明示的な型が指定されている場合のみvarを使用する
- コーディング規約で明示する型を決めてそれ以外はvarを使う
- 単体テストでカバーするためプロジェクトではvarを使用する
どれも正解ですが、現実的には1 or 2が妥当であると考えられます。コーディング規約でいくら明示する型を指定しても大規模プロジェクトでは、コーディング規約をすべてのエンジニアが遵守できるなんて到底考えられませんからね。コーディング規約で決めて、CheckstyleやSpotBugs、PMD等でしばっておいたほうがいいかと思います。
何事にもメリット、デメリットはあります。
この辺りは、プロジェクトでどうするか必ず決めておいて下さい。決めないと出来上がったプロジェクトのソースはカオスになってしまいますからね。
- 投稿日:2019-07-07T12:54:36+09:00
【Scala】処理中のものを処理し終わった上で終了するProducer-Consumerパターン
並行処理のデザインパターンでよくあるProducer-Consumerパターンですが、
このパターンに、タイトルの通りの動きのロジックを作成しましたので、紹介いたします。コード
import java.util.concurrent.ArrayBlockingQueue class ProducerConsumer[E <: AnyRef](producerConcurrentNumber: Int, producer: () => E, consumerConcurrentNumber: Int, consumer: E => Unit, sentinelObject: E) { @volatile private[this] var terminateProducer: Boolean = _ private[this] val queue = new ArrayBlockingQueue[E](consumerConcurrentNumber * 2) private[this] val producerThreadList = List.fill(producerConcurrentNumber) { new Thread(() => { while (!terminateProducer) queue.put(producer()) }) } private[this] val consumerThreadList = List.fill(producerConcurrentNumber){ new Thread(() => { var item: E = sentinelObject//ignore value while( {item = queue.take();item} ne sentinelObject) consumer(item) }) } def start() { producerThreadList.foreach(_.start()) consumerThreadList.foreach(_.start()) } def stop() { terminateProducer = true producerThreadList.foreach(_.join()) 1 to producerConcurrentNumber foreach(_ => queue.put(sentinelObject)) consumerThreadList.foreach(_.join()) } }1秒間に64スレッドで生産して、128スレッドで消費するパターンでの使用例
使用例import java.util.concurrent.TimeUnit object Main extends App { import java.util.concurrent.atomic.AtomicLong val prodCnt = new AtomicLong() val consCnt = new AtomicLong() val cc: ProducerConsumer[String] = new ProducerConsumer( 64, () => "aaa"+prodCnt.getAndIncrement() , 128, _a => consCnt.getAndIncrement(), new String(""))//終了処理の判定だけに使う番兵オブジェクト cc.start() Thread.sleep(TimeUnit.SECONDS.toMillis(1)) cc.stop() println("----- finish -----") println(f"生産した個数: ${prodCnt.get}%,d") println(f"消費した個数: ${consCnt.get}%,d") assert( prodCnt.get == consCnt.get) }解説
Producerの終了方法
terminateProducerをtrueにすると、whileループから外れて生産しなくなって終了
terminateProducerはマルチスレッドから呼ばれるため、@volatileをつけておいたが、
つけなくても終了処理はされるため、外してもよい。Consumerの終了方法
Producerのスレッドが全部終了し、queueへの追加が行われなくなった後に、
番兵オブジェクト(sentinelObject)をConsumerのスレッド数分だけ投入する。Consumerスレッドでは、
sentinelObjectが来たら終了という判定を行っている。
番兵オブジェクト(sentinelObject)の判定は、!=ではダメでneで同じ参照値かのチェックで判定を行う。その他
ConsumerスレッドのロジックがScalaっぽくないコードになってしまった。
Scalaでは、ローカル変数宣言時の初期値Must、代入式の結果を利用できないため…。
こういう場合だけは、Javaのほうが短く書ける。参考資料
- 投稿日:2019-07-07T12:00:09+09:00
黒魔術を使って行数が多いメソッドを検出したらNGにするJUnit
前提: Java11, JUnit5, sbt
モンスターメソッドにうんざりしてるのでこんなものを書いてしまいました…。
プロジェクト初期にしれっと仕込んでしまいましょう。このようなものを仕込んだ結果、
メソッド分割して1メソッド辺りの行数をとりあえず少なくしたけど、
その代わりに、色んなメソッドで参照できるように、変数のスコープを広げてグローバル変数化されかねない
という問題点もあるにはあるんですが…。
たぶん、それでも今回のこれを仕込んだほうがマシなのかなあ?とは思っています。build.sbtのlibraryDependenciesには↓を貼り付け
build.sbt"org.junit.jupiter" % "junit-jupiter-api" % "5.5.0", "org.junit.jupiter"%"junit-jupiter-engine" % "5.5.0", "org.javassist" % "javassist" % "3.25.0-GA",コード
package com.github.momosetkn; import javassist.ClassPool; import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; class MonsterMethodAlert { @Test void test() throws Exception { var cp = ClassPool.getDefault(); var fail = false; for (var className : getClassNameList()) { var cc = cp.get(className); for (var method : cc.getMethods()) { // java.lang.Object.equalsなど、javaパッケージ配下のメソッドは対象外 if (method.getDeclaringClass().getName().startsWith("java")) continue; var methodInfo = method.getMethodInfo(); var start = methodInfo.getLineNumber(Integer.MIN_VALUE); var end = methodInfo.getLineNumber(Integer.MAX_VALUE); var line = end - start + 1; if (line >= 25) { System.err.println(String.format("%sが%s行のモンスターメソッドとなっております", className + "#" + methodInfo.getName(), line)); fail = true; } } } if (fail) throw new Exception("モンスターメソッドが検出されました"); } private List<String> getClassNameList() throws IOException, URISyntaxException { var list = new ArrayList<String>(); var classLoader = Thread.currentThread().getContextClassLoader(); var targetUrls = classLoader.getResources(""); var CLASS_EXT = ".class"; while (targetUrls.hasMoreElements()) { var url = targetUrls.nextElement(); if (!url.getProtocol().equals("file")) { continue; } var targetPath = Paths.get(url.toURI()); Files.walkFileTree(targetPath, new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path foundPath, BasicFileAttributes attrs) throws IOException { if (foundPath.toString().endsWith(CLASS_EXT)){ var relativizeStr = targetPath.relativize(foundPath).toString(); list.add( relativizeStr .substring(0, relativizeStr.length() - CLASS_EXT.length()) .replace(File.separatorChar, '.') ); } return super.visitFile(foundPath, attrs); } }); } return list; } }Example#mainが36行のモンスターメソッドとなっております java.lang.Exception: モンスターメソッドが検出されました at com.github.momosetkn.MonsterMethodAlert.test(MonsterMethodAlert.java:37) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170) at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112) at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133) at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133) at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)解説
メソッド行数取得
javassist.bytecode.MethodInfo#getLineNumberの実装を見ると、
引数に渡した数値を以下メソッドに渡しているようです。
https://github.com/jboss-javassist/javassist/blob/rel_3_25_0_ga/src/main/javassist/bytecode/LineNumberAttribute.java#L77
ループで回していって超えたかどうかでしか判定していないようなので、
Integer.MIN_VALUEとInteger.MAX_VALUEを渡しています。startとendは、
100: public void method(){ 101: //startはここの行数 102: // 103: //endはここの行数 104: }が取れますので、103-102=2となるため、1足して3行のメソッドという扱いにしています。
Javassistについて
古いバージョンのJavassistだと、新し目のJavaのバージョンに追従していないため、できるだけ新しくする。
参考資料
パッケージ配下のクラス一覧を再帰的に探索したい - Qiita
Javassistメモ(Hishidama's Javassist Memo)
- 投稿日:2019-07-07T12:00:09+09:00
【Java】黒魔術を使って行数が多いメソッドを検出したらNGにするJUnit
前提: Java11, JUnit5, sbt
モンスターメソッドにうんざりしてるのでこんなものを書いてしまいました…。
プロジェクト初期にしれっと仕込んでしまいましょう。このようなものを仕込んだ結果、
メソッド分割して1メソッド辺りの行数をとりあえず少なくしたけど、
その代わりに、色んなメソッドで参照できるように、変数のスコープを広げてグローバル変数化されかねない
という問題点もあるにはあるんですが…。
たぶん、それでも今回のこれを仕込んだほうがマシなのかなあ?とは思っています。build.sbtのlibraryDependenciesには↓を貼り付け
build.sbt"org.junit.jupiter" % "junit-jupiter-api" % "5.5.0", "org.junit.jupiter"%"junit-jupiter-engine" % "5.5.0", "org.javassist" % "javassist" % "3.25.0-GA",コード
package com.github.momosetkn; import javassist.ClassPool; import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; class MonsterMethodAlert { @Test void test() throws Exception { var cp = ClassPool.getDefault(); var fail = false; for (var className : getClassNameList()) { var cc = cp.get(className); for (var method : cc.getMethods()) { // java.lang.Object.equalsなど、javaパッケージ配下のメソッドは対象外 if (method.getDeclaringClass().getName().startsWith("java")) continue; var methodInfo = method.getMethodInfo(); var start = methodInfo.getLineNumber(Integer.MIN_VALUE); var end = methodInfo.getLineNumber(Integer.MAX_VALUE); var line = end - start + 1; if (line >= 25) { System.err.println(String.format("%sが%s行のモンスターメソッドとなっております", className + "#" + methodInfo.getName(), line)); fail = true; } } } if (fail) throw new Exception("モンスターメソッドが検出されました"); } private List<String> getClassNameList() throws IOException, URISyntaxException { var list = new ArrayList<String>(); var classLoader = Thread.currentThread().getContextClassLoader(); var targetUrls = classLoader.getResources(""); var CLASS_EXT = ".class"; while (targetUrls.hasMoreElements()) { var url = targetUrls.nextElement(); if (!url.getProtocol().equals("file")) { continue; } var targetPath = Paths.get(url.toURI()); Files.walkFileTree(targetPath, new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path foundPath, BasicFileAttributes attrs) throws IOException { if (foundPath.toString().endsWith(CLASS_EXT)){ var relativizeStr = targetPath.relativize(foundPath).toString(); list.add( relativizeStr .substring(0, relativizeStr.length() - CLASS_EXT.length()) .replace(File.separatorChar, '.') ); } return super.visitFile(foundPath, attrs); } }); } return list; } }Example#mainが36行のモンスターメソッドとなっております java.lang.Exception: モンスターメソッドが検出されました at com.github.momosetkn.MonsterMethodAlert.test(MonsterMethodAlert.java:37) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170) at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112) at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133) at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133) at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)解説
メソッド行数取得
javassist.bytecode.MethodInfo#getLineNumberの実装を見ると、
引数に渡した数値を以下メソッドに渡しているようです。
https://github.com/jboss-javassist/javassist/blob/rel_3_25_0_ga/src/main/javassist/bytecode/LineNumberAttribute.java#L77
ループで回していって超えたかどうかでしか判定していないようなので、
Integer.MIN_VALUEとInteger.MAX_VALUEを渡しています。startとendは、
100: public void method(){ 101: //startはここの行数 102: // 103: //endはここの行数 104: }が取れますので、103-102=2となるため、1足して3行のメソッドという扱いにしています。
Javassistについて
古いバージョンのJavassistだと、新し目のJavaのバージョンに追従していないため、できるだけ新しくする。
参考資料
パッケージ配下のクラス一覧を再帰的に探索したい - Qiita
Javassistメモ(Hishidama's Javassist Memo)
- 投稿日:2019-07-07T08:46:57+09:00
Oracle Java Silver に受かったので記録
出題傾向
皆さん書いている通り、黒本から大量に出題されます。
私は黒本しか勉強しませんでしたが、1冊全部勉強したところ95%くらい見覚えのある問題でした。
77問中3問くらい見覚えがなく、異常に問題文の長い(パッと見で明らかに毛色が違う)ものが出ますが、黒本の巻末模試で100点取れるようになっていれば3問落としても関係ないのでさっさと見直しフラグつけて適当に選んでから余った時間で見直せばいけます。一字一句、全く同じ問題が大量に出ます。ポリモーフィズムについてとか、拡張for文について語群から2つか3つ選べ、みたいなものは誤答も含めて全く同じでした。
問題文を読まずに選択肢を見ただけで答えがわかります。その他もクラス名か変数名が変わってるだけで中身は全く同じ問題も多数。
黒本でA extends B{}となっているのがcar extends vehicle とか cat extends Animalとかになっているだけで中のコードがそのまま。多重配列の2重ループも選択肢見ただけで分かったりしました。
逆に黒本を勉強せずに解くのはJavaのベテランでも至難の技だと思います。
半数以上がナゾナゾじみた引っ掛け問題なので。気をつけるべき事
これから目指す方はとにかく体調に気をつけてください。
試験前の三日前には規則正しい生活を心がけたほうがいいです。
- トイレに行けない(時間がすぎるだけでなく、一度出たら戻れないのでその場で失格。)
- 鼻水も拭けない。汗も拭けない。 (ティッシュもハンカチも洗顔シートも禁止)
- 水分補給等禁止
- 目が乾いても目薬をさせない。
- 腰が痛くても立ち上がれない。
などなど。150分間もこれを我慢するのは大変です。
体調対策
1週間前くらいから、ご飯を食べた後、どれくらいでお腹が痛くなったりしてトイレに行きたくなるか1時間単位くらいで把握しておく。
当日はそれを逆算して、絶対に試験中にお腹が痛くならない時間帯に軽く食べておく。
逆に抜いてしまうのも禁物。お腹が空いていると集中力が切れるからです。
同様に水分も飲んでからいつトイレに行きたくなるか把握しておく。
その少し前に飲んでおく。試験直前には催してなくても必ず最後にトイレに行っておく。出なくてもいい。試験中に後悔しなくなるから。
試験会場は下見しておくか、最寄駅には1時間くらい前につくようにしておく、30分前くらいでも受けられるのでトイレが済んで、汗拭いたら即受ける。
試験の三日前くらいからエアコンを冷やしすぎないように注意しておく。ちょっと暑いかなってくらいになれておく。
ティッシュは使えないので、最悪風邪ひいたら鼻水拭いても平気なシャツでも着ていくしかない。私の場合、上記の対策をやってなんとかトイレと鼻水は大丈夫でした。
それでも結構きつい頭痛に苛まれました。頭が痛くなったらヘッドフォン外した治りました。
ヘッドフォンに慣れていない人はそれも気をつけてください。
とはいえつけなかったら周りのキーボードの音とか割と気になります。
- 投稿日:2019-07-07T03:03:57+09:00
Javaで設定ファイル、クラスがロードされる順番を指定する
解決したい問題
- WARを実行するときに、訳あってクラスパス上に同名の設定ファイルが複数存在する場合に、ロードされる順番を指定したい
- 環境はWebSphere Liberty、Java8を想定
- 設定ファイル、クラスをクラスパスに含める方法として単純なものは以下の3種類がある。この3つの優先順位を確認したい
- WARファイルに含める
- JARファイルに含め、WARファイルのWEB-INF/libに配置する
- WAR外部に配置する(Libertyのserver.xmlで
<library>に指定する)調査した結果
以下の順番となった。1と2はパッケージングの方法や環境依存ファイルの配置の都合上、自由に設定しにくいのでロード順を細かく指定したい場合は、WARの外部にJARを配置する形をとり、さらに
<library>のなかで細かく順序を指定するのが良さそう。
- WARファイルに含める
- JARファイルに含め、WARファイルのWEB-INF/libに配置する
- WAR外部に配置する(Libertyのserver.xmlで
<library>に指定する)具体的にはこのような形となる。
<library>の子要素の指定順がクラスロードの順番となる。<file>だけでなく<folder>で指定する場合もXML要素の順番がクラスロードの順番となる。<library id="mydir"> <file name="/mydir/foo1.jar"/> <file name="/mydir/foo2.jar"/> </library> <webApplication location="/dir/bar.war"> <classloader privateLibraryRef="mydir"/> </webApplication>よくわからなかったこと
MANIFEST.MFの
Class-Path指定でも同様の設定ができるのではないかと思えるのだが、WARに含めたMANIFEST.MFのClass-Pathで指定した場合、なぜかクラスロードの対象にならないようだった。
- 投稿日:2019-07-07T03:03:00+09:00
Java8とJava11が共存している環境下でSparkを使おうとしたときに出たエラーを解決
Java8とJava11が共存している環境下でSparkを使おうとしたときに出たエラーを解決
概要
spark-shellからsparkを使ってもpysparkを実行しても以下のような同じエラーが出ていたので直した。
'Unsupported class file major version 55'環境
Ubuntu18.04
Spark 2.4.3解決方法(試行錯誤つき)
原因はJava11を使っていることらしい。使用しているJavaのバージョンを確認して、別のバージョンを選ぶために以下を実行。
$ sudo update-alternatives --config java alternative java (/usr/bin/java を提供) には 3 個の選択肢があります。 選択肢 パス 優先度 状態 ------------------------------------------------------------ 0 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1101 自動モード 1 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1101 手動モード * 2 /usr/lib/jvm/java-11-oracle/bin/java 1091 手動モード 3 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java 1081 手動モード 現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください:3これでJava8を使うようになるかと思ったのだけれど、以下のように、そうはならなかった。
$ java --version openjdk 11.0.2 2019-01-15 OpenJDK Runtime Environment 18.9 (build 11.0.2+9) OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)そもそもどこを見に行っているのか調べてみる。すると、
$ which java /home/ksn/.sdkman/candidates/java/current/bin/javaとなっておりJava(とKotlin)はSDKMANを使ってインストールした形跡があり。
ここで、SDKMANでsparkをインストールできるらしいことを知ったのでそちらを試すことに。
$ sdk install sparkでインストールして
$spark-sessionから動作確認を試みたが、やはり'Unsupported class file major version 55'のような同じエラーが出ている。$ sdk list javaをしてSDKMANでJava8がインストール出来るのか見てみると、Javaは8以下はインストールできないっぽいことが判明。そうなるとこちらで解決しようというのは無理だということを判断。
よって、以下でSDKMANで入れたjavaをアンインストール。
$ sdk uninstall java 11.0.2-openこれで、
$ java -version openjdk version "1.8.0_212" OpenJDK Runtime Environment (build 1.8.0_212-8u212-b03-0ubuntu1.18.04.1-b03) OpenJDK 64-Bit Server VM (build 25.212-b03, mixed mode) $ which java /usr/bin/javaとなり、
/usr/bin/下のjavaを読んでくれることに。
$ spark-shellとしてSDKMANでインストールしたsparkを立ち上げてみる。すると$ spark-shell ... scala> val textFile = spark.read.text("README.md") textFile: org.apache.spark.sql.DataFrame = [value: string] scala> textFile.count() res0: Long = 109となり、無事エラーがでなくなった。
調べた限りだと、SparkやHadoopと一緒にJava11を使うのはまだ早すぎでJava11を使いたければSpark3.xに期待しろとのことであった。これで先日のHadoopを導入した際の問題も解決すると思われる。
- 投稿日:2019-07-07T00:46:35+09:00
JavaのアプリをIBM Cloud Kubernetesサービス上にデプロイ
先日タイトルの内容でハンズオンやってと言われたので忘れないうちに手順を書いておきます。
やりたいことは持っているJavaアプリ(warファイルになっている)からOpenLibertyと一緒にDockerイメージを作ってそのイメージをIBM Cloud上でデプロイします。
なお今回のは無料で作れるライトアカウントでもできるので初心者のかたも是非やってみてください。手順は
1. IBM CloudにKubernetesクラスターを作成
2. ローカルのDockerDockerイメージを作成、Docker Hubにアップロード
3. IBM CloudのKubernetesサービス上にデプロイアプリ(サーブレット)は極めてシンプルなものですがきっと複雑なアプリもできるはず
IBM CloudにKubernetesクラスターを作成
これはこちらを参考に作りました。
https://cloud.ibm.com/docs/containers?topic=containers-cs_cluster_tutorial&locale=ja
ライトアカウントで作れる無料のクラスターでやりました。ローカルのDockerDockerイメージを作成、Docker Hubにアップロード
PCかMACで以下のコマンドを実行Open Liberty のDocker イメージをダウンロード
$ docker image pull open-liberty次に以下の内容でDockerfileを作成
FROM open-liberty
COPY ./book-deploy.war /config/dropins/book-deploy.war
同じフォルダーにwarファイルを配置して以下のコマンドでopenliberty-handsonのDockerイメージを作成。
$ docker build . openliberty-handsonできたらDocker Hubにアップローヂ
$ docker tag openliberty-handson /openliberty-handson
$ docker push ユーザー名/openliberty-handson
アップロードされたのを確認
- IBM CloudのKubernetesサービス上にデプロイ IBM cloudにログインしたのちに以下のコマンドでDeploymentの作成、サービスの作成を行ってください。 $ Kubectl run liberty --image=<DockerHubのユーザー名>/openliberty-handson $ kubectl expose deployment liberty --type="NodePort" --port=9080
これでできました。次にIPアドレス、ポート番号を調べてブラウザーからアクセスします。
IPアドレスは
$ ibmcloud cs workers <クラスター名>
で出てきたパブリックアドレスです。
ポート番号は
$ kubectl get service liberty
ででてくるPort(s)の2番目の番号で30000番台の数字です。ブラウザーでアクセスしてみましょう!







































