実行中のクラス名やメソッド名の取得

Thread.currentThread() を参照することで、

スレッド名 → Thread.currentThread().getName()
クラス名 → Thread.currentThread().getStackTrace()[1].getClassName()
メソッド名 → Thread.currentThread().getStackTrace()[1].getMethodName()

で取得できるので、以下のように staticメソッドのユーティリティクラスを用意すれば、、、

   public static String getClassName(){
      return Thread.currentThread().getStackTrace()[2].getClassName();
   }
   public static String getMethodName(){
      return Thread.currentThread().getStackTrace()[2].getMethodName();
   }

と思うが、落とし穴があって、ラムダ式の中で実行すると、

lambda$1 のように、メソッド名が取得できても役に立たない場合がある。
それなら、ラムダの場合は、コード上の行番号を付加したものを返す約束にすれば使えそうだ。

工夫して作ったのが以下のとおり。

public final class CurrentUtil{
   private CurrentUtil(){}

   /**
    * @return 実行中スレッド名
    */
   public static String getThreadName(){
      return Thread.currentThread().getName();
   }

   /**
    * @return 実行中クラス名
    */
   public static String getClassName(){
      return Thread.currentThread().getStackTrace()[2].getClassName();
   }

   /**
    * 実行中メソッド名取得.
    * @return 実行中メソッド名
    */
   public static String getMethodName(){
      return Optional.of(Thread.currentThread().getStackTrace()[2])
      .map(e->e.getMethodName().startsWith("lambda$")
         ? e.getMethodName() + ":" + e.getLineNumber() : e.getMethodName())
      .get();
   }
}

startsWithでラムダなんて判断しないで、以下の様にと考えもしたが、

Optional.of(Thread.currentThread().getStackTrace()[2])
.map(e->e.getClassName()
+ "." + e.getMethodName()
+ ":" + e.getLineNumber())
.get();

実際のラムダ式が使用されてるメソッドまできちんと出すには、getStackTrace()の配列をきちんと
順に解析しないとならない。
それよりも、getLineNumber() が返す行番号の方が役に立つ

Pattern to Stream

前から常に思っていたのですが、Java8 には、java.util.regex.Pattern に、splitAsStream があるのに、
matchAsStream に相当するマッチしたものをストリームで返すメソッドが提供されてないんだと不満でした。
Java9 なら、Matcher に、 Stream を取得できる
public Stream results()
が提供される予定のようです。もうすぐ Java9 が出るだろうが実運用がすぐに移行させてはもらえないでしょうし。

そこで代替えを探していたらネットにはたくさん溢れていたので、その中で納得のいくもの1つに手を
加えたものと1、もう1つを紹介

パターンマッチ → Spliterator → StreamSupport → Stream という目的の為のイテレータ

import java.util.Spliterators.AbstractSpliterator;
import java.util.function.Consumer;
import java.util.regex.Matcher;
/**
 * MatcherItrator
 */
public final class MatcherItrator extends AbstractSpliterator<CharSequence>{
   private final Matcher matcher;

   public MatcherItrator(Matcher m){
      super(m.regionEnd() - m.regionStart(), ORDERED|NONNULL);
      matcher = m;
   }
   @Override
   public boolean tryAdvance(Consumer<? super CharSequence> c){
      if (!matcher.find()) return false;
      c.accept(matcher.group());
      return true;
   }
}

この super の呼び出し、super(Long.MAX_VALUE, ORDERED|NONNULL); でも良いのではないかと考えるが。。。

サンプル

String string = " abc_def_ghi_..";

StreamSupport.stream(new MatcherItrator(Pattern.compile("[a-z]+").matcher(string)), false)
.forEach(e->{
  System.out.println(e);
});


Pattern と 検査対象を渡して、マッチ結果文字列Stream あるいは、MatchResultのStream を求める
ユーティリティクラス

import java.util.Spliterator;
import java.util.Spliterators.AbstractSpliterator;
import java.util.function.Consumer;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
 * MatcherStream
 */
public final class MatcherStream{
   private MatcherStream(){}

   public static Stream<String> find(Pattern pattern, CharSequence input){
      return findMatches(pattern, input).map(MatchResult::group);
   }

   public static Stream<MatchResult> findMatches(Pattern pattern, CharSequence input){
      Matcher matcher = pattern.matcher(input);
      Spliterator<MatchResult> spliterator
= new AbstractSpliterator<MatchResult>(Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.NONNULL){
         @Override
         public boolean tryAdvance(Consumer<? super MatchResult> action){
            if (!matcher.find()) return false;
            action.accept(matcher.toMatchResult());
            return true;
         }
      };
       return StreamSupport.stream(spliterator, false);
   }
}

