20201009のJavaに関する記事は12件です。

Java HashMapクラス

【Java HashMapクラス】

HashMapは、Javaで開発しているとよく使うので、復習を兼ねてまとめました。

Map

ListやSet、Queueと異なる要素で管理される。
Mapは、keyとvalueの組み合わせで要素を管理されている。

HashMap

HashMapは、Mapの実装クラスの中で最も基本的なクラスである。
keyは重複できない。順番を持たない。

HashMapクラスの主なメソッド

・int size( )

Mapの要素数を取得

・clear( )

すべての要素を削除

・get( Object key )

keyに対応する値を取得

・keySet( )

すべてのkeyを取得

・put( key, value )

指定されたkey, valueの組み合わせを追加

・isEmpty( )

Mapが空かを判定

・remove( Object key )

指定のkeyを削除

・Collection values( )

すべてのvalueを取得

・containsKey( Object key )

keyがMapに含まれているかを判定

・containsValue( Object value )

valueがMapに含まれているかを判定

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

【Java Siler】varによる型推論について

varとは

Java SE10 以降登場した、ローカル変数型推論を行う仕組み。
右辺の型からデータ型を推論する。
varによる型推論は、コンパイル時に行われる。

※【ローカル変数とは】
メソッド内で宣言する変数のこと(メソッドの中の仮引数または引数として使われる)

・varによる型推論の例

var i = 10;  //右辺の値より、iはint型であると推論する

varによる型推論ができるのはローカル変数のみ!!!!

varを使えないパターン(コンパイルエラー発生)

・ローカル変数以外の変数(インスタンス変数・static変数・メソッドの戻り値型)の場合
・変数宣言時に初期化していない場合(つまり、「var i;」と変数だけ作成する場合)
・nullで初期化している場合
・配列の初期化を代入する変数の場合

varで配列を作る際の注意

varは右辺の型からデータ型を推論する。そして、配列の作成に使う初期化子({})も、代入する値の型から配列の型を推論する。お互いに推論しあってしまうため、型が決まらずにコンパイルエラーとなる。

・コンパイルエラーとなる配列の初期化例

var array = {1,2,3};

しかし、右辺で配列の値を作成する際に、型を宣言してくれれば、varによる配列の初期化が可能になる

・varによる配列の初期化例

var array = new int []{1,2,3};  //int型の配列が作成できる

varでArrayListを作る際の注意

配列と同様に、varによってArrayListを作成することもできる。

・varによるArrayListの初期化

var list = new ArrayList<>();

ArrayListのダイヤモンド演算子は、参照できる型がない時に、Object型を返す。故に上記のコードは下記のコードと同じ。

 var list = new ArrayList<Object>();

listとして、Object型のArrayListが作成される。

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

JODConverter+LibreOfficeの変換が遅いとお嘆きのあなたへ

JODConverter


 巷で見かけるサンプルコードは、次のような流れが多数となっている。しかし下記の処理を実行すると、外部プロセスとしてLibreOfficeを起動・終了するため、処理に時間がかかる。例えばWebアプリケーションの1リクエストごとに実行する処理としては、適切でない。

OfficeManager officeManager = LocalOfficeManager.make();
officeManager.start();
// ・・・
// フォーマット変換(中略)
// ・・・
officeManager.stop();

 公式に推奨された方法としては、単一のOfficeManagerをWebアプリ起動時にstart()して、全リクエストで共有して、Webアプリ終了時にstop()する。
https://github.com/sbraconnier/jodconverter/wiki/Web-Application


 ExternalOfficeManagerもそれなりに有効かもしれない。

ExternalOfficeManager (JODConverter Local 4.3.0 API)
https://www.javadoc.io/static/org.jodconverter/jodconverter-local/4.3.0/org/jodconverter/local/office/ExternalOfficeManager.html

[1] 次のように引数を指定してLibreOfficeを起動しておく。

soffice.exe -accept="socket,host=127.0.0.1,port=2002;urp;"

[2] フォーマット変換時には ExternalOfficeManager を利用して、起動済みのLibreOfficeに接続する。この処理はそれなりに速く実行できる。

OfficeManager officeManager = ExternalOfficeManager.make();
officeManager.start();
// 中略
officeManager.stop();

 ただし、Javadocに書いてある通り、LibreOfficeが異常終了しても、JODConverterはLibreOfficeを再起動しない。

Since this implementation does not manage the Office process, it does not support auto-restarting the process if it exits unexpectedly.

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

コーディングの正解は1つではない

はじめに

