覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Gitでタグ付けたり消したり

コマンドラインでGitのタグを付けたり削除したりする方法


タグを付ける

ローカルでタグを付けて、その変更をリモートにpushするという流れになります

git tag {TAGNAME}

git push origin {TAGNAME}


リモートのタグを削除する

ローカルでタグを削除して、その変更をリモートにpushするという流れになります

git tag -d {TAGNAME}

git push origin :{TAGNAME}

Arrays#asListで生成されるList

JavaでListをリテラルに記述して生成する方法が基本的にないので、
文字列List等を作る際には基本的にArrays#asListを利用することが多いです。

ただし、Arrays#asListによってに生成されるクラスはArrayListという名前ですが、
いわゆるjava.util.ArrayListとは別物であるということを知っておかなければなりません。


サンプルコードを実行して確認してみます。

■サンプルコード

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

List<String> list1 = Arrays.asList("a", "b", "c");
System.out.println("## Arrays#asList");
System.out.println("class: " + list1.getClass());

// list1.add("d"); -> throw java.lang.UnsupportedOperationException
// list1.remove(0); -> throw java.lang.UnsupportedOperationException

System.out.println("--------------------");


List<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("b");
list2.add("c");

System.out.println("## ArrayList");
System.out.println("class: " + list2.getClass());

■実行結果

## Arrays.asList
class: class java.util.Arrays$ArrayList
--------------------
## ArrayList
class: class java.util.ArrayList

実行結果からArrays#asListによって生成されるオブジェクトはjava.util.Arrays$ArrayListというクラスであることが分かります


java.util.Arrays$ArrayList の実装内容

かなり省略していますがjava.util.Arrays$ArrayListは以下のような実装になっています。
addやremove等のメソッドはAbstractListから継承してオーバーライドされていないというのがポイントとなります。
(そのためUnsupportedOperationExceptionがスローされる状態になっています)

public class Arrays {

    private static class ArrayList<E> extends AbstractList<E>
            implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        @Override
        public int size() {
            return a.length;
        }

        @Override
        public Object[] toArray() {
            return a.clone();
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }

        @Override
        public E get(int index) {
            return a[index];
        }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

        @Override
        public int indexOf(Object o) {
            E[] a = this.a;
            if (o == null) {
                for (int i = 0; i < a.length; i++)
                    if (a[i] == null)
                        return i;
            } else {
                for (int i = 0; i < a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

        @Override
        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }

        @Override
        public Spliterator<E> spliterator() {
            return Spliterators.spliterator(a, Spliterator.ORDERED);
        }

        @Override
        public void forEach(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            for (E e : a) {
                action.accept(e);
            }
        }

    }

}



関連エントリ

日時オブジェクトのサイズをJOLで確認してみる

以前、JMHで現在日時取得のベンチマークを取得してみました。

今回は色々な日時オブジェクトのメモリサイズをJOLで確認してみます


対象

今回の測定対象とするクラスは以下です

  • java.util.Date
  • java.util.Calendar
  • java.time.LocalDateTime
  • java.time.LocalDate
  • java.time.LocalTime


メモリサイズ取得

以下のサンプルコードを実行してメモリサイズを取得してみました

■サンプルコード

import org.openjdk.jol.info.GraphLayout;


public class DateObjSize {
    private static java.util.Date utilDate = new java.util.Date();

    private static java.util.Calendar calendar = java.util.Calendar.getInstance();

    private static java.time.LocalDateTime localDateTime = java.time.LocalDateTime.now();

    private static java.time.LocalDate localDate = java.time.LocalDate.now();

    private static java.time.LocalTime localTime = java.time.LocalTime.now();