Stream を求める

MatcherStream.find(Pattern.compile("[a-z]+"), string)
.forEach(e->{
  System.out.println(e);
});

java.util.regex.MatchResult の Stream を求める

MatcherStream.findMatches(Pattern.compile("[a-z]+"), string)
.forEach(r->{
   System.out.println(r.group()+" "+r.start());
}

Stream でListの中で特定要素があるインデックスを求める

完璧=普遍的とは言えないが、、
例)

List<String> list = Arrays.asList("a", "b", "c", "d", "e");
int findIndex =
IntStream.range(0, list.size()).map(i->list.get(i).equals("c") ? i : -1).max().orElse(-1);;

でも、2つ以上マッチする場合は、最後のインデックスを取得することになる。
それでなら、

int findIndex =
IntStream.range(0, list.size()).map(i->list.get(i).equals("c") ? i : -1)
.filter(i->i >= 0).min().getAsInt();

これで最初に見つかるインデックスであり、全てのインデックスは、

IntStream.range(0, list.size()).map(i->list.get(i).equals("c") ? i : -1).filter(i->i >= 0)

PaxHeaders.X が作られないように圧縮ファイルを作成する

apache commons compress で圧縮ファイル tar.gz を作成していたら、
階層が深かったり長すぎるファイル名で圧縮後、解凍を行ったときに、
PaxHeaders.X という名のディレクトリエントリ、中に展開したときに不完全に解凍されたファイルのパスが
作られてしまった。

tar の仕様の問題であるが、Apache commons compress で圧縮するときの回避として、

TarArchiveOutputStream の設定メソッドで、

setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);

ではなく、

setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);

で設定する。

以下も修正

tar and zip の圧縮・展開 - Oboe吹きプログラマの黙示録

 

tar.gz のファイルをアップロードしたら、ブラウザにより ContentTypeが違う。

Wicket ファイルアップロード実行で、受信する FileUpload で取得する ContentType
には、ブラウザによって違いがある。

tar.gz のファイルをアップロードした時、

chrome
application/x-compressed


edge と IE11
application/x-gzip-compressed

 

Wicket の FileUploadField を使っていて気づいた

ラムダ式の例外処理を綺麗にする

ラムダ式の中で例外が発生する場合は厄介なもので、何とかしようとするならラップに近い形で自分で用意するしかないみたい。

Consumer 、Function 、Predicate これらの例外捕捉処理バージョンを作っておけばかなり便利かもしれません。

import java.io.Serializable;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
 * ThrowableConsumer
 */
@FunctionalInterface
public interface ThrowableConsumer<T> extends Serializable{
   void accept(T t) throws Exception;

   default Consumer<T> andThen(Consumer<? super T> after, BiConsumer<T, Exception> onCatch){
      Objects.requireNonNull(after);
      return (T t)->{
         try{
            accept(t);
         }catch(Exception e){
            onCatch.accept(t, e);
         }
         after.accept(t);
      };
   }
   /**
    * ThrowableConsumer 生成.
    * @param consumer 例外スローする Consumer<T>処理
    * @param onCatch Exception捕捉処理
    * @return Consumer<T>
    */
   public static <T> Consumer<T> of(ThrowableConsumer<T> consumer, BiConsumer<T, Exception> onCatch){
      return t->{
         try{
            consumer.accept(t);
         }catch(Exception ex){
            onCatch.accept(t, ex);
         }
      };
   }
   /**
    * ThrowableConsumer 生成(外に例外スロー).
    * @param consumer 例外スローする Consumer<T>処理
    * @return Consumer<T>
    */
   public static <T> Consumer<T> of(ThrowableConsumer<T> consumer){
      return t->{
         try{
            consumer.accept(t);
         }catch(Throwable ex){
            throw new RuntimeException(ex);
         }
      };
   }
}
import java.io.Serializable;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
 * ThrowableFunction
 */
@FunctionalInterface
public interface ThrowableFunction<T, R> extends Serializable{
   R apply(T t) throws Exception;

   default <V> Function<V, R> compose(Function<? super V, ? extends T> before, BiFunction<V, Exception, R> onCatch){
      Objects.requireNonNull(before);
      return (V v)->{
         try{
            return apply(before.apply(v));
         }catch(Exception e){
            return onCatch.apply(v, e);
         }
      };
   }