java言語を学んでいる文系学生です。
最近、AtCoderというコーディングスキルを競えるコンテンツに興味を持ち、過去問を解きまくっている最中です。

このコードをもっとスマートにできないかな?

参考にさせていただいたコードを、自分なりにスマートにできないかと試行錯誤しました。。

問題はAtcoderのB - Crane and Turtleの、つるかめ算の問題です。
https://atcoder.jp/contests/abc170/tasks/abc170_b

qiita.turukame
import java.util.Scanner;
public class Main{
  public static void main(String[] args){
    Scanner scan = new Scanner(System.in);
    int x = scan.nextInt();
    int y = scan.nextInt();
    int flag = 0;
    for (int i = 0; i <= x; i++){
      if ((y-2*i)%4 == 0 && (y - 2 * i)/4 == x-i){
        flag++;
        System.out.println("Yes");
        break;
      }
    }
    if  (flag == 0){
      System.out.println("No");
    }
  }
}

これを、、、、
(saka1029様にコードレビューしていただきました!)

qiita.turukamekai
public class main {
static boolean tsurukame(int x, int y) {
    return y % 2 == 0 && y >= 2 * x && 4 * x >= y;
}

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    int x = scan.nextInt();//匹
    int y = scan.nextInt();//本数
    System.out.println(tsurukame(x, y) ? "yes" : "no");
}
}


工夫したこと

結論、for文のなかに詰め込みました。(Y/4 <= X && Y%2 == 0 )を入れることで、たまたま偶数の本数でyesと出てしまうとこを、Y%2 == 0 を入れ偶数であることを証明したうえですると奇数の本数で処理することを防ぐことができます。あってるのかな。。。

結論

コーディングはやろうと思えばコンパクトにコーディングすることができる!
おもろい!!!!

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

[Java] WordArtをWord文書に追加

通常のテキストと比較するなら、WordArtがより美しくて面白く見えながら、分別しやすいデザインされていて、雑誌やポスターにもよく見られます。日常の仕事ではWord文書を編集するときに、WordArtを通して記事を目立たせたり、ページレイアウトを美しくすることができます。
この記事では、Free Spire.Doc for Javaを使用して、ワードドキュメントにWordArtを追加し、スタイルと効果を設定する方法を紹介します。

JARパッケージのインポート
方法1: Free Spire.Doc for Javaをダウンロードして解凍したら、libフォルダーのSpire.Doc.jarパッケージを依存関係としてJavaアプリケーションにインポートします。

方法2: Mavenリポジトリから直接にJARパッケージをインストールしたら、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.doc.free</artifactId>
        <version>3.9.0</version>
    </dependency>
</dependencies>

WordArtを追加します

import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.ShapeObject;
import java.awt.*;


public class WordArt{
    public static void main(String[] args) throws Exception {
        //ワードドキュメントを作成します
        Document doc = new Document();

        //sectionを追加します
        Section section = doc.addSection();

        //sectionに段落を追加します
        Paragraph paragraph = section.addParagraph();

        //形状を追加し、そのサイズとスタイルを設定します
        ShapeObject shape = paragraph.appendShape(280, 80, ShapeType.Text_Inflate);

        //形状の位置を設定します
        shape.setVerticalPosition(80);
        shape.setHorizontalPosition(100);

        //WordArtテキストコンテンツ
        shape.getWordArt().setText("言葉の影響力");

        //WordArtの塗りつぶしの色を設定します
        shape.setFillColor(Color.CYAN);
        shape.setStrokeColor(Color.BLACK);

        //ドキュメントを保存します
        doc.saveToFile("WordArt.docx", FileFormat.Docx_2013);
    }
}

WordArtの効果を追加します
art.jpg

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

wsimportのエラー対応(クラス/インタフェースがすでに使用されています/A class/interface with the same name "xxx" is already in use)

Java用のSoapクライアントコードの自動生成に利用するwsimportで発生したエラーメッセージが日本語になっていて、日本語情報だと見つからず、ちょっと遠回りしたので備考。

エラーメッセージ

日本語だと

[ERROR] 同じ名前"xxxxxx.SampleResponse"のクラス/インタフェースがすでに使用されています。
この競合を解決するには、クラス・カスタマイズを使用してください。

英語だと

[ERROR] A class/interface with the same name "xxx" is already in use. 
Use a class customization to resolve this conflict.

原因と対策

原因は2つ考えられる。

  • -pオプションを指定してパッケージ名を任意に指定したことにより名称が重複
  • wsdl内でname属性の値が重複している・・・サーバ側が.NET(拡張子asmx)だと発生するのかも

