Skip to content

Instantly share code, notes, and snippets.

@yusuiked
Last active October 16, 2020 16:07
Show Gist options
  • Save yusuiked/9662641 to your computer and use it in GitHub Desktop.
Save yusuiked/9662641 to your computer and use it in GitHub Desktop.
Sample code to sort by word length.
import java.util.concurrent.atomic.LongAdder;
public class ConcurrentNew {
public static void main(String[] args) {
// Java8 から追加された、複数スレッドからアトミックに更新できる Long 型の LongAdder
// Java5 からある、AtomicInteger などと同じような考え方だが、Atomic系のクラスよりも高いパフォーマンスを出す。
// 複数スレッドから頻繁に更新するようなケースで高いパフォーマンスを発揮する。
// 他にも DoubleAdder などがある。
LongAdder longAdder = new LongAdder();
// 加算
longAdder.add(100);
// インクリメント
longAdder.increment();
// デクリメント
longAdder.decrement();
// 値を long 型で取得
long l = longAdder.longValue();
}
}
public interface DefaultImplementation {
/*
* Java8 ではインタフェースでメソッドのデフォルト実装を提供できるようになった。
* このインタフェースを実装したクラスは、自分でメソッドを実装しなくてもインタフェースで定義されたメソッドが利用可能。
* デフォルト実装をオーバーライドすることも可能。
*
* Ruby や Scala における Mix-in と同じような機能。
*
* インタフェースを実装するために、特定のオブジェクトに処理をデリゲートするような場合は、
* インタフェースにデフォルト実装として定義しておくことで、実装クラスでの冗長な記述が不要になる。
*/
default public String hello(String name) {
return "Hello " + name;
}
/*
* Java8 では、インタフェースに static メソッドを定義することも可能。
* インタフェースの実装を返すファクトリメソッドなどを、別途クラスを用意しなくてもOK。
*
* Java8 の標準クラスとして新しく java.util.Stream というインタフェースが追加されたが、このインタフェースでも、
* java.util.Stream インタフェースの static メソッドとして Stream を生成するためのファクトリメソッドが定義されている。
* (ex. java.util.Stream#of(T t) など。)
*/
public static String message() {
return "Hello, Interface";
}
}
import java.util.function.Function;
import java.util.logging.Logger;
public class FunctionalInterfaceSample {
private static final Logger logger = Logger.getLogger("hoge");
public static void main(String[] args) {
// ラムダ式を変数に代入
TriFunction function = (a, b, c) -> a + b + c;
int result = function.apply(1, 2, 3);
System.out.println(result);
// hoge を10回繰り返した文字列を取得
String value = repeat("hoge").apply(10);
System.out.println(value);
// Logger はログレベルが合ってるものだけをラムダ式として評価するので、昔のログレベルチェックする if 文は要らない
// if (logger.isLoggable(Level.INFO)) {
// logger.info("info:" + value);
// }
// こう書く
logger.info(() -> "info:" + value);
}
/*
* 文字列を指定した回数繰り返す関数を返す
*/
private static Function<Integer, String> repeat(String value) {
return times -> {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < times; i++) {
sb.append(value);
}
return sb.toString();
};
}
@FunctionalInterface
private interface TriFunction {
public int apply(int a, int b, int c);
}
}
  • Function<T, R> … 1つの引数を受け取って結果を返す関数
  • BiFunction<T, U, R> … 2つの引数を受け取って結果を返す関数
  • UnaryOperator … 単項演算子
  • BinaryOperator … 二項演算子
  • Predicate … 1つの引数を受け取る条件式
  • BiPredicate<T, U> … 2つの引数を受け取る条件式
  • Supplier … 引数を取らず、値を返すだけの関数
  • Consumer … 1つの引数を受け取る戻り値のない関数
  • BiConsumer<T, U> … 2つの引数を受け取る戻り値のない関数