   default <V> Function<T, V> andThen(Function<? super R, ? extends V> after, BiFunction<T, Exception,  ? extends V> onCatch){
      Objects.requireNonNull(after);
      return (T t)->{
         try{
            return after.apply(apply(t));
         }catch(Exception e){
            return onCatch.apply(t, e);
         }
      };
   }

   static <T> Function<T, T> identity(){
      return t -> t;
   }
   /**
    * ThrowableFunction 生成.
    * @param function 例外スローする Function<T, R>処理
    * @param onCatch Exception捕捉処理 , R を返すもしくは、null を返さなければならない。
    * @return Function<T, R>
    */
   public static <T, R> Function<T, R> of(ThrowableFunction<T, R> function, BiFunction<T, Exception, R> onCatch){
      return  t->{
         try{
            return function.apply(t);
         }catch(Exception e){
            return onCatch.apply(t, e);
         }
      };
   }
   /**
    * ThrowableFunction 生成(外に例外スロー).
    * @param function 例外スローする Function<T, R>処理
    * @return Function<T, R>
    */
   public static <T, R> Function<T, R> of(ThrowableFunction<T, R> function){
      return  t->{
         try{
            return function.apply(t);
         }catch(Throwable ex){
            throw new RuntimeException(ex);
         }
      };
   }
}
import java.io.Serializable;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Predicate;
/**
 * ThrowablePredicate
 */
@FunctionalInterface
public interface ThrowablePredicate<T> extends Serializable{

   boolean test(T t) throws Exception;

   default Predicate<T> and(Predicate<? super T> other){
      Objects.requireNonNull(other);
         return (t)->{
         try{
            return test(t) && other.test(t);
         }catch(Exception e){
            return false;
         }
      };
   }
   default Predicate<T> and(Predicate<? super T> other, BiFunction<T, Exception, Boolean> onCatch){
      Objects.requireNonNull(other);
         return (t)->{
         try{
            return test(t) && other.test(t);
         }catch(Exception e){
            return onCatch.apply(t, e);
         }
      };
   }

   default Predicate<T> negate(){
      return (t)->{
         try{
            return !test(t);
         }catch(Exception e){
            return false;
         }
      };
   }
   default Predicate<T> negate(BiFunction<T, Exception, Boolean> onCatch){
      return (t)->{
         try{
            return !test(t);
         }catch(Exception e){
            return !onCatch.apply(t, e);
         }
      };
   }

   default Predicate<T> or(Predicate<? super T> other){
      Objects.requireNonNull(other);
      return (t)->{
         try{
            return test(t) || other.test(t);
         }catch(Exception e){
            return false;
         }
      };
   }
   default Predicate<T> or(Predicate<? super T> other, BiFunction<T, Exception, Boolean> onCatch){
      Objects.requireNonNull(other);
      return (t)->{
         try{
            return test(t) || other.test(t);
         }catch(Exception e){
            return onCatch.apply(t, e);
         }
      };
   }

   static <T> Predicate<T> isEqual(Object targetRef){
      return (null==targetRef)  ? Objects::isNull : object -> targetRef.equals(object);
   }
   /**
    * ThrowablePredicate 生成.
    * @param p 例外スローする Predicate<T>処理
    * @param onCatch Exception捕捉処理 , boolean値を返さなければならない。
    * @return Predicate<T>
    */
   public static <T> Predicate<T> of(ThrowablePredicate<T> p, BiFunction<T, Exception, Boolean> onCatch){
      return t->{
         try{
            return p.test(t);
         }catch(Exception e){
            return onCatch.apply(t, e);
         }
      };
   }
   /**
    * ThrowablePredicate 生成(外に例外スロー).
    * @param p 例外スローする Predicate<T>処理
    * @return Predicate<T>
    */
   public static <T> Predicate<T> of(ThrowablePredicate<T> p){
      return t->{
         try{
            return p.test(t);
         }catch(Throwable ex){
            throw new RuntimeException(ex);
         }
      };
   }
}

これを使うものとして、
Javaで MACアドレスを抽出する - Oboe吹きプログラマの黙示録
の処理を書いてみましょう。

最初の NetworkInterface.getNetworkInterfaces() だけは、SocketException の捕捉を外側(呼出し側)で処理を書かなくては
ならないですが、
NetworkInterface の isUp() や、getHardwareAddress() で発生の Exception 捕捉処理は
ThrowableXxxxx . of メソッドに、ラムダで書くことができます。
  特に、Predicate で、(t, error)->false と、問答無用に無視を指定できるのが良いです。