前者の場合は-pオプションを指定せず(=つまりwsdlにしたがって)にwsimportを実行すれば解決。

自分の場合は後者だった。具体的には以下のSampleResponseのように同じname()を持つ定義があるのが悪い模様。
片方の定義を削除すると重複エラーは消えるが、メソッドから参照されているので結局エラーになる。

hoge.wsdl
<s:element name="SampleResponse">
  <s:complexType>
    <s:sequence>
      <s:element minOccurs="1" maxOccurs="1" name="Response" nillable="true" type="tns:SampleResponse" />
    </s:sequence>
  </s:complexType>
</s:element>
<s:complexType name="SampleResponse">
  <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="Result" type="tns:SampleResponseResult" />
    <s:element minOccurs="0" maxOccurs="1" name="ApplicationResponse" type="tns:SampleResponseApplicationResponse" />
  </s:sequence>
</s:complexType>

この場合の対策は、wsimportコマンドに以下のオプションを指定すること。-Bの後には空白ないので注意。

-B-XautoNameResolution

なお、この場合は、SampleResponseSampleResponse2というクラスが生成されるので適宜修正する。

参考

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

EclipseLink JPAでの自動トリムを止める方法

背景

最近仕事でWebSphere Liberty (Open Liberty)を利用する事になりましたが、JPAでデータベースの項目を取得するときに標準ではCHAR型のスペースが自動トリムされていることが判明しました。CHAR(3)の項目に、"a  "(後ろにスペース2つ)や"   "(スペース3つ)を意図的に設定しているときに、"a"や""(空文字列)と取得されてしまいます。調べると、これはEclispeLinkの標準仕様だそうで。

Solution

persistence.xmlかなにかの設定で簡単に変更できると思いきや単純な設定はなさそうでした。はまってしまいましたが、その解決方法としてはSessionCustomizerを作成する必要がありました。

SessionCustomizerの作成

JavaEE APIでの対応が難しく、EclipseLinkのAPIを利用した制御が必要です。

import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.sessions.Session;

public class YOURSessionCustomizer implements SessionCustomizer{
    public void customize(Session session) {
        session.getLogin().setShouldTrimStrings(false);
    }
}

persistence.xmlの設定

<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<!-- 中略 -->
    <persistence-unit name="ABC" transaction-type="JTA">
<!-- 中略 -->
        <properties>
            <!-- EclipseLink settings -->
            <property name="eclipselink.validate-existence" value="true"/>
            <property name="eclipselink.logging.level" value="ALL" />
            <property name="eclipselink.logging.sql" value="ALL"/>
            <property name="eclipselink.logging.level.sql" value="ALL"/>
            <property name="eclipselink.logging.parameters" value="true"/>
<!-- 追加したところ -->
            <property name="eclipselink.session.customizer" value="package.YOURSessionCustomizer"/>
<!-- 追加したところ -->
        </properties>
    </persistence-unit>
</persistence>

Libertyのserver.xmlの設定変更

<server>
<!-- 中略 -->
    <webApplication contextRoot="app" id="webapp" location="webapp.war" name="webapp">
        <classloader apiTypeVisibility="spec, ibm-api, stable, third-party" />
    </webApplication>
</server>

参考:Java EE アプリケーションからのサード・パーティー API へのアクセス
https://www.ibm.com/support/knowledgecenter/ja/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_classloader_3p_apis.html

(option)pox.xmlの修正

EclipseLinkのAPIのが必要ですので、プロジェクトのクラスパスの通し方に応じて設定してください。
EclopseLinkはLibertyに含まれますのでprovidedにしてます。

        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.6.9</version>
            <scope>provided</scope>
        </dependency>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java で JSON と YAML を変換する (Jackson と SnakeYAML を使って)

概要

  • Java で JSON と YAML を変換する (Jackson と SnakeYAML を使って)
  • Jackson で JSON を Java オブジェクトに変換し、SnakeYAML で Java オブジェクトを YAML に変換する
  • SnakeYAML で YAML を Java オブジェクトに変換し、Jackson で Java オブジェクトを JSON に変換する
  • 環境: Java 15 (AdoptOpenJDK 15+36) + Jackson Databind 2.11.3 + ShakeYAML 1.27 + Gradle 6.6.1

Gradle によるビルド環境・実行環境を構築

以下の build.gradle を用意する。

plugins {
  id 'java'
}

repositories {
  mavenCentral()
}

dependencies {
  // Jackson Databind を使う
  implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.3'

  // ShakeYAML を使う
  implementation 'org.yaml:snakeyaml:1.27'
}

// JsonToYaml クラスを実行するタスクを定義
task jsonToYaml(type: JavaExec) {
  main = 'JsonToYaml'
  classpath = sourceSets.main.runtimeClasspath
}

// YamlToJson クラスを実行するタスクを定義
task yamlToJson(type: JavaExec) {
  main = 'YamlToJson'
  classpath = sourceSets.main.runtimeClasspath
}

Java オブジェクトの中身を出力するクラスを用意

JSON や YAML を Java オブジェクトに変換した際のデータ構造やクラスについて把握するため、オブジェクトの情報を出力するクラスを用意する。

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * JSON や YAML 由来の Java オブジェクトの中身を出力する。
 */
public class ObjectDumper {

  private static final int INDENT = 2;

  public static String dump(Map<String, Object> obj) {
    List<String> buffer = new ArrayList<String>();
    dumpMap(obj, 0, buffer);
    return String.join("\n", buffer);
  }

  private static void dumpMap(Map<String, Object> obj, int depth, List<String> buffer) {
    for (Map.Entry<String, Object> entry : obj.entrySet()) {
      Object value = entry.getValue();
      if (value instanceof List) {
        buffer.add(line(entry.getKey(), value, depth));
        dumpList((List<Object>) value, depth + 1, buffer);
      } else if (value instanceof Map) {
        buffer.add(line(entry.getKey(), value, depth));
        dumpMap((Map<String, Object>) value, depth + 1, buffer);
      } else {
        buffer.add(line(entry.getKey(), value, depth));
      }
    }
  }

  private static void dumpList(List<Object> array, int depth, List<String> buffer) {
    for (Object element : array) {
      if (element instanceof List) {
        buffer.add(line(element, depth));
        dumpList((List<Object>) element, depth + 1, buffer);
      } else if (element instanceof Map) {
        buffer.add(line(element, depth));
        dumpMap((Map<String, Object>) element, depth + 1, buffer);
      } else {
        buffer.add(line(element, depth));
      }
    }
  }

  private static String line(String key, Object value, int depth) {
    if (value == null) {
      return " ".repeat(INDENT * depth) + key + ": " + "null";
    } else if (value instanceof Map) {
      return " ".repeat(INDENT * depth) + key + ": " + "(" + value.getClass().getName() + ")";
    } else if (value instanceof List) {
      return " ".repeat(INDENT * depth) + key + ": " + "(" + value.getClass().getName() + ")";
    } else {
      return " ".repeat(INDENT * depth) + key + ": " + value.toString() + " (" + value.getClass().getName() + ")";
    }
  }

  private static String line(Object value, int depth) {
    if (value == null) {
      return " ".repeat(INDENT * depth) + "null";
    } else if (value instanceof Map) {
      return " ".repeat(INDENT * depth) + "(" + value.getClass().getName() + ")";
    } else if (value instanceof List) {
      return " ".repeat(INDENT * depth) + "(" + value.getClass().getName() + ")";
    } else {
      return " ".repeat(INDENT * depth) + value.toString() + " (" + value.getClass().getName() + ")";
    }
  }
}

JSON を YAML に変換する

Jackson で変換: JSON → Java オブジェクト
SnakeYAML で変換: Java オブジェクト → YAML

ソースコード

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import java.util.Map;

public class JsonToYaml {

  public static void main(String[] args) throws JsonProcessingException {

    // JSON 文字列
    String json = """
      {
        "key": "value",
        "foo": "bar",
        "hoge": "fuga",
        "datalist": [
          {
            "string": "mojiretu",
            "integer": 123456,
            "decimal": 123.456,
            "boolean": true,
            "date": "2020-01-01",
            "timestamp": "2020-01-01T00:00:00.123456789+09:00",
            "nullonly": null,
            "object": {"hoge": "HOGE", "fuga": "FUGA"},
            "array": ["foo", "bar", "baz", ["spam", "ham", "eggs"]]
          },
          {
            "string": "文字列",
            "integer": 100000,
            "decimal": 999.999,
            "boolean": false,
            "date": "2020-01-01",
            "timestamp": "2020-01-01T00:00:00.123456789+09:00",
            "nullonly": null,
            "object": {"hoge": "ほげ", "fuga": "ふが"},
            "array": ["ふー", "ばー", "ばず", ["スパム", "ハム", "エッグ"]]
          }
        ]
      }
      """;
    System.out.println("********** 入力する JSON 文字列 **********");
    System.out.println(json);

    System.out.println("********** JSON を Java オブジェクト に変換 **********");
    ObjectMapper mapper = new ObjectMapper();
    Map<String, Object> obj = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
    });
    System.out.println(ObjectDumper.dump(obj));

    System.out.println("********** Java オブジェクトを YAML に変換 **********");
    DumperOptions opts = new DumperOptions();
    opts.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
    String yaml = new Yaml(opts).dump(obj);
    System.out.println(yaml);
  }
}