メソッド 内容
forEach() Mapの各要素に対してラムダ式で繰り返し処理を行う
putIfAbsent() 指定した値が存在しない場合だけMapに値を追加する
replace() 指定したキーが存在する場合だけMapの値を上書きする
replaceAll() Mapの各要素をラムダ式で置換する
compute() ラムダ式の戻り値を指定したキーでMapに追加する
computeIfAbsent() 指定したキーが存在しない場合だけラムダ式の戻り値をMapに追加する
computeIfPresent() 指定したキーが存在する場合だけラムダ式の戻り値でMapの値を上書きする
getOrDefault() 指定したキーの値を返す。キーが存在しない場合はデフォルト値を返す
merge() 指定したキーが存在しない場合は値を追加、存在する場合は既存の値と指定した値をマージする
import java.time.*;
import java.util.Date;
public class JavaTimeAPI {
/*
* Java8 で新規追加された Java Time API。
* 日時の計算処理については従来のCalendarやDateを使用した場合との違いは一目瞭然で、Time APIでは非常に簡潔に記述できる。
* Java 8では積極的にTime APIを活用するようにしたい。
*/
public static void main(String[] args) {
// 現在日時を取得
LocalDateTime localDateTime = LocalDateTime.now();
// 現在日を取得
LocalDate localDate = LocalDate.now();
// 現在時刻を取得
LocalTime localTime = LocalTime.now();
// 年月日時分まで指定して取得
LocalDateTime specifiedDateTime = LocalDateTime.of(2014, 07, 12, 12, 5);
// 2年6ヶ月後の日付を取得
LocalDateTime result1 = localDateTime.plusYears(2).plusMonths(6);
System.out.println(result1);
// 2週間前の日付を取得
LocalDate result2 = localDate.minusWeeks(2);
System.out.println(result2);
// Time APIの日時オブジェクトと、現行の java.util.Date オブジェクトを相互に変換
Date date1 = new Date();
System.out.println(date1);
Instant instant1 = date1.toInstant();
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant1, ZoneId.of("Asia/Tokyo"));
System.out.println(zonedDateTime);
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
Instant instant2 = Instant.from(now);
Date date2 = Date.from(instant2);
System.out.println(date2);
}
}

Java Time API で日時を表すための型