    public static void main(String[] args) {

        System.out.println("java.util.Date totalSize(byte) -> " + GraphLayout.parseInstance(utilDate).totalSize());
        System.out.println("java.util.Date footprint -> \n" + GraphLayout.parseInstance(utilDate).toFootprint());

        System.out.println("-------------");

        System.out.println("java.util.Calendar totalSize(byte) -> " + GraphLayout.parseInstance(calendar).totalSize());
        System.out.println("java.util.Calendar footprint -> \n" + GraphLayout.parseInstance(calendar).toFootprint());

        System.out.println("-------------");

        System.out.println("java.time.LocalDateTime totalSize(byte) -> " + GraphLayout.parseInstance(localDateTime).totalSize());
        System.out.println("java.time.LocalDateTime footprint -> \n" + GraphLayout.parseInstance(localDateTime).toFootprint());

        System.out.println("-------------");

        System.out.println("java.time.LocalDate totalSize(byte) -> " + GraphLayout.parseInstance(localDate).totalSize());
        System.out.println("java.time.LocalDate footprint -> \n" + GraphLayout.parseInstance(localDate).toFootprint());

        System.out.println("-------------");

        System.out.println("java.time.LocalTime totalSize(byte) -> " + GraphLayout.parseInstance(localTime).totalSize());
        System.out.println("java.time.LocalTime footprint -> \n" + GraphLayout.parseInstance(localTime).toFootprint());

    }
}


■実行結果

java.util.Date totalSize(byte) -> 24
java.util.Date footprint -> 
java.util.Date@aec6354d footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        24        24   java.util.Date
         1                  24   (total)


-------------
java.util.Calendar totalSize(byte) -> 712
java.util.Calendar footprint -> 
java.util.GregorianCalendar@58d25a40d footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        40        40   [C
         4        58       232   [I
         1        96        96   [J
         1        40        40   [Z
         1        24        24   java.lang.String
         1       112       112   java.util.GregorianCalendar
         1        16        16   sun.util.calendar.Gregorian
         1        96        96   sun.util.calendar.Gregorian$Date
         1        56        56   sun.util.calendar.ZoneInfo
        12                 712   (total)


-------------
java.time.LocalDateTime totalSize(byte) -> 72
java.time.LocalDateTime footprint -> 
java.time.LocalDateTime@1c4af82cd footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        24        24   java.time.LocalDate
         1        24        24   java.time.LocalDateTime
         1        24        24   java.time.LocalTime
         3                  72   (total)


-------------
java.time.LocalDate totalSize(byte) -> 24
java.time.LocalDate footprint -> 
java.time.LocalDate@7de26db8d footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        24        24   java.time.LocalDate
         1                  24   (total)


-------------
java.time.LocalTime totalSize(byte) -> 24
java.time.LocalTime footprint -> 
java.time.LocalTime@1175e2dbd footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        24        24   java.time.LocalTime
         1                  24   (total)


結果

表にまとめると以下の通りです

クラス メモリサイズ(byte)
java.util.Date 24
java.util.Calendar (java.util.GregorianCalendar) 712
java.time.LocalDateTime 72
java.time.LocalDate 24
java.time.LocalTime 24

クラスごとに特性があるので良い悪いと一概に言えませんが、Calendarのメモリサイズはかなり大きいことが分かります。



関連エントリ

Guava 21.0 がリリースされてた

Guavaの21.0がいつの間にかリリースされてました。

Release21 · google/guava Wiki · GitHub


今回からJava8必須になったようです。

色々変更があったようなので簡単に(ごく一部を)試してみます。


準備

pom.xmlに以下を追記します

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>


com.google.common.base.Optional

Java標準のOptional(java.util.Optional)との相互変換ができるようになっています。

  • Optional#toJavaUtil : GuavaのOptional -> java.util.Optional の変換を行います。
  • Optional#fromJavaUtil : java.util.Optional -> GuavaのOptional の変換を行います。


■サンプルコード

import com.google.common.base.Optional;

Optional guavaOpt1 = Optional.of("Some");

// Guava -> Java
java.util.Optional javaOpt = guavaOpt1.toJavaUtil();

// Java -> Guava
Optional guavaOpt2 = Optional.fromJavaUtil(javaOpt);


com.google.common.collect.Multimap

MultimapにforEachメソッドがいくつか追加されています

  • Multimap#foreach : Multimap内の(重複keyも含めた)全要素に対する処理を行うことができます。(引数にはkeyとvalueが渡されます)


■サンプルコード

import com.google.common.collect.Multimap;
import com.google.common.collect.ArrayListMultimap;

Multimap<String, String> multiMap = ArrayListMultimap.create();
multiMap.put("key1", "value1");
multiMap.put("key1", "value2");
multiMap.put("key1", "value3");
multiMap.put("key2", "data1");
multiMap.put("key3", "Taro");

// 引数にはkeyとvalueが渡される
System.out.println("## Multimap#foreach");
multiMap.forEach((k, v) -> System.out.println(k + ": " + v));

■実行結果

## Multimap#foreach
key1: value1
key1: value2
key1: value3
key2: data1
key3: Taro


com.google.common.collect.Multiset

Multisetにメソッドがいくつか追加されています

  • Multiset#foreach : Multiset内の(重複要素も含めた)全要素に対する処理を行うことができます。
  • Multiset#forEachEntry : Multiset内の各エントリに対する処理を行うことができます。エントリとして要素とその保持数が引数に渡されます
  • Multiset#size : Multiset内の(重複要素も含めた)全要素を取得することができます。


■サンプルコード

import com.google.common.collect.Multiset;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;

List<String> words = Lists.newArrayList("hello", "dog", "cat", "red", "hello", "hello", "dog", "blue", "blue");

Multiset<String> wordMultiSet = HashMultiset.create(words);

System.out.println("## Multiset#foreach");
wordMultiSet.forEach(e -> System.out.println(e));

System.out.println("\n");

System.out.println("## Multiset#forEachEntry");
wordMultiSet.forEachEntry((e, count) -> System.out.println(e + ":" + count));

System.out.println("\n");

System.out.println("## Multiset#size");
System.out.println("size : " + wordMultiSet.size());

■実行結果

## Multiset#foreach
red
blue
blue
cat
hello
hello
hello
dog
dog


## Multiset#forEachEntry
red:1
blue:2
cat:1
hello:3
dog:2


## Multiset#size
size : 9


com.google.common.collect.Streams

新しく追加されたクラスです、Stream APIにはない補助的なメソッドを提供してくれています

  • Streams#zip : 指定された2つのStream内の要素同士を合成することができます。
  • Streams#concat : 指定された複数のStreamを結合したStreamを返します。
  • Streams#findLast : Streamの内の最終要素をjava.util.Optionalで返します。


■サンプルコード

import com.google.common.collect.Streams;

List<Integer> list1 = Arrays.asList(0, 1, 2, 3, 4, 5);
List<Integer> list2 = Arrays.asList(12, 13, 14, 15, 16, 17);

List<Integer> zippedList =
        Streams.zip(list1.stream(), list2.stream(), (i1, i2) -> i1 + i2)
            .collect(Collectors.toList());

System.out.println("Streams#zip List: " + zippedList);


List<Integer> concatList = Streams.concat(list2.stream(), list1.stream())
        .collect(Collectors.toList());

System.out.println("Streams#concat List: " + concatList);


java.util.Optional<Integer> last = Streams.findLast(list1.stream());
last.ifPresent(val -> System.out.println("list1 last -> " +val));

■実行結果

Streams#zip List: [12, 14, 16, 18, 20, 22]
Streams#concat List: [12, 13, 14, 15, 16, 17, 0, 1, 2, 3, 4, 5]
list1 last -> 5



関連エントリ

ND4J - Scalaで行列の演算

前回のエントリでND4Jを利用して、Javaプログラムでの行列の演算を試しました

今回は行列の演算をScalaから実行してみます。


準備

開発はsbtを用います。

build.sbtに以下を追記します

libraryDependencies ++= Seq(
  "org.nd4j" % "nd4j-native-platform" % "0.7.2",
  "org.slf4j" % "slf4j-api" % "1.7.22",
  "ch.qos.logback" % "logback-classic" % "1.1.8"
)


各種演算

行列の和

行列と行列の足し算です。

\begin
{bmatrix}
1.0 \ 2.0 \\
3.0 \ 4.0
\end
{bmatrix}
+
\begin
{bmatrix}
11.0 \ 12.0 \\
13.0 \ 14.0
\end
{bmatrix}=\begin{bmatrix}
12.0 \ 14.0 \\
16.0 \ 18.0
\end{bmatrix}

■サンプルコード

import org.nd4j.linalg.factory.Nd4j

val matrixA = Nd4j.create(Array(1.0, 2.0, 3.0, 4.0), Array(2, 2))
val matrixB = Nd4j.create(Array(11.0, 12.0, 13.0, 14.0), Array(2, 2))

val matrixRet1 = matrixA.add(matrixB)
println("Ret1: \n" + matrixRet1)

■実行結果

Ret1: 
[[12.00, 14.00],
 [16.00, 18.00]]


行列の差

行列と行列の引き算です。

\begin
{bmatrix}
1.0\ 2.0 \\
3.0\ 4.0
\end
{bmatrix}
-
\begin
{bmatrix}
11.0\ 12.0 \\
13.0\ 14.0
\end
{bmatrix}=\begin{bmatrix}
-10.0\ -10.0 \\
-10.0\ -10.0
\end{bmatrix}

■サンプルコード

import org.nd4j.linalg.factory.Nd4j

val matrixA = Nd4j.create(Array(1.0, 2.0, 3.0, 4.0), Array(2, 2))
val matrixB = Nd4j.create(Array(11.0, 12.0, 13.0, 14.0), Array(2, 2))

val matrixRet2 = matrixA.sub(matrixB)
println("Ret2: \n" + matrixRet2)

■実行結果

Ret2: 
[[-10.00, -10.00],
 [-10.00, -10.00]]


行列×スカラー

行列をスカラー倍します。

\begin
{bmatrix}
1.0\ 2.0\\
3.0\ 4.0
\end
{bmatrix}
\cdot3=\begin{bmatrix}
3.0\ 6.0 \\
9.0\ 12.0
\end{bmatrix}

■サンプルコード

import org.nd4j.linalg.factory.Nd4j

val matrixA = Nd4j.create(Array(1.0, 2.0, 3.0, 4.0), Array(2, 2))

val matrixRet3 = matrixA.mul(3)
println("Ret3: \n" + matrixRet3)

■実行結果

Ret3: 
[[3.00, 6.00],
 [9.00, 12.00]]


行列と行列の積

行列と行列のかけ算です

\begin
{bmatrix}
1.0\ 2.0\\
3.0\ 4.0
\end
{bmatrix}
\begin
{bmatrix}
11.0\ 12.0\\
13.0\ 14.0
\end
{bmatrix}=\begin{bmatrix}
37.0\ 40.0 \\
85.0\ 92.0
\end{bmatrix}

■サンプルコード

import org.nd4j.linalg.factory.Nd4j

val matrixA = Nd4j.create(Array(1.0, 2.0, 3.0, 4.0), Array(2, 2))
val matrixB = Nd4j.create(Array(11.0, 12.0, 13.0, 14.0), Array(2, 2))

val matrixRet4 = matrixA.mmul(matrixB)
println("Ret4: \n" + matrixRet4)

■実行結果

Ret4: 
[[37.00, 40.00],
 [85.00, 92.00]]


零行列との積

行列と零行列のかけ算です

\begin
{bmatrix}
1.0\ 2.0\\
3.0\ 4.0
\end
{bmatrix}
\begin
{bmatrix}
0.0\ 0.0\\
0.0\ 0.0
\end
{bmatrix}=\begin{bmatrix}
0.0\ 0.0 \\
0.0\ 0.0
\end{bmatrix}

■サンプルコード

import org.nd4j.linalg.factory.Nd4j

val matrixA = Nd4j.create(Array(1.0, 2.0, 3.0, 4.0), Array(2, 2))
val zeroMatrix = Nd4j.zeros(2, 2)

val matrixRet5 = matrixA.mmul(zeroMatrix)
println("Ret5: \n" + matrixRet5)

■実行結果

[[0.00, 0.00],
 [0.00, 0.00]]


単位行列との積

行列と単位行列のかけ算です

\begin
{bmatrix}
1.0\ 2.0\\
3.0\ 4.0
\end
{bmatrix}
\begin
{bmatrix}
1.0\ 0.0\\
0.0\ 1.0
\end
{bmatrix}=\begin{bmatrix}
1.0\ 2.0 \\
3.0\ 4.0
\end{bmatrix}

■サンプルコード

import org.nd4j.linalg.factory.Nd4j

val matrixA = Nd4j.create(Array(1.0, 2.0, 3.0, 4.0), Array(2, 2))
val identityMatrix = Nd4j.eye(2)

val matrixRet6 = matrixA.mmul(identityMatrix)
println("Ret6: \n" + matrixRet6)

■実行結果

Ret6: 
[[1.00, 2.00],
 [3.00, 4.00]]


転置行列

対象行列Cの転置行列を求めます

\begin
{equation}
C=
\begin
{bmatrix}
1.0\ 2.0\ 3.0\\
4.0\ 5.0\ 6.0\\
7.0\ 8.0\ 9.0
\end{bmatrix}
\end{equation}

\begin
{equation}
C^{T}=
\begin
{bmatrix}
1.0\ 4.0\ 7.0\\
2.0\ 5.0\ 8.0\\
3.0\ 6.0\ 9.0
\end{bmatrix}
\end{equation}

■サンプルコード

import org.nd4j.linalg.factory.Nd4j

val matrixC = Nd4j.create(Array(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0), Array(3, 3))

val matrixRet7 = matrixC.transpose()

println("Raw Matrix: \n" + matrixC)
println("Transposed Matrix: \n" + matrixRet7)

■実行結果

Raw Matrix: 
[[1.00, 2.00, 3.00],
 [4.00, 5.00, 6.00],
 [7.00, 8.00, 9.00]]
Transposed Matrix: 
[[1.00, 4.00, 7.00],
 [2.00, 5.00, 8.00],
 [3.00, 6.00, 9.00]]


逆行列

対象行列Aの逆行列を求めます

\begin
{equation}
A=
\begin
{bmatrix}
1.0\ 2.0 \\
3.0\ 4.0
\end
{bmatrix}
\end
{equation}

\begin
{equation}
A^{-1}=
\begin
{bmatrix}
-2.0\ 1.0 \\
1.5\ -0.5
\end{bmatrix}
\end{equation}

■サンプルコード

import org.nd4j.linalg.factory.Nd4j
import org.nd4j.linalg.inverse.InvertMatrix

val matrixC = Nd4j.create(Array(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0), Array(3, 3))

val matrixRet8 = InvertMatrix.invert(matrixA, false)

println("Raw Matrix: \n" + matrixA)
println("Invert Matrix: \n" + matrixRet8)

// 元の行列×逆行列=単位行列
println("identity Matrix: \n" + matrixA.mmul(matrixRet8))

■実行結果

Raw Matrix: 
[[1.00, 2.00],
 [3.00, 4.00]]
Invert Matrix: 
[[-2.00, 1.00],
 [1.50, -0.50]]
identity Matrix: 
[[1.00, 0.00],
 [0.00, 1.00]]



関連エントリ