実行結果

********** 入力する JSON 文字列 **********
{
  "key": "value",
  "foo": "bar",
  "hoge": "fuga",
  "datalist": [
    {
      "string": "mojiretu",
      "integer": 123456,
      "decimal": 123.456,
      "boolean": true,
      "date": "2020-01-01",
      "timestamp": "2020-01-01T00:00:00.123456789+09:00",
      "nullonly": null,
      "object": {"hoge": "HOGE", "fuga": "FUGA"},
      "array": ["foo", "bar", "baz", ["spam", "ham", "eggs"]]
    },
    {
      "string": "文字列",
      "integer": 100000,
      "decimal": 999.999,
      "boolean": false,
      "date": "2020-01-01",
      "timestamp": "2020-01-01T00:00:00.123456789+09:00",
      "nullonly": null,
      "object": {"hoge": "ほげ", "fuga": "ふが"},
      "array": ["ふー", "ばー", "ばず", ["スパム", "ハム", "エッグ"]]
    }
  ]
}

********** JSON を Java オブジェクト に変換 **********
key: value (java.lang.String)
foo: bar (java.lang.String)
hoge: fuga (java.lang.String)
datalist: (java.util.ArrayList)
  (java.util.LinkedHashMap)
    string: mojiretu (java.lang.String)
    integer: 123456 (java.lang.Integer)
    decimal: 123.456 (java.lang.Double)
    boolean: true (java.lang.Boolean)
    date: 2020-01-01 (java.lang.String)
    timestamp: 2020-01-01T00:00:00.123456789+09:00 (java.lang.String)
    nullonly: null
    object: (java.util.LinkedHashMap)
      hoge: HOGE (java.lang.String)
      fuga: FUGA (java.lang.String)
    array: (java.util.ArrayList)
      foo (java.lang.String)
      bar (java.lang.String)
      baz (java.lang.String)
      (java.util.ArrayList)
        spam (java.lang.String)
        ham (java.lang.String)
        eggs (java.lang.String)
  (java.util.LinkedHashMap)
    string: 文字列 (java.lang.String)
    integer: 100000 (java.lang.Integer)
    decimal: 999.999 (java.lang.Double)
    boolean: false (java.lang.Boolean)
    date: 2020-01-01 (java.lang.String)
    timestamp: 2020-01-01T00:00:00.123456789+09:00 (java.lang.String)
    nullonly: null
    object: (java.util.LinkedHashMap)
      hoge: ほげ (java.lang.String)
      fuga: ふが (java.lang.String)
    array: (java.util.ArrayList)
      ふー (java.lang.String)
      ばー (java.lang.String)
      ばず (java.lang.String)
      (java.util.ArrayList)
        スパム (java.lang.String)
        ハム (java.lang.String)
        エッグ (java.lang.String)
********** Java オブジェクトを YAML に変換 **********
key: value
foo: bar
hoge: fuga
datalist:
- string: mojiretu
  integer: 123456
  decimal: 123.456
  boolean: true
  date: '2020-01-01'
  timestamp: '2020-01-01T00:00:00.123456789+09:00'
  nullonly: null
  object:
    hoge: HOGE
    fuga: FUGA
  array:
  - foo
  - bar
  - baz
  - - spam
    - ham
    - eggs
- string: 文字列
  integer: 100000
  decimal: 999.999
  boolean: false
  date: '2020-01-01'
  timestamp: '2020-01-01T00:00:00.123456789+09:00'
  nullonly: null
  object:
    hoge: ほげ
    fuga: ふが
  array:
  - ふー
  - ばー
  - ばず
  - - スパム
    - ハム
    - エッグ

YAML を JSON に変換する

SnakeYAML で変換: YAML → Java オブジェクト
Jackson で変換: Java オブジェクト → JSON

ソースコード

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.yaml.snakeyaml.Yaml;

import java.util.Map;

public class YamlToJson {

  public static void main(String[] args) throws JsonProcessingException {

    // YAML 文字列
    String yaml = """
      key: value
      foo: bar
      hoge: fuga
      datalist:
      - string: mojiretu
        integer: 123456
        decimal: 123.456
        boolean: true
        date: 2020-01-01
        timestamp: 2020-01-01T00:00:00.123456789+09:00
        nullonly: null
        object:
          hoge: HOGE
          fuga: FUGA
        array:
        - foo
        - bar
        - baz
        - - spam
          - ham
          - eggs
      - string: 文字列
        integer: 100000
        decimal: 999.999
        boolean: false
        date: 2020-01-01
        timestamp: 2020-01-01T00:00:00.123456789+09:00
        nullonly: null
        object:
          hoge: ほげ
          fuga: ふが
        array:
        - ふー
        - ばー
        - ばず
        - - スパム
          - ハム
          - エッグ
      """;
    System.out.println("********** 入力する YAML 文字列 **********");
    System.out.println(yaml);

    System.out.println("********** YAML を Java オブジェクト に変換 **********");
    Map<String, Object> obj = new Yaml().load(yaml);
    System.out.println(ObjectDumper.dump(obj));

    System.out.println("********** Java オブジェクトを JSON に変換 **********");
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
    System.out.println(json);
  }
}

実行結果

********** 入力する YAML 文字列 **********
key: value
foo: bar
hoge: fuga
datalist:
- string: mojiretu
  integer: 123456
  decimal: 123.456
  boolean: true
  date: 2020-01-01
  timestamp: 2020-01-01T00:00:00.123456789+09:00
  nullonly: null
  object:
    hoge: HOGE
    fuga: FUGA
  array:
  - foo
  - bar
  - baz
  - - spam
    - ham
    - eggs
- string: 文字列
  integer: 100000
  decimal: 999.999
  boolean: false
  date: 2020-01-01
  timestamp: 2020-01-01T00:00:00.123456789+09:00
  nullonly: null
  object:
    hoge: ほげ
    fuga: ふが
  array:
  - ふー
  - ばー
  - ばず
  - - スパム
    - ハム
    - エッグ

********** YAML を Java オブジェクト に変換 **********
key: value (java.lang.String)
foo: bar (java.lang.String)
hoge: fuga (java.lang.String)
datalist: (java.util.ArrayList)
  (java.util.LinkedHashMap)
    string: mojiretu (java.lang.String)
    integer: 123456 (java.lang.Integer)
    decimal: 123.456 (java.lang.Double)
    boolean: true (java.lang.Boolean)
    date: Wed Jan 01 09:00:00 JST 2020 (java.util.Date)
    timestamp: Wed Jan 01 00:00:00 JST 2020 (java.util.Date)
    nullonly: null
    object: (java.util.LinkedHashMap)
      hoge: HOGE (java.lang.String)
      fuga: FUGA (java.lang.String)
    array: (java.util.ArrayList)
      foo (java.lang.String)
      bar (java.lang.String)
      baz (java.lang.String)
      (java.util.ArrayList)
        spam (java.lang.String)
        ham (java.lang.String)
        eggs (java.lang.String)
  (java.util.LinkedHashMap)
    string: 文字列 (java.lang.String)
    integer: 100000 (java.lang.Integer)
    decimal: 999.999 (java.lang.Double)
    boolean: false (java.lang.Boolean)
    date: Wed Jan 01 09:00:00 JST 2020 (java.util.Date)
    timestamp: Wed Jan 01 00:00:00 JST 2020 (java.util.Date)
    nullonly: null
    object: (java.util.LinkedHashMap)
      hoge: ほげ (java.lang.String)
      fuga: ふが (java.lang.String)
    array: (java.util.ArrayList)
      ふー (java.lang.String)
      ばー (java.lang.String)
      ばず (java.lang.String)
      (java.util.ArrayList)
        スパム (java.lang.String)
        ハム (java.lang.String)
        エッグ (java.lang.String)
********** Java オブジェクトを JSON に変換 **********
{
  "key" : "value",
  "foo" : "bar",
  "hoge" : "fuga",
  "datalist" : [ {
    "string" : "mojiretu",
    "integer" : 123456,
    "decimal" : 123.456,
    "boolean" : true,
    "date" : 1577836800000,
    "timestamp" : 1577804400123,
    "nullonly" : null,
    "object" : {
      "hoge" : "HOGE",
      "fuga" : "FUGA"
    },
    "array" : [ "foo", "bar", "baz", [ "spam", "ham", "eggs" ] ]
  }, {
    "string" : "文字列",
    "integer" : 100000,
    "decimal" : 999.999,
    "boolean" : false,
    "date" : 1577836800000,
    "timestamp" : 1577804400123,
    "nullonly" : null,
    "object" : {
      "hoge" : "ほげ",
      "fuga" : "ふが"
    },
    "array" : [ "ふー", "ばー", "ばず", [ "スパム", "ハム", "エッグ" ] ]
  } ]
}