内容
LocalDate タイムゾーンを持たない日付
LocalDateTime タイムゾーンを持たない日時
LocalTime タイムゾーンを持たない時刻
OffsetDateTime UTCからの時差を持つ日時
OffsetTime UTCからの時差を持つ時刻
ZonedDateTime タイムゾーンを持つ日時
Duration 時間の量
Period 日付の量
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class LambdaSample {
public static void main(String[] args) {
List<String> langs = Arrays.asList("Java", "Groovy", "Scala", "JRuby", "Clojure", "Kotlin", "Jython");
sortByWordLengthUntilJava7(langs);
sortByWordLengthSinceJava8(langs);
}
private static void sortByWordLengthSinceJava8(List<String> langs) {
langs.sort((o1, o2) -> o1.length() - o2.length());
langs.forEach(System.out::println);
// ↑は↓と等価
langs.forEach(s -> System.out.println(s));
}
private static void sortByWordLengthUntilJava7(List<String> langs) {
Collections.sort(langs, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
for (String lang : langs) {
System.out.println(lang);
}
}
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class LazyEvaluationAndParallel {
/*
* Stream はラムダ式を使って関数型言語のようなスタイルで操作することができるため、
* 従来のコレクションの操作に使っても便利だが、遅延評価可能なコレクションという特徴も持っている。
*
* また、並列処理可能なStreamも生成できる。並列処理可能なStreamでは、map()やfilter()などのメソッドで
* 各要素に対する処理が自動的に並列に実行されるため、処理の高速化が期待できる。
*/
public static void main(String[] args) {
LazyEvaluation();
ParallelOperation();
}
/*
* 通常のStreamでは各要素に対する処理は要素の格納順に行われるが、
* 並列処理可能なStreamでは要素の格納順と処理の順番がばらばらになる
*/
private static void ParallelOperation() {
// List から並列処理可能なStreamを取得する
List<String> list = Arrays.asList("Java", "Groovy", "Scala");
list.parallelStream()
.map(s -> s.toUpperCase())
.forEach(System.out::println);
// Streamから並列処理可能なStreamを取得する
IntStream.range(1, 100)
.parallel()
.filter(i -> i % 2 == 0)
.forEach(System.out::println);
// なお、並列処理可能なStreamに対して sequential() メソッドを呼び出して
// シーケンシャルに処理が実行される通常の Stream を取得することができる。
IntStream.range(1, 100)
.parallel()
.filter(i -> i % 2 == 0)
.sequential()
.forEach(System.out::println);
}
private static void LazyEvaluation() {
// 10, 20, 40, 80…と無限に値を返すStreamを生成する
// この時点では実際に生成されている要素はまだ確定していない
Stream<Integer> stream = Stream.iterate(10, i -> i * 2);
// 先頭の5件のみ表示
// forEach しながら1件ずつ要素を評価(確定)させていき、5件目までしか計算しない
// これが遅延評価
stream.limit(5).forEach(System.out::println);
}
}
import java.util.function.Consumer;
public class MethodReferenceSample {
public static void main(String[] args) {
// メソッド参照の関数型インタフェース型変数への代入
Consumer<String> c = System.out::println;
c.accept("Hello, World!");
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class NewCollectionAPI {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("Java", "Scala", "Groovy"));
// Listの要素に対してラムダ式で繰り返し操作を行う
list.forEach(s -> System.out.println("[" + s + "]"));
// ラムダ式で指定した条件でソート(文字数が多い順にソート)
list.sort((o1, o2) -> o2.length() - o1.length());
// Listの要素をラムダ式で変換する(大文字に変換)
list.replaceAll(s -> s.toUpperCase());
// 条件に一致する要素を削除する(Jで始まる要素を削除する)
list.removeIf(s -> s.startsWith("J"));
list.forEach(s -> System.out.println("[" + s + "]"));
}
}
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
public class NewMapAPI {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
// キーが存在しない場合のデフォルト値を指定して値を取得
Integer v = map.getOrDefault("D", -1);
System.out.println(v);
// Mapの要素に対してラムダ式で繰り返し処理を行う
map.forEach((key, value) -> System.out.println(key + "=" + value));
// キーが存在しない場合のみMapに要素を追加
map.putIfAbsent("D", 4);
// キーが存在する場合のみMapの要素の値を上書き
map.replace("A", 5);
// Mapの要素をラムダ式で置換する
map.replaceAll((key, value) -> value * 2);
// キーが存在しない場合のみラムダ式の戻り値をMapに追加
map.computeIfAbsent("A", (key) -> LocalDate.now().getYear());
// キーが存在する場合のみラムダ式の戻り値でMapの要素を上書き
map.computeIfPresent("A", (key, value) -> value * 3);
map.forEach((key, value) -> System.out.println(key + "=" + value));
}
}
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class NIONewMethod {
/*
* Java8で java.nio.Files に新たに追加されたStreamを生成するためのメソッドを使っている。
* java.io パッケージのストリーム処理(FileInputStream や FileReader など)を使った
* ファイル入出力処理のコードよりも大幅に短く簡潔に書くことができるようになっていることに注目したい。
*
* これらのメソッドが返すStreamは FileInputStream などと同様、使用後はクローズする必要があるが、
* Stream は AutoCloseable インタフェースを実装しているため、Java7 で導入された
* try-with-resources 文を使用することでクローズを明示的に行わなくても確実にクローズすることができる。
*/
public static void main(String[] args) throws IOException {
// カレントディレクトリのファイル一覧を返すStreamを取得する
{
try (Stream<Path> stream = Files.list(Paths.get("."))) {
stream.forEach(System.out::println);
}
}
// ファイルの内容を1行ごとに返すStreamを取得する
{
try (Stream<String> stream = Files.lines(Paths.get("./java.util.Functionパッケージ.md"), StandardCharsets.UTF_8)) {
stream.forEach(System.out::println);
}
}
// カレントディレクトリ配下のファイルをツリーウォークするStreamを取得する
{
try (Stream<Path> stream = Files.walk(Paths.get("."), Integer.MAX_VALUE)) {
stream.forEach(System.out::println);
}
}
// カレントディレクトリ配下から「.java」で終わるファイルを検索する
{
try (Stream<Path> stream = Files.find(Paths.get("."), Integer.MAX_VALUE, (path, attr) -> path.toString().endsWith(".java"))) {
stream.forEach(System.out::println);
}
}
// BufferedReader にも1行ごとに文字列を返す lines() メソッドが追加されている。
// こちらは Stream の close() メソッドでは BufferedReader はクローズされず、
// BufferedReader 自体をクローズする必要があるので注意。
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("./java.util.Mapに追加された新しいAPI.md"), "UTF-8"))) {
reader.lines().forEach(System.out::println);
}
}
}
}
import javax.print.attribute.standard.DateTimeAtCompleted;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;
public class OptionalSample {
/*
* Java8 で新しく追加された Optional という型のサンプル。
* Optional は、存在するかどうかわからない値を表す型。従来は、null を使って表すことが多かったが、
* そのために各所で null チェックするコードが必要になっており、忘れると NullPointerException が発生していた。
*
* Optional を使うと、値が存在しないかもしれないということを明示することができ、nullチェックを忘れてしまうという
* 単純なミスを防止することができる。
*/
public static void main(String[] args) throws Exception {
// Optional のオブジェクトは値の有無に応じてインスタンスを生成する。
// 値を持つ Optional オブジェクト(of()メソッドにはnullを渡すと例外をスローする)
Optional<String> exist = Optional.of("123");
// 値を持たない空の Optional オブジェクト
Optional<String> empty = Optional.empty();
// 値がnull以外の場合は値を持つOptional、nullの場合は空のOptionalを生成する
String value0 = null;
Optional<String> optional0 = Optional.ofNullable(value0);
System.out.println(optional0);
Optional<String> optional = Optional.ofNullable(null);
// Optional オブジェクトからは以下のようにして値を取得できる
// 値を取得(空の場合はNoSuchElementExceptionがスローされる
String value1 = optional.get();
// 値を取得(空の場合は空文字列を返す)
String value2 = optional.orElse("");
// 値を取得(空の場合はラムダ式の結果を返す)
String value3 = optional.orElseGet(() -> new SimpleDateFormat("yyyyMMddHHmmSS").format(new Date()));
// 値を取得(空の場合は例外をスローする)
String value4 = optional.orElseThrow(() -> new Exception("値がありません"));
}
}
import java.io.UnsupportedEncodingException;
import java.util.*;
public class OtherChanges {
/*
* その他既存の機能に追加されたもの
*/
public static void main(String[] args) {
List<String> list = Arrays.asList("Java", "Groovy", "Scala");
// Stringクラスに、配列やリストに格納された要素を指定したデリミタで結合する join() メソッドが追加された
String str = String.join(", ", list);
System.out.println(str);
// Base64クラスに追加されたエンコードメソッド
String s = Base64.getEncoder().encodeToString("エンコード前の文字列".getBytes());
System.out.println("エンコードすると:" + s);
// デコード
byte[] decode = Base64.getDecoder().decode(s);
System.out.println("デコードすると:" + new String(decode));
// Java7 で導入されたダイヤモンド演算子。ジェネリクスの型パラメータを省略できる
Map<String, List<String>> map = new HashMap<>();
map.put("key", new ArrayList<>()); // Java8 でメソッド呼び出しの引数もダイヤモンド演算子が使える(Java7ではエラー)
// 以下、メソッドの型パラメータも自明な場合は省略可能
// Java7 の場合
List<List<String>> list2 = new ArrayList<>();
list2.add(Collections.<String>emptyList());
// Java8 の場合
List<List<String>> list3 = new ArrayList<>();
list3.add(Collections.emptyList());
}
}
import java.util.Arrays;
public class ParallelSort {
public static void main(String[] args) {
int[] array = {7, 6, 3, 4, 1, 2, 9};
// Java7 から追加された Fork/Join Framework を使った並列ソート。高速なソート。
Arrays.parallelSort(array);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.StampedLock;
public class StampedLockSample {
private final StampedLock lock = new StampedLock();
private int a;
private int b;
public void setValues(int a, int b) {
// 書き込みロックを取得
long stamp = lock.writeLock();
// 値を更新
this.a = a;
this.b = b;
// 書き込みロックを解放
lock.unlockWrite(stamp);
}
public int calculate() {
// 楽観的読み取りのためのスタンプを取得
long stamp = lock.tryOptimisticRead();
// 値を読み取り
int currentA = this.a;
int currentB = this.b;
// 他のスレッドから値が更新されていないことを確認
if (!lock.validate(stamp)) {
// 他のスレッドから値が更新されていた時は読み取りロックを取得して読み取り
stamp = lock.readLock();
currentA = this.a;
currentB = this.b;
// 読み取りロックを解放
lock.unlockRead(stamp);
}
return currentA + currentB;
}
// TODO サンプルコード書く
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamSample {
public static void main(String[] args) {
streamList();
streamOperation();
streamGeneration();
streamToList();
}
private static void streamToList() {
Stream<String> stream = Stream.of("Java", "Groovy", "Scala", "JavaScript");
// Stream から List へ変換
stream.collect(Collectors.toList());
}
private static void streamGeneration() {
// 固定の要素からIntStreamを生成する
IntStream intStream1 = IntStream.of(1, 2, 3);
// 配列からIntStreamを生成する
int[] array = {1,2,3};
IntStream intStream2 = IntStream.of(array);
// 1から10までの値を返すIntStreamを生成する
IntStream intStream3 = IntStream.range(1, 10);
// Stream#mapToInt()メソッドでIntStreamに変換
Stream<String> stream = Stream.of("Java", "Scala", "Groovy", "JavaScript");
IntStream intStream4 = stream.mapToInt(s -> s.length());
}
private static void streamOperation() {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
// 初期値を指定せずに集計(戻り値はOptional<Integer>)
// ((((1 * 2) * 3) * 4) * 5) という計算が行われる
Optional<Integer> result = stream.reduce((a, b) -> a * b);
System.out.println(result);
// 初期値を指定して集計(戻り値はInteger)
// ((((1 * 1) * 2) * 3) * 4) * 5) という計算が行われる
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);
Integer result2 = stream2.reduce(1, (a, b) -> a * b);
System.out.println(result2);
// 合計値を取得
IntStream intStream = IntStream.of(1, 2, 3, 4, 5);
int total = intStream.sum();
System.out.println(total);
// 終端メソッドを呼び出した後にStreamのインスタンスを利用しようとするとIllegalStateException
// intStream.forEach(System.out::println);
}
private static void streamList() {
List<String> list = Arrays.asList("Java", "Scala", "Groovy");
list.stream()
.map(s -> s.toUpperCase())
.sorted((a, b) -> b.length() - a.length())
.forEach(System.out::println);
// "J"で始まる要素のみにフィルタリング
list.stream()
.filter(s -> s.startsWith("J"))
.forEach(System.out::println);
// 先頭の一文字が同一の要素をグルーピング
Map<Character,List<String>> map = list.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0)));
System.out.println(map.get('J'));
System.out.println(map.get('G'));
System.out.println(map.get('S'));
// すべての要素が"J"で始まるかどうか
boolean result1 = list.stream().allMatch(s -> s.startsWith("J"));
// "J"で始まる要素があるかどうか
boolean result2 = list.stream().anyMatch(s -> s.startsWith("J"));
// "J"で始まる要素がないかどうか
boolean result3 = list.stream().noneMatch(s -> s.startsWith("J"));
}
}
public class SubstantialFinalSample {
public static void main(String[] args) {
SubstantialFinalSample sample = new SubstantialFinalSample();
sample.outer("Hello,World!");
}
private void outer(String message) {
Runnable r = () -> {
// ラムダ式の中から outer メソッドの引数を参照可能
System.out.println(message);
};
// 変数を再代入するとコンパイルエラー
// message = "hoge";
r.run();
}
}
import com.sun.istack.internal.NotNull;
public class TypeAnnotation {
static Object getObject() {
return null;
}
public static void main(String[] args) {
@NotNull Object object = getObject(); // @NotNull アノテーションを型に対して付与しておくことで、事前にエラーを検出することができる
System.out.println(object.toString());
}
}
public class UnsignedNumber {
/*
* Java8 から、通常の符号あり整数だけでなく、符号なし整数もサポートされた。
* Java8 までは、組み込みの整数型の範囲を超える値を表したい場合、BigDecimal 型を使う必要があった。
* BigDecimal は内部的に文字列型で値を保持するため、プリミティブ型での処理と比べると効率が悪かった。
*/
public static void main(String[] args) {
// intの最大値に対して加算する
int i = Integer.MAX_VALUE + 1;
// そのまま表示すると桁あふれを起こし負の数として表示される
System.out.println(i);
// Integer#toUnsignedString()で符号なし整数として表示すると正しい結果が表示される
System.out.println(Integer.toUnsignedString(i));
// 符号なし整数の四則演算は、加算・減算・乗算は通常の整数と同じように組み込みの算術演算子を使用して計算するが、
// 除算及び剰余については、計算対象の値を符号付き整数とみなすか符号なし整数とみなすかで計算結果が変わってしまう場合が
// あるため、IntegerクラスまたはLongクラスのdevideUnsigned()メソッド、remainderUnsigned()メソッドを使用する必要がある。
int a = Integer.MAX_VALUE + 1;
int b = Integer.MAX_VALUE + 2;
// 除算
int result1 = Integer.divideUnsigned(a, b);
System.out.println(result1);
// 剰余
int result2 = Integer.remainderUnsigned(a, b);
System.out.println(result2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment