- 投稿日:2020-05-18T23:33:46+09:00
面倒くさがり屋なJavaエンジニアのためのGroovy入門
目次
- Groovyとは
- Groovyの特徴
- Groovyのメリット
- Groovyのデメリット
- おわりに
Groovyとは
JVM上で動作する、動的型付けスクリプト言語
Groovyの特徴
なぜ、"面倒くさがり屋な" "Javaエンジニア" を対象にするのか...
それはGroovyには次のようなメリットがあるから。
1.Javaに比べてコード量が少なく済む
2.JavaのAPIも利用できる
3.充実したエコシステム(WebアプリケーションフレームワークのGrails、テスティングフレームワークのSpockなど)
Groovyのメリット - Javaに比べてコード量が少なく済む
- 変数宣言/メソッド宣言
def
で変数宣言ができる(型を明示することもできる)
def
で宣言した場合、変数の型はObject型
publicメソッド宣言時にpublic
は不要(メソッドのスコープはデフォルトでpublicのため)JavaString helloWorld = "Hello World."; public static void main(String[] args) { // do something }Groovydef helloWorld = "Hello World." //publicは省略可 static void main(String[] args) { // do something } // 戻り値の型はdefでもOK static def main(String[] args) { //do something } // 戻り値の型は省略可 static main(String[] args) { //do something } // 引数の型も省略可 static main(args) { //do something }
- 文字列
${変数}
の形で、変数を文字列に埋め込めるJavaString name = "Michael"; System.out.println("Hello " + name + "!"); // 出力結果 // Hello Michael!Groovydef name = "Michael" println "Hello ${name}!" // 出力結果 // Hello Michael!
- List, Mapの初期化
Listの初期化は
[]
Mapの初期化は[:]
JavaList<String> list = new ArrayList<>(); Map<String, String> map = new HashMap<>();Groovydef list = [] def map = [:] // 型はLinkedhashMapになる
- コレクションの操作
クロージャーが便利
it
はクロージャーに渡される引数を表す暗黙の変数(下の例ではnumbers
リストの1つ1つの要素)JavaList<Integer> numbers = List.of(1, 2, 3, 4, 5); List<Integer> odds = numbers.stream().filter(number -> number % 2 != 0).collect(Collectors.toList()); System.out.println(odds); // 出力結果 // [1, 3, 5]Groovydef numbers = [1, 2, 3, 4, 5] def odds = numbers.findAll { it % 2 != 0 } // def odds = numbers.findAll { number -> number != 0 } println odds // 出力結果 // [1, 3, 5]
- DB操作(MySQL)
@Grab
でGrapeという構成管理ツールを使用して外部リポジトリ(Mavenリポジトリなど)からライブラリを取得できる
groovy.sql.Sql
クラスが便利personテーブル
person_id first_name last_name 1 Michael Jordan 2 Michael Jackson Java// mysql-connector-javaをダウンロードし、クラスパスに追加 Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sampledb", "root", "root"); // first_nameがMichaelのレコードのlast_nameを取得 PreparedStatement pstmt = conn.prepareStatement("SELECT last_name FROM person WHERE first_name = ?"); pstmt.setString(1, "Michael"); ResultSet rs = pstmt.executeQuery(); // 取得したレコードのlast_nameをコンソールに出力 while(rs.next()) { System.out.println(rs.getString("last_name")); } // 出力結果 // "Jordan" // "Jackson"Groovy// Grapeを使用して外部リポジトリからmysql-connector-javaを取得 @GrabConfig(systemClassLoader=true) @Grab("mysql:mysql-connector-java:5.1.49") def sql = Sql.newInstance("jdbc:mysql://localhost:3306/sampledb", "root", "root", "com.mysql.jdbc.Driver") // first_nameがMichaelのレコードのlast_nameを取得 def rows = sql.rows("SELECT last_name FROM person WHERE first_name = ?", ["Michael"]) // 取得したレコードのlast_nameをコンソールに出力 rows.each { println it.last_name } // 出力結果 // "Jordan" // "Jackson"
Groovyのデメリット
- コンパイル時に型チェックができない
動的型付け言語であるため、型を宣言せず、
def
で宣言した変数やクロージャーの引数については実行時に型チェックがされるため、型が原因のエラーについては実行時まで指摘されない。
- バージョンによってはJavaの構文が一部サポートされていない
try-with-resource文やラムダ式等の一部の構文について、2系ではサポートされていない。
バージョン3系ではこれらもサポートされているが、リリースされたのが今年の2月のため、Groovyを使用するフレームワークやライブラリについては最新バージョンでも2.5系を使っている可能性がある。
おわりに
GroovyはJavaに比べてコード量が少なく済み、開発効率のアップにつながることが期待できます。
また、Javaエンジニアにとっては学習コストは低く、習得までさほど時間はかからないでしょう。(私も3か月ほどで習得できました。)
もしJavaのコードを冗長に感じていたり、より効率的に開発したいと思っていたりするようなら、Groovyを試してみてはいかがでしょうか?
- 投稿日:2020-05-18T22:45:07+09:00
NLP4J [001b] Java で 形態素解析(kuromojiを利用)
kuromoji とは
Javaで開発したオープンソース日本語形態素解析エンジンです。
kuromoji | Atilika
https://www.atilika.com/ja/kuromoji/Maven
<dependency> <groupId>org.nlp4j</groupId> <artifactId>nlp4j-core</artifactId> <version>1.3.0.0</version> </dependency> <dependency> <groupId>org.nlp4j</groupId> <artifactId>nlp4j-kuromoji</artifactId> <version>1.3.0.0</version> </dependency>コード
package example; import nlp4j.Document; import nlp4j.Keyword; import nlp4j.impl.DefaultDocument; import nlp4j.krmj.annotator.KuromojiAnnotator; public class HelloKuromojiNLP1 { public static void main(String[] args) throws Exception { // 自然文のテキスト String text = "今日はいい天気です。"; Document doc = new DefaultDocument(); // 属性「text」としてセットする doc.putAttribute("text", text); // kuromoji アノテーター KuromojiAnnotator annotator = new KuromojiAnnotator(); // 処理対象の属性を指定 annotator.setProperty("target", "text"); // 形態素解析処理 annotator.annotate(doc); // throws Exception // キーワードの出力 for (Keyword kwd : doc.getKeywords()) { System.err.println(kwd); } } }結果
今日 [facet=名詞, str=今日] は [facet=助詞, str=は] いい [facet=形容詞, str=いい] 天気 [facet=名詞, str=天気] です [facet=助動詞, str=です] 。 [facet=記号, str=。]
- 投稿日:2020-05-18T22:14:44+09:00
Spring Boot + Spring Data JPA にて getOne, findById, クエリメソッドの挙動を確認する
概要
- Spring Boot + Spring Data JPA にて JpaRepository#getOne, CrudRepository#findById, クエリメソッド HogeRepository#findByFoo の挙動を確認する
メソッドの説明
JpaRepository#getOne
JpaRepository#getOne は遅延取得 (laze fetch) するメソッド。
JpaRepository (Spring Data JPA 2.2.7.RELEASE API) - Javadoc 日本語訳
T getOne(ID id)
指定された識別子を持つエンティティへの参照を返します。JPA 永続性プロバイダーの実装方法によっては、これは常にインスタンスを返し、最初のアクセスで EntityNotFoundException をスローする可能性が非常に高くなります。それらのいくつかは、無効な識別子をすぐに拒否します。パラメーター :
id - null であってはなりません。戻り値 :
指定された識別子を持つエンティティへの参照。関連事項 :
for details on when an exception is thrown.JpaRepository#getOne は EntityManager#getReference を呼び出している。
EntityManager (Java(TM) EE 8 Specification APIs)
T getReference(Class entityClass, Object primaryKey)
Get an instance, whose state may be lazily fetched.CrudRepository#findById
CrudRepository (Spring Data Core 2.2.7.RELEASE API) - Javadoc 日本語訳
Optional findById(ID id)
ID でエンティティを取得します。パラメーター :
id - null であってはなりません。戻り値 :
指定された ID を持つエンティティ、または見つからない場合は Optional#empty()例外 :
IllegalArgumentException - id が null の場合。HogeRepository#findByFoo
今回作成する Hoge エンティティクラスの ID (主キー) である foo カラムの値を引数としてエンティティを取得するクエリメソッド。
クエリメソッドは Spring Data の命名規則に沿ったメソッド名を指定することで処理の実装が自動生成される仕組み。Spring Data JPA 5.3. クエリメソッド - リファレンスドキュメント - 日本語訳
JPA モジュールは、クエリを文字列として手動で定義すること、またはメソッド名から派生させることをサポートしています。
Spring Dataが定めた命名規約に則ったメソッド名にすることで実行するQuery(JPQL)を指定する。
Spring Data JPAの機能によってメソッド名からJPQLが生成される。
ただし、メソッド名からJPQLを作成できるのはSELECTのみで、UPDATEおよびDELETEのJPQLは生成できない。サンプルコード
ソースコード一覧
├── build.gradle ├── settings.gradle └── src └── main ├── java │ └── com │ └── example │ ├── Hoge.java │ ├── HogeController.java │ ├── HogeRepository.java │ └── HogeService.java └── resources ├── application.properties └── data.sqlbuild.gradle
plugins { id 'org.springframework.boot' version '2.2.7.RELEASE' id 'io.spring.dependency-management' version '1.0.9.RELEASE' id 'java' } group = 'com.example' version = '0.0.1' sourceCompatibility = '11' repositories { mavenCentral() } dependencies { // Spring implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // Lombok compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' // H2 Database runtimeOnly 'com.h2database:h2' }settings.gradle
rootProject.name = 'my-app'src/main/java/com/example/Hoge.java
package com.example; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; /** * DB テーブルの1レコード分に相当。 */ @Data // Lombok で getter setter など便利なメソッドを自動生成 @Entity // JPA エンティティとして扱う public class Hoge { @Id // JPA にこの変数をオブジェクトの ID (主キー) だと認識させる private String foo; private String bar; }src/main/java/com/example/HogeRepository.java
package com.example; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; /** * DB アクセス用リポジトリ。 * Spring Data JPA が標準で提供するメソッドが自動生成される。 */ @Repository public interface HogeRepository extends JpaRepository<Hoge, String> { // エンティティと主キーの型を指定 // Spring Data JPA の命名規則に沿ったクエリメソッドを定義 // 中身が自動生成される public Hoge findByFoo(String foo); }src/main/java/com/example/HogeService.java
サービスクラス。リポジトリのメソッドをコールする。
package com.example; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @Service @Transactional @Slf4j // org.slf4j.Logger 型の static final 変数 log を自動生成 public class HogeService { @Autowired private HogeRepository repository; public Hoge getOne(String id) { // JpaRepository#getOne log.debug("Before: JpaRepository#getOne"); Hoge hoge = repository.getOne(id); log.debug("After: JpaRepository#getOne"); return hoge; } public Hoge findById(String id) { // CrudRepository#findById log.debug("Before: CrudRepository#findById"); Optional<Hoge> opt = repository.findById(id); log.debug("After: CrudRepository#findById"); return opt.orElseThrow(); } public Hoge findByFoo(String foo) { // HogeRepository#findByFoo log.debug("Before: HogeRepository#findByFoo"); Hoge hoge = repository.findByFoo(foo); log.debug("After: HogeRepository#findByFoo"); return hoge; } }src/main/java/com/example/HogeController.java
コントローラークラス。サービスのメソッドをコールする。
package com.example; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @SpringBootApplication @RestController @Slf4j // org.slf4j.Logger 型の static final 変数 log を自動生成 public class HogeController { public static void main(String[] args) { SpringApplication.run(HogeController.class, args); } @Autowired private HogeService service; @GetMapping("/getOne/{foo}") public Map getOne(@PathVariable("foo") String foo) { // エンティティを取得 log.debug("Before: HogeService#getOne"); Hoge hoge = service.getOne(foo); log.debug("After: HogeService#getOne"); // エンティティから値を取り出す log.debug("Before: Hoge#getFoo, Hoge#getBar"); Map result = Map.of(hoge.getFoo(), hoge.getBar()); log.debug("After: Hoge#getFoo, Hoge#getBar"); return result; } @GetMapping("/findById/{foo}") public Map findById(@PathVariable("foo") String foo) { // エンティティを取得 log.debug("Before: HogeService#findById"); Hoge hoge = service.findById(foo); log.debug("After: HogeService#findById"); // エンティティから値を取り出す log.debug("Before: Hoge#getFoo, Hoge#getBar"); Map result = Map.of(hoge.getFoo(), hoge.getBar()); log.debug("After: Hoge#getFoo, Hoge#getBar"); return result; } @GetMapping("/findByFoo/{foo}") public Map findByFoo(@PathVariable("foo") String foo) { // エンティティを取得 log.debug("Before: HogeService#findByFoo"); Hoge hoge = service.findByFoo(foo); log.debug("After: HogeService#findByFoo"); // エンティティから値を取り出す log.debug("Before: Hoge#getFoo, Hoge#getBar"); Map result = Map.of(hoge.getFoo(), hoge.getBar()); log.debug("After: Hoge#getFoo, Hoge#getBar"); return result; } }src/main/resources/application.properties
application.properties# Spring Framework と Hibernate ORM 等のログを出力するように指定 logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql=TRACE logging.level.org.springframework.orm.jpa=DEBUG logging.level.com.example=DEBUG # Open EntityManager in View パターンを使う spring.jpa.open-in-view=truesrc/main/resources/data.sql
-- 初期データを DB に追加 INSERT INTO hoge (foo, bar) VALUES ('myfoo', 'mybar');Spring Boot アプリケーションを起動
Java 11 (AdoptOpenJDK 11.0.7+10) + Gradle 6.4.1 で Spring Boot アプリケーションを起動する。
$ gradle bootRun > Task :bootRun . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.7.RELEASE)起動時のログを見る。
Spring Boot 2.2.7 + Spring 5.2.6 が使われている。
com.example.HogeController : Running with Spring Boot v2.2.7.RELEASE, Spring v5.2.6.RELEASEHibernate ORM core version 5.4.15.Final が使われている。
o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.4.15.Final o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.0.Final} org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialectエンティティクラスの定義から自動的にテーブルが作成される。
org.hibernate.SQL : create table hoge (foo varchar(255) not null, bar varchar(255), primary key (foo)) o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'アクセスしてそれぞれのメソッドの挙動を見る
JpaRepository#getOne
curl でアクセスする。
$ curl http://localhost:8080/getOne/myfooSpring Boot のログを確認する。
JpaRepository#getOne で Hoge エンティティを取得する際にではなく、取得した Hoge エンティティのフィールドにアクセスする際に select 文が発行されている (lazy fetch による遅延取得)。
o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor com.example.HogeController : Before: HogeService#getOne o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1004472706<open>)] for JPA transaction o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.example.HogeService.getOne]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@2c01e862] com.example.HogeService : Before: JpaRepository#getOne o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1004472706<open>)] for JPA transaction o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction com.example.HogeService : After: JpaRepository#getOne o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(1004472706<open>)] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction com.example.HogeController : After: HogeService#getOne com.example.HogeController : Before: Hoge#getFoo, Hoge#getBar org.hibernate.SQL : select hoge0_.foo as foo1_0_0_, hoge0_.bar as bar2_0_0_ from hoge hoge0_ where hoge0_.foo=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [myfoo] o.h.type.descriptor.sql.BasicExtractor : extracted value ([bar2_0_0_] : [VARCHAR]) - [mybar] com.example.HogeController : After: Hoge#getFoo, Hoge#getBar o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptorCrudRepository#findById
curl でアクセスする。
$ curl http://localhost:8080/findById/myfooSpring Boot のログを確認する。
CrudRepository#findById で Hoge エンティティを取得する際に select 文が発行されている。
o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor com.example.HogeController : Before: HogeService#findById o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(794705340<open>)] for JPA transaction o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.example.HogeService.findById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@2199c627] com.example.HogeService : Before: CrudRepository#findById o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(794705340<open>)] for JPA transaction o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction org.hibernate.SQL : select hoge0_.foo as foo1_0_0_, hoge0_.bar as bar2_0_0_ from hoge hoge0_ where hoge0_.foo=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [myfoo] o.h.type.descriptor.sql.BasicExtractor : extracted value ([bar2_0_0_] : [VARCHAR]) - [mybar] com.example.HogeService : After: CrudRepository#findById o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(794705340<open>)] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction com.example.HogeController : After: HogeService#findById com.example.HogeController : Before: Hoge#getFoo, Hoge#getBar com.example.HogeController : After: Hoge#getFoo, Hoge#getBar o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptorHogeRepository#findByFoo
curl でアクセスする。
$ curl http://localhost:8080/findByFoo/myfooSpring Boot のログを確認する。
HogeRepository#findByFoo で Hoge エンティティを取得する際に select 文が発行されている。
o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor com.example.HogeController : Before: HogeService#findByFoo o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1242780251<open>)] for JPA transaction o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.example.HogeService.findByFoo]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@44d4b569] com.example.HogeService : Before: HogeRepository#findByFoo org.hibernate.SQL : select hoge0_.foo as foo1_0_, hoge0_.bar as bar2_0_ from hoge hoge0_ where hoge0_.foo=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [myfoo] o.h.type.descriptor.sql.BasicExtractor : extracted value ([foo1_0_] : [VARCHAR]) - [myfoo] o.h.type.descriptor.sql.BasicExtractor : extracted value ([bar2_0_] : [VARCHAR]) - [mybar] com.example.HogeService : After: HogeRepository#findByFoo o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(1242780251<open>)] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction com.example.HogeController : After: HogeService#findByFoo com.example.HogeController : Before: Hoge#getFoo, Hoge#getBar com.example.HogeController : After: Hoge#getFoo, Hoge#getBar o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor参考資料
- 投稿日:2020-05-18T17:27:54+09:00
java の抽象クラスについて
java のabstract の理解が進んでいなかったので学習した。
特徴
・直接のインスタンス生成が出来ない
・サブクラスにオーバーライドを強制する
・サブクラスでコンストラクタを記述する必要があるsample.javaabstract class Abst_sample { abstract void abstractMethod(int num, String str); void nonAbstractMethod() { System.out.println("非抽象メソッドより出力"); } } public class sample extends Abst_sample { public static void main(String[] args) { sample aaa = new sample(); // 継承したあとで、自身のインスタンスを生成してabstractMethod を呼び出している。 aaa.abstractMethod(3, "Test"); } @Override public void abstractMethod(int num, String str) { System.out.println("引数int num = " + num + " / 引数String str = "+ str); } }「こういうメソッドを使いなさい」を指示を出すイメージかな。
多人数で開発をするとなると、こういう機能も必要になってくるんだろう。
覚えておいて損はないな。
参考
- 投稿日:2020-05-18T15:02:26+09:00
Javaの配列での複数を求める場合
【例】
Main.javaclass xxxx { public static void main(String[] args) { int[] numbers = {1, 6, 11, 16, 21, 26}; int oddNumber = 0; int evenNumber = 0; for (int number : numbers) { if (number % 2 == 0) { evenNumber += number; } else { oddNumber += number; } } System.out.println("奇数の合計は" + oddNumber + "です"); System.out.println("偶数の合計は" + evenNumber + "です"); } }上記の結果は奇数の合計は33です
偶数の合計は48です
となります。
配列numbersの要素を1つずつ取得し、その要素の値が
奇数であれば変数oddNumberで
偶数であれば変数evenNumberとしています。
偶数であるか奇数であるかの判定は、if文で「%」を用いています。
「% 2 == 0」とすることでk「evenNumber += number;」で偶数であるか
違えばelseの「oddNumber += number;」が実行されます。
- 投稿日:2020-05-18T14:23:29+09:00
Javaの配列
配列
配列とは、複数の値をまとめられることです。
配列の変数定義
配列を扱う場合には、配列型の変数に配列を代入します。
配列の変数定義int型とString型int[] String[]int型は数値を要素に持つ配列です。
String型は文字列を要素に持つ配列です。Stringの頭文字は大文字です。
int型の配列の例Main.javaint[] numbers = {1,5,10};String型の配列の例
Main.javaString[] names = {"佐藤","鈴木","高橋"};配列の要素には、前から順に「0, 1, 2・・・」と数字が割り振られています。
配列の各要素は、配列名[インデックス番号]とすることで取得することができます。
【例】Main.javaString[] names = {"佐藤","鈴木","高橋"}; System.out.println("名前は"+names[0]+"です");配列の要素の上書き
Main.javaString[] names = {"佐藤","鈴木","高橋"}; System.out.println("名前は"+names[0]+"です"); names[0] = "上野"; System.out.println("名前は"+names[0]+"です");names[インデックス] = "要素";で上書きできます。
上記の例だとコンソールの出力結果は佐藤と上野になります。配列の繰り返し処理
for文を使って繰り返し処理ができます。
【例】Main.javaString[] names = {"佐藤","鈴木","高橋"}; for (int x = 0;x < 3;x++){ System.out.println("名前は"+names[x]+"です"); }上記の例だとインデックスの0から2までの3つをnamesから呼び出しています。
length
lengthとは要素の数を数えるという機能です。
上記のfor文とlengthを使って、繰り返し処理ができます。
先ほどのfor文の条件式x<3を配列.lengthにすることで書き換えることができます。
【例】Main.javaString[] names = {"佐藤","鈴木","高橋"}; for (int x = 0;x < names.length;x++){ System.out.println("名前は"+names[x]+"です"); }上記のように記述すれば、配列の要素数を気にする必要がなくなります。
なので、こちらの方が使いやすいと思います。
ですが、もっとシンプルなfor文もあります。それは配列拡張for文です。配列拡張for文
for文は配列用に拡張for文があります。これを使えば、先ほどのfor文をよりシンプルに書くことができます。
Main.javafor (データ型 変数名:配列名) { 繰り返す処理; }【例】
Main.javaString[] names = {"佐藤","鈴木","高橋"}; for (String name:names){ System.out.println("名前は"+name+"です"); }上記の例だとStringがデータ型、nameが変数名、namesが配列名です。
先ほどまでのlengthを使ったfor文と比較して、拡張for文では変数に配列の要素自体が代入されます。
私が理解するためにだらだら書きましたが、これが一番使いやすいかなと思います。
- 投稿日:2020-05-18T12:12:14+09:00
JavaでTODOアプリを制作しよう1 MVCの簡単な説明
こんにちは。
タイトルの通り、JavaでTODOアプリを作る方法を書いていきます。
今回は実際にコードを書く前にJavaではどんな風な値が流れているのかを説明したいと思います。MVCとは?
MVCとは
Model...(データベースとのやりとりをしたり、処理をしたりする)
View...(HTML/CSSとかを使ってユーザーへ実際に表示される画面)
Controller...(Modelにデータの処理を頼んだり、返ってきたデータをViewに渡す)こんな感じでそれぞれが役割を持っています。
ではJavaのMVCはどうなっているのでしょうか?
View, Controller, Service, Repository, Entity
JavaではModelの部分をService, Repository, Entityというクラスで行う事が一般的のようです。
簡単にTODO登録の流れを書くと
View上で登録ボタンが押されて登録内容が送信される。
登録内容がControllerのメソッドに渡される。
ControllerはServiceクラスに登録内容を渡す。
Serviceクラスは登録内容をEntityクラスの変数にあてはめてRepositoryクラスのメソッドでデータベースに保存する。
みたいな流れです。
正直これだけだとなかなか掴めないと思うので、今後の記事で実際に一つ一つ解説しながら進めていこうと思います!
- 投稿日:2020-05-18T11:07:08+09:00
JavaはExcelを画像、html、XPS、XML、CSV、PostScript、PCLに変換します
Excel文書の日常の運用では、さまざまな作業場面のニーズを満たすために、文書の形式を変換する必要があることがよくあります。この記事では、Javaプログラムでコードを使用してExcelを画像、html、XPS、XML、CSVに変換する方法を示します。
使用ツール: Free Spire.XLS for Java(無料版)
JARファイルのインポート方法
方法1: Free Spire.XLS for Javaパッケージをダウンロードして解凍し、Spire.Xls.jarパッケージをlibフォルダーからJavaアプリケーションにインポートします。
方法2: mavenを使用している場合は、pom.xmlファイルに次の依存関係を追加する必要があります。<repositories> <repository> <id>com.e-iceblue</id> <name>e-iceblue</name> <url>http://repo.e-iceblue.com/nexus/content/groups/public/</url> </repository> </repositories> <dependencies> <dependency> <groupId>e-iceblue</groupId> <artifactId>spire.xls.free</artifactId> <version>2.2.0</version> </dependency> </dependencies>Javaコード例:
import com.spire.xls.*; public class ExcelToImg { public static void main(String[] args) { //Excelワークシートを読み込む Workbook wb = new Workbook(); wb.loadFromFile("input.xlsx"); //ワークシートを取得 Worksheet sheet = wb.getWorksheets().get(0); //画像としてExcelワークシートを保存 sheet.saveToImage("ToImg.png"); //Excelで指定したセルのデータ範囲を画像として保存する //sheet.saveToImage("ToImg2.png",8,1,30,7); //ExcelをHTMLとして保存 sheet.saveToHtml("ToHtml.html"); //ExcelをXPSとして保存 sheet.saveToFile("ToXPS.xps", String.valueOf(FileFormat.XPS)); //ExcelをCSVとして保存 sheet.saveToFile("ToCSV.csv", String.valueOf(FileFormat.CSV)); //ExcelをXMLとして保存 sheet.saveToFile("ToXML.xml", String.valueOf(FileFormat.XML)); //ExcelをPostScriptとして保存 sheet.saveToFile("ToPostScript.postscript", String.valueOf(FileFormat.PostScript)); //ExcelをPCLとして保存 sheet.saveToFile("ToPCL.pcl", String.valueOf(FileFormat.PCL)); } }
- 投稿日:2020-05-18T10:36:27+09:00
localhost:8080で表示されるログイン画面
原因の正体はSpringSecurity
SpringBootを使ってWEBアプリケーションを開発するとき、localhost:8080で実際に画面を表示したりする。そのとき、想定していたhtmlファイルに遷移せずに謎のログインページに飛ばされた。
調べてみると、どうやらSpringSecurityを使用する場合に出てくるものみたい。
対応策
デフォルト設定であればユーザー名は`"user"`、SpringBoot起動時にコンソールに表示されるパスワードを入力してあげるとログインして、目的のページにたどり着くみたい。
※もしSpringSecurityを使わないのであれば、依存関係を削除すればOK!
- 投稿日:2020-05-18T01:08:34+09:00
【Android Studio】 SQLiteを使いやすくするクラス テーブルの作成・削除
概要
Android Studioには、データベースを用いたアプリケーションを作りやすくするために「SQLiteOpenHelper」クラスや「SQLiteDatabase」クラスなどのクラスが用意されています。
これらのクラスはとても便利で使いやすいのですが、・テーブルを作る際に既に同じ名前のテーブルが存在しないかチェックする必要がある。
・SQLをコード中に直接書く必要がある。
・SQLはStringオブジェクトとして書く必要があり、間違ってコーディングしたときに気づきにくい。
・Stringオブジェクトとして書いたSQLが邪魔でちょっと見ずらい。という点で不便だなと思うことがありました。
中でも、私はもともとwebアプリケーションを作っていたので生のSQLがコードにあると不安になってしまうというきらいがあります。
また、何がしているのか直感的に分かるコードが好きでもあります。
ということで今回は、関数チックにSQLを使えてメインのプログラムを見たときに何をしているのか分かりやすいものであることを目標にして「SQLiteDatabase」クラスをサポートするクラスを作っていこうと思います。ソースコード
「controlTable」クラス
controlTable.javapackage com.example; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; public class controlTable implements SQLiteSupporter { public void createTable(SQLiteDatabase dbObject, String tableName, String[][] list) { if (!getTableExist(dbObject,tableName)) { StringBuilder createTable = new StringBuilder("CREATE TABLE "); for (String[] str :list) { if (str == list[0]) { String s = tableName + "(" + str[0] + " " + str[1] + " PRIMARY KEY"; createTable.append(s); } else { String s = ", " + str[0] + " " + str[1]; createTable.append(s); } } createTable.append(")"); dbObject.execSQL(createTable.toString()); } } public void dropTable(SQLiteDatabase dbObject,String tableName) { if (getTableExist(dbObject,tableName)) { String dropTable = String.format("DROP TABLE IF EXISTS '%s'",tableName); dbObject.execSQL(dropTable); } } private boolean getTableExist(SQLiteDatabase dbObject, String tableName){ String query = String.format("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='%s';", tableName); Cursor c = dbObject.rawQuery(query, null); c.moveToFirst(); String result = c.getString(0); return !result.equals("0"); } }「SQLiteSupporter」というインターフェイスを継承していますが、メインプログラムが読みやすくなるためと後で機能を変えやすくするためですので継承させなくても構いません。
今回はテーブルの作成と削除だけですので、非常にシンプルですね。
テーブルの作成はcreateTableメゾットで、削除はdropTableメゾットで行います。テーブルの有無はgetTableExistメゾットで行います。
これらの使い方は後ほど具体例を交えて説明するとして、大まかにソースコードの中身をいうと基本的には受け取った引数をもとにSQLを組み立ててそれを実行するといった感じですね。これは後々作るであろう他のメゾットでも変わらないと思います。「controlTable」クラスが継承しているインターフェイス
SQLiteSupporter.javapackage com.example; import android.database.sqlite.SQLiteDatabase; public interface SQLiteSupporter { public void createTable (SQLiteDatabase dbObject, String tableName, String[][] list) ; public void delateTable (SQLiteDatabase dbObject,String tableName); }これも特に説明するところはないですね。ただ、引数を決め過ぎたかなーと思ったのでオーバーロードしてテーブルを全て消す機能などを追加してもいいかなと個人的には思いました。
各メゾットの使い方
createTableメゾット
createTableには引数が三つあります。
一つ目は、「SQLiteDatabase」クラスのインスタンスです。注意点はopenOrCreateDatabaseメゾットを使った後に入れるということです。SQLiteDatabase dbObject; String dbName ; ///////////////////////////////////////////////////////////////////////////////////// dbName = "data/data/" + getActivity() + "/myDatabase1.db"; dbObject = SQLiteDatabase.openOrCreateDatabase(dbName,null);私の場合はフラグメント内で使いたかったのでgetActivityメゾットを使ってデータベースの場所と取得しました。データベースの名前もデフォルトのままですのでmyDatabase1.dbで取得できています。
参考までにコードを載せてはいますが、ここに関しては使う場所などによって取得方法に違いがでると思います。二つ目の引数の名前はテーブル名の名前です。Stringオブジェクトとして好きな名前を入れて下さい。
string name = "table";三つ目の引数はテーブルの項目です。下記のようなStringオブジェクトの配列で入れて下さい。一番最初の項目が主キーになります。
{項目名,項目のデータ形}です。String[][] data = { {"id", "INTEGER"}, {"type", "STRING"}, {"int", "INTEGER"}, {"date", "STRING"}, {"category", "STRING"}, {"tag", "STRING"} };createTableメゾットにこれらの引数を入れるとテーブルを作ることが出来ます。
SQLiteDatabase dbObject; String dbName ; dbName = "data/data/" + getActivity() + "/myDatabase1.db"; dbObject = SQLiteDatabase.openOrCreateDatabase(dbName,null); string name = "table"; String[][] data = { {"id", "INTEGER"}, {"type", "STRING"}, {"int", "INTEGER"}, {"date", "STRING"}, {"category", "STRING"}, {"tag", "STRING"} }; SQLiteSupporter db = new controlTable(); db.createTable(dbObject,name, data);delateTableメゾット
createメゾットとだいたい一緒です。SQLiteDatabaseクラスのインスタンスとテーブルの名前を入れて下さい。
SQLiteDatabase dbObject; String dbName ; dbName = "data/data/" + getActivity() + "/myDatabase1.db"; dbObject = SQLiteDatabase.openOrCreateDatabase(dbName,null); string name = "table"; SQLiteSupporter db = new controlTable(); db.dropTable(dbObject,name);まとめ
テーブルを作るのが一つだけでいいという場合はSQLを直接書いた方がいいと思います。また、簡単な構造で必要なコード数が少ない場合もSQLを直接書いた方が余計なファイルを増やさずに済むのでいいと思います。
ただ、ボタン操作と関連付けたり、頻繁にテーブル操作を行う必要があったりする場合などはコードが煩雑になりやすいので今回のようにしてみてもいいのではないかと思います。
あとは、SQLはメゾットが組み立ててくれるのでテーブル名を変更したい場合や、項目の数や名前を変えたい場合はかなり楽に変えることができるので変更にも強くなります。実際、試しにSQLを直接書いたコードと今回のコードを作ってみ比べてみたのですが、目に見えて効果を感じることが出来ました。ただ、createTableメゾット本体は外部キーには対応できていないので拡張の余地が残っているなと思います。
また、今回のような簡単なテーブル操作の場合だと可読性や保守性の向上という強みは生かされにくいので他の操作にも対応したものを作っていこうかなと思います。拙いところや不具合等がありましたらコメント欄にてご指摘・ご指導のほどよろしくお願いします。では、失礼します。