参考資料

JSON + Jackson

YAML + SnakeYAML

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

Javaアプリデプロイ時の例外「ServletException」の原因と対応策

例外発生時の状況

Eclipseでサーブレットアプリを作成し、VPSにデプロイしたところ、以下のような例外が発生した。

javax.servlet.ServletException: Error instantiating servlet class [servlet.LoginServlet]

error.png

原因

原因はしっかりエラー文の中に書かれてありました。

根本原因

java.lang.UnsupportedClassVersionError: 
servlet/LoginServlet has been compiled by a more recent version of the Java Runtime (class file version 55.0), 
this version of the Java Runtime only recognizes class file versions up to 52.0 (unable to load class [servlet.LoginServlet])
 
~以下略~

 
EclipseのJDKバージョンと、TomcatのJREバージョンが一致していないのが原因で、Tomcatがクラスファイルを実行できない状態になっていました。(コンパイル時のJavaバージョンが実行時のJavaバージョンを上回っていると、例外が発生するようです。)

解決策

 Tomcat側のバージョンを最新にするか、Eclipse側のバージョンを下げる。(今回はEclipse側を変更することにした。)
※ ちなみに、クラスファイルのバージョンはJREのバージョンに対し、以下の様になっている。今回のケースでは、Eclipse側のバージョンをJava11→Java8に変更すればよいということになる。

JREバージョン クラスファイルバージョン
Java 8 52.0
Java 9 53.0
Java 10 54.0
Java 11 55.0
Java 12 56.0
Java 13 57.0
Java 14 58.0
Java 15 59.0

 

手順

 Eclipseウインドウからウィンドウ > 設定と遷移すると設定画面が表示される。Java > コンパイラーページへ遷移すると、JDKのコンパイラー準拠レベルという項目があるので、こちらを1.8に変更する。
 

eclipse設定.png

 
※ 既にプロジェクトを作成している場合、この設定変更は適用されない。作成済みのプロジェクトのバージョンを落としたい場合は、プロジェクト名(右クリック) > プロパティで同じ画面が表示されるので、そちらで変更する。

参考

https://stackoverflow.com/questions/47457105/class-has-been-compiled-by-a-more-recent-version-of-the-java-environment
http://www.ne.jp/asahi/hishidama/home/tech/java/version.html
https://jpn.itlibra.com/article?id=21118

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

Javaアプリデプロイ時の例外「ServletException: Error instantiating servlet class」の原因と対応策

例外発生時の状況

Eclipseでサーブレットアプリを作成し、VPSにデプロイしたところ、以下のような例外が発生した。

javax.servlet.ServletException: Error instantiating servlet class [servlet.LoginServlet]

error.png

原因

EclipseのJDKバージョンと、TomcatのJREバージョンが一致していないのが原因で、Tomcatがクラスファイルを実行できない状態になっていました。(コンパイル時のJavaバージョンが実行時のJavaバージョンを上回っていると、例外が発生するようです。)

<エラーログ>

根本原因

java.lang.UnsupportedClassVersionError: 
servlet/LoginServlet has been compiled by a more recent version of the Java Runtime (class file version 55.0), 
this version of the Java Runtime only recognizes class file versions up to 52.0 (unable to load class [servlet.LoginServlet])
 
~以下略~

※ ちなみに、クラスファイルのバージョンはJREのバージョンに対し、以下の様に対応しています。
 

JREバージョン クラスファイルバージョン
Java 8 52.0
Java 9 53.0
Java 10 54.0
Java 11 55.0
Java 12 56.0
Java 13 57.0
Java 14 58.0
Java 15 59.0

 
今回のケースだと、アプリがバージョン55.0(Java 11)でコンパイルされているのにも関わらず、バージョン52.0(Java 8)で実行しようとしている、という状況になっていました。

解決策

 Tomcat側のバージョンを最新にするか、Eclipse側のバージョンを下げる。(今回はEclipse側を変更することにした。)
 
 Eclipseウインドウからウィンドウ > 設定と遷移すると設定画面が表示される。Java > コンパイラーページへ遷移すると、JDKのコンパイラー準拠レベルという項目があるので、こちらを1.8に変更する。
eclipse設定.png
 
※ 既にプロジェクトを作成している場合、この設定変更は適用されない。作成済みのプロジェクトのバージョンを落としたい場合は、プロジェクト名(右クリック) > プロパティで同じ画面が表示されるので、そちらで変更する。

参考