Collections.list(NetworkInterface.getNetworkInterfaces()).stream()
.filter(ThrowablePredicate.of(t->t.isUp(), (t, error)->false))
.forEach(ThrowableConsumer.of(nf->{
	String address = Optional.ofNullable(nf.getHardwareAddress())
			.map(e->IntStream.range(0, e.length).mapToObj(i->String.format("%02X", e[i])).collect(Collectors.joining(" "))
		).orElse(null);

        System.out.printf("%d,%d,%s,\"%s\",%s%n"
            , nf.isLoopback() ? 1 : 0
            , nf.isUp() ? 1 : 0
            , nf.getName()
            , nf.getDisplayName()
            , address
        );
}, (e, error)->{}));

Javaで MACアドレスを抽出する

java.net.NetworkInterface を利用して抽出します。
NetworkInterface から、getHardwareAddress() で、ハードウエアのアドレス=MAC アドレスに相当が見れます。

NetworkInterface は、以下の static メソッドがあります。

getByIndex(int index)               → 指定インデックスのネットワークインターフェース
getByInetAddress(InetAddress addr) → 指定IPアドレスのネットワークインターフェース
getByName(String name) → 指定する名前のネットワークインターフェース
getNetworkInterfaces() → 実行マシン上のすべてのネットワークインターフェース

だいたい、getNetworkInterfaces か、getByInetAddress を使用するのが実践向きと考えます。

getNetworkInterfaces が返すのは、残念ながら、Enumeration です。

getNetworkInterfaces を実行すると Windows PC の場合、
Teredo Tunneling Pseudo-Interface
  IPv6 over IPv4トンネリングプロトコルとして割り当てたものまで採取できてしまいます。
これはよくみると、6バイトで表す MACアドレスになってませんでした。


全てを見る場合、Enumeration なので、仕方なく while ループで書いてみます。

try{
   Enumeration<NetworkInterface> nfs = NetworkInterface.getNetworkInterfaces();
   while(nfs.hasMoreElements()){
      NetworkInterface nf = nfs.nextElement();

      String address = Optional.ofNullable(nf.getHardwareAddress())
      .map(e->IntStream.range(0, e.length).mapToObj(i->String.format("%02X", e[i]))
               .collect(Collectors.joining(" ")))
      .orElse(null);

      System.out.printf("%d,%d,%s,\"%s\",%s%n"
         , nf.isLoopback() ? 1 : 0
         , nf.isUp() ? 1 : 0
         , nf.getName()
         , nf.getDisplayName()
         , address
      );
   }
}catch(SocketException ex){
   ex.printStackTrace();
}

NetworkInterface の isUp()メソッドが返す動作してるものだけ抽出は、これだとwhile文中にif文書かなければ
なりません。

isUp()メソッドをつかうものを単純に Stream で書いてみます。

try{
   Collections.list(NetworkInterface.getNetworkInterfaces())
   .stream().filter(n->{
      try{
         return n.isUp();
      }catch(SocketException e){
      }
      return false;
   }).forEach(nf->{
      try{
         String address = Optional.ofNullable(nf.getHardwareAddress())
            .map(e->IntStream.range(0, e.length)
                     .mapToObj(i->String.format("%02X", e[i])).collect(Collectors.joining(" ")))
            .orElse(null);
         System.out.printf("%d,%d,%s,\"%s\",%s%n"
            , nf.isLoopback() ? 1 : 0
            , nf.isUp() ? 1 : 0
            , nf.getName()
            , nf.getDisplayName()
            , address
         );
      }catch(SocketException ex){
         ex.printStackTrace();
      }
   });
}catch(SocketException ex){
   ex.printStackTrace();
}

ラムダの中に try~catch を書くハメになってみっともない。Predicate や Consumer の例外スローするものでも
用意するか。。。

getByInetAddress で1つの MACアドレスを抽出する場合、、、

try{
   NetworkInterface nf = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());

   String address = Optional.ofNullable(nf.getHardwareAddress())
         .map(e->IntStream.range(0, e.length).mapToObj(i->String.format("%02X", e[i]))
                  .collect(Collectors.joining(" ")))
         .orElse(null);

   System.out.printf("%d,%d,%s,\"%s\",%s%n"
      , nf.isLoopback() ? 1 : 0
      , nf.isUp() ? 1 : 0
      , nf.getName()
      , nf.getDisplayName()
      , address
   );

}catch(SocketException ex){
   ex.printStackTrace();
}catch(UnknownHostException ex){
   ex.printStackTrace();
}

InetAddress.getLocalHost() の実行で、UnknownHostException 捕捉も必要になります。