https://stackoverflow.com/questions/47457105/class-has-been-compiled-by-a-more-recent-version-of-the-java-environment
http://www.ne.jp/asahi/hishidama/home/tech/java/version.html
https://jpn.itlibra.com/article?id=21118

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

【Eclipse】ショートカットキーチートシート

これからEclipseを扱うことになるので、操作方法のお勉強。
ほとんどVSCodeと変わらないのでスッと入りそうではありますね。

キー 内容
Ctr + M 画面最大化
Ctrl + ; フォントサイズ大(セミコロンの位置は +と覚える)
Ctrl + - フォントサイズ小
Option + Shift + J + X RUN (実行する)
Option + 矢印 行を移動する
Command + D 行を削除
Sift + Ctrl + F フォーマットの整形
Ctrl + Speace 入力補完
・tabで移動
・shift + tab で戻る
Shift + Ctrl + O インポート文整理(要らなくなったインポート文を消す)
Ctrl + Command + R リファクタリング
Ctrl + . エラー部分に移動
Ctrl + 1 クイックフィックス
Ctrl + N 新規作成
Option + Ctrl +S セッター・ゲッター生成
Option + Ctrl +S コンストラクタ生成
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

結局最初学ぶならJavaかなと思う

十数年Javaの仕事をやってきて、数年前よりJavaに飽きたしもっと効率よく開発できる言語があるのではないかと思ってPythonを使っていて社内でも新人にはじめからPythonを教えてきた。

2年前こんな記事を書いたりした。

Pythonはいい。環境構築がかなり手軽でかつスクリプト言語ならではの実装とデバッグの速さがある。
ただ、エンジニア志望の初学者はやはりJavaをやった方がいいと思った。もし、最初はJavaではないにしても一度は通ってほしい。

型宣言はやっぱりいい

数値を入れてた変数に文字列入れたり好き放題はやめてほしい。
でもプログラミング始めたばかりだとやってしまいがち。
混乱するし、型はしっかり意識したいところ。

オブジェクト指向やるなら

オブジェクト指向の一通りを学ぶにもJavaはいい。インタフェース、インスタンス変数、クラス変数などが概念に近い書き方をする。
他の言語でも学べなくはないけど概念のイメージがしやすいのはJavaだと思う。

色んな技術に触れやすい

構文が似ている

  • Javascript(Web技術に必須)・・・Web技術
  • C#(Unityも使える)・・・ゲーム
  • Kotlin(似ているというか派生だけど)・・・Androidアプリ
  • C言語(C言語の影響を受けてるから似てるところ多い)・・・制御系 それ以外もいけるけど
  • C++・・・なんでも来い?^^

C#は便利すぎる!?

これまでの特徴ならC#でもいい。
C#の書き方はほぼJavaのそれと変わりない。
C#はよくできていてC#が提供する部品内でほとんどのことができる。多少他のライブラリに頼るときもあるがJavaなどのように最初からいろんなライブラリを組み合わせないと始まらないということはない。
ずっとC#しかやらないと決めたならそれもありだが高見を目指すエンジニアとしてはいろんな技術を身につけたいと思うだろう。Javaだと最初キツイけどそのあとの伸び率に期待できると思った。

C言語もいいけど

プログラム基礎としてはかなりいいけど、初心者にはハードルが高い。ポインターという概念が難しい。
またオブジェクト指向が使えないから、やるならC++だけど、さらにハードルが高い。。
Webとかやろうと思うとキツイのも初心者には向かない理由かな。

対応できる幅が広くなる

Javaは業務システム、ECサイト、機械学習、帳票出力、バッチ、ほぼなんでも来い状態。
苦手なものがほとんどないのは強い。
他の技術でキツイときはJavaでやれば実現できるという保険にもなる。
Javaで作りたくないものだとデスクトップアプリ。デスクトップアプリ作るなら、node.js + ExpressかC#が作りやすいと思う。

Pythonをやっていると帳票とかちょっとつらい。定番のWingarc SVF使うにも都合がよくないCSV連携でなんとかできそうではあるが。。PDFも得意ではない。

まとめ

なにごとも基礎は大事。Javaは基礎になる要素がふんだんにあると再認識した。
十数年たってなんて面倒な技術なんだと感じたけど、その面倒な技術は私を強くしてくれた。

面倒くさいことがしっかりできたら他のことがやりやすいよ。と現時点はそんな結論に達した。

ただし、それはエンジニア志望の人向けのおすすめであって、大学の研究で使うなどエンジニアでなければこの限りではない。都合のいい技術をさくっと身につけてその特性を把握しながら使ったらいいと思う。

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