Java SE 7以上

Java SE 9 以上

Java SE7

★基本

// 2進数リテラルと整数リテラル区切り文字

int billion = 1_000_000_000;

int binary = 0b1001_1001;

// ジェネリクスの省略記法

Map<String, String> map = new HashMap<>();

// switch文で文字列

if(arg == null) {

return;

}

switch(arg) {

case "aaa":

break;

case "bbb":

break;

default:

break;

}

★例外

// マルチキャッチ

try {

} catch (IOException

| IllegalArgumentException

| ParserConfigurationException

| SAXException ex) {

...

}

// 安全な再スロー

//public void doSomething() throws Exception{

private void doSomething()

throws IOException,

IllegalArgumentException,

ParserConfigurationException,

SAXException {

try {

...

} catch (Exception ex) {

throw ex;

}

}

※継承関係がある例外をキャッチする場合、スーパークラスの例外のみを記述すること

★リソースの自動管理

従来

InputStream in = null;

OutputStream out = null;

try {

in = new FileInputStream(...);

out = new FileOutputStream(...);

byte[] buf = new byte[1024];

int n;

while((n = in.read(buf)) >= 0) {

out.write(buf, 0, n);

}

} catch (IOException ex) {

...

} finally {

try {

if (in != null) {

in.close();

}

if (out != null) {

out.close();

}

} catch (IOException ex) {}

}

Java SE7以降

try (InputStream in = new FileInputStream(...);

OutputStream out = new FileOutputStream(...)) {

byte[] buf = new byte[1024];

int n;

while((n = in.read(buf)) >= 0) {

out.write(buf, 0, n);

}

} catch (IOException ex) {

...

}

public void execute() throws Exception {

try (

Closable1 c1 = new Closable1();

Closable2 c2 = new Closable2();

) {

...

} finally {

out.println("finally");

}

}

class Closable1 implements AutoCloseable {

@Override

public void close() throws Exception {

out.println("Closable1");

}

}

class Closable2 implements AutoCloseable { ... }

出力

Closable2

Closable1

finally

★New I/O 2

新しいファイルシステムインタフェース

非同期I/O

NIO/NIO2を参照

★Fork/Join Framework

細粒度の並行処理

サンプル1

class FibonacciTask extends RecursiveTask<Integer> {

private final int n;

public FibonacciTask(int n) {

this.n = n;

}

@Override

protected Integer compute() {

if (n <= 1) {

return n;

}

FibonacciTask f1 = new FibonacciTask(n - 1);

f1.fork();

FibonacciTask f2 = new FibonacciTask(n - 2);

// 処理結果を足し合せる

return f2.compute() + f1.join();

}

}

// 利用側

final ForkJoinPool pool = new ForkJoinPool();

// プールにタスクを登録し、実行する

int result = pool.invoke(new FibonacciTask(30));

サンプル2

public class SortTask extends RecursiveAction {

private int[] array;

private int fromIndex;

private int toIndex;

private final int chunkSize = 1024;

public SortTask(int[] array, int fromIndex, int toIndex) {

this.array = array;

this.fromIndex = fromIndex;

this.toIndex = toIndex;

}

@Override

protected void compute() {

int size = toIndex - fromIndex + 1;

if (size < chunkSize) {

Arrays.sort(array, fromIndex, toIndex);

} else {

int leftSize = size / 2;

SortTask leftTask =

new SortTask(array, fromIndex, fromIndex + leftSize);

SortTask rightTask =

new SortTask(array, fromIndex + leftSize + 1, toIndex);

ForkJoinTask.invokeAll(leftTask, rightTask);

}

}

}

final ForkJoinPool pool = new ForkJoinPool();

int len = 1000 * 10;

int[] array = new int[len];

...

pool.invoke(new SortTask(array, 0, len - 1));

Java SE9

★不変List/Set/Map用のファクトリメソッド

List immutableList = List.of("one","two","three");

Set<String> immutableSet = Set.of("key1", "key2", "key3");

Map immutableMap = Map.of(1, "one", 2, "two", 3, "three");

★Interface内のprivateメソッド

interface InterfaceWithPrivateMethods {

private static String staticPrivate() {...}

private String instancePrivate() {...}

default void check() {

String result = staticPrivate();

InterfaceWithPrivateMethods pvt

= new InterfaceWithPrivateMethods() {...};

result = pvt.instancePrivate();

}

}

★Modular System(Jigsaw)

公開・非公開するAPIをmodule-info.javaに定義

★Process APIの改善

ProcessHandle self = ProcessHandle.current();

long PID = self.getPid();

ProcessHandle.Info procInfo = self.info();

Optional<String[]> args = procInfo.arguments();

Optional<String> cmd = procInfo.commandLine();

Optional<Instant> startTime = procInfo.startInstant();

Optional<Duration> cpuUsage = procInfo.totalCpuDuration();

childProc = ProcessHandle.current().children();

childProc.forEach(procHandle -> {

procHandle.destroy();

});

★try-with-resourceの改善

BufferedReader reader1 = new BufferedReader(new FileReader("journaldev.txt"));

//try (BufferedReader reader2 = reader1) {...}

try (reader1) {...}

★CompletableFuture APIの改善

Executor exe = CompletableFuture.delayedExecutor(50L, TimeUnit.SECONDS);

★Reactive Streams

java.util.concurrent.Flow

java.util.concurrent.Flow.Publisher

java.util.concurrent.Flow.Subscriber

java.util.concurrent.Flow.Processor

★Optionalクラスの改善

public void ifPresentOrElse(Consumerl<? super Tl> action, Runnable emptyAction)

public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)

Optional::stream

Stream<Optional> emp = getEmployee(id);

Stream empStream = emp.flatMap(Optional::stream);

List<String> filteredList = listOfOptionals.stream()

.flatMap(Optional::stream)

.collect(Collectors.toList());

★Stream APIの改善

Stream.of(1,2,3,4,5)

.takeWhile(i -> i < 3 )

.forEach(System.out::println);

★HTTP2クライアント

import java.net.http.*;

import static java.net.http.HttpRequest.*;

import static java.net.http.HttpResponse.*;

URI uri = new URI("http://localhost:8080");

// HttpRequest.create(uri).body(noBody()).GET();

HttpRequest request = HttpRequest.create(uri).GET();

HttpResponse response = request.response();

String responseBody = response.body(asString());

Java SE8

DEMO

★Time/Date (java.time)

※java.text.NumberFormatと違い、DateTimeFormatterはスレッドセーフ

★Repeatable Annotation

★Stream & Parallel Stream

上記のDEMOリンクを参照

★Lambda expression

syntax

(parameters) -> expression / statement / { statements }

(int x, int y) -> { return x + y; }

(int x, int y) -> x + y

(x, y) -> x + y

x -> x * x

() -> x

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

x -> { System.out.println(x); }

(String s) -> { int n = s.length(); return n; }

// 従来

Runnable r = new Runnable() {

@Override

public void run() {

System.out.println("xxx");

}

};

final String s = "xxx";

Runnable r = () -> System.out.println(s);

r.run();

List<Person> persons = ...;

// 従来

Collections.sort(persons, new Comparator<Person<() {

public int compare(Person p1, Person p2){

return p1.name.compareTo(p2.name);

}

});

Collections.sort(persons, (p1, p2) -> p1.name.compareTo(p2.name));

★Exceptions in Lambdas

private static void writeToFile(File file, String value,

Function<OutputStream, OutputStream> writing) throws IOException {

try (PrintWriter pw = new PrintWriter(new BufferedOutputStream(

writing.apply(new FileOutputStream(file))))) {

pw.write(value);

}

}

private static void writeToFile(File file, String value,

ThrowingFunction<OutputStream, OutputStream, IOException> writing) throws IOException {

...

}

@FunctionalInterface

public interface ThrowingFunction<I, O, T extends Throwable> {

O apply(I i) throws T;

}

try {

writeToFile(new File("test.csv"), "Hello", GZIPOutputStream::new);

writeToFile(new File("test.csv"), "Hello", i -> i);

} catch (IOException e) {

...

}

★Method reference

syntax

Class::staticMethod / instanceMethod

String::valueOf x -> String.valueOf(x)

Instant.now()::isAfter Instant then = Instant.now(); t -> then.isAfter(t)

Object::toString x -> x.toString()

String::toLowerCase str -> str.toLowerCase()

x::toString () -> x.toString()

ArrayList::new () -> new ArrayList<>()

int[]::new len -> new int[len]

Arrays.sort(items, Util::compareItems);

Arrays.sort(items, (a, b) -> Util.compareItems(a, b));

items.forEach(Item::publish);

items.forEach((x) -> { x.publish(); });

ConstructorReference cref = Item::new;

Item item = cref.constructor();

execFunction("a"::concat);

execFunction(String::toUpperCase);

execFunction(p -> p.toUpperCase());

execFunction(String::new);

★Default method and Static method

interface Clickable{

default void click(){ ... }

default void print(){ ... }

}

interface Accessible{

default void access(){ ... }

default void print(){ ... }

}

class Button implements Clickable, Accessible {

public void print(){

Clickable.super.print();

Accessible.super.print();

}

public void action() {

this.click();

this.access();

this.print();

}

}

interface Defaulable {

default String method() {...}

}

class DefaultableImpl implements Defaulable {

}

class OverridableImpl implements Defaulable {

@Override

public String method() {...}

}

interface DefaulableFactory {

static Defaulable create(Supplier<Defaulable> supplier) {

return supplier.get();

}

}

Defaulable defaulable = DefaulableFactory.create(DefaultableImpl::new);

out.println(defaulable.method());

Defaulable defaulable = DefaulableFactory.create(OverridableImpl::new);

out.println(defaulable.method());

★Annotation定義

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})

public @interface NonEmpty {

}

public static class Holder<@NonEmpty T> extends @NonEmpty Object{

public void method() throws @NonEmpty Exception {...}

}

final Holder<String> holder = new @NonEmpty Holder<>();

@NonEmpty Collection<@NonEmpty String> strings = new ArrayList<>();

★Streamに関する注意点

IntStream stream = IntStream.of(1, 2);

stream.forEach(out::println);

// IllegalStateException: stream has already been operated upon or closed

stream.forEach(out::println);

IntStream.iterate(0, i -> i + 1)

.limit(10)

.skip(5)

.forEach(out::println); // 5 6 7 8 9

IntStream.iterate(0, i -> i + 1)

.skip(5)

.limit(10)

.forEach(out::println); // 5 6 7 8 9 10 11 12 13 14

stream.count() > 0

stream.findAny().isPresent() // 効率が良い

無限ループに陥る例

// limitがないと

IntStream.iterate(0, i -> i + 1)

.limit(10)

.forEach(out::println);

// distinctとlimitの順番が逆になると

IntStream.iterate(0, i -> ( i + 1 ) % 2)

.distinct()

.limit(10)

.forEach(out::println);

// sortedとlimitの順序が逆になると

Stream.iterate(100, n -> n - 1)

.sorted()

.limit(100)

.collect(Collectors.toList());

Stream.iterate(1, n -> (n + 1) % 10).anyMatch(n -> n >= 10);

// 並列処理でunorderedなしでskipを実行すると

Stream.iterate(0, n -> n + 1) // NG

//list.stream() // OK

.parallel()

.map(x -> x + 1)

.skip(10)

.limit(30)

.collect(Collectors.toList());

★対策1

Stream.iterate(0, n -> n + 1)

.sequential() // 省略可

.map(x -> x + 1)

...;

★対策2

Stream.iterate(0, n -> n + 1)

.parallel()

.unordered()

.map(x -> x + 1)

...;

並列処理について

private static Stream<String> fullNames(List<String> first, List<String> last) {

Iterator<String> firstItr = first.iterator();

return last.stream().map(l -> firstItr.next() + " " + l);

}

List<String> firstNames = Arrays.asList("A", "B", "C");

List<String> lastNames = Arrays.asList("A", "B", "C");

fullNames(firstNames, lastNames)

// .parallel() // 並列処理で姓と名が対応しない

.forEach(out::println);

List<Integer> result = list.stream()

// .parallel() // skip,limit,distinctは、なるべく逐次実行とする

.filter(x -> x % 2 == 0)

.peek(s -> out.println(s + ":" + Thread.currentThread())) // スレッドを確認

.skip(20)

.limit(20)

.collect(Collectors.toList());

List<String> result = new ArrayList<>();

Stream.of(1,2,3,4,5)

.parallel() // 並列処理でresultへの格納順が不定となる

.map(n -> "" + n)

.forEach(n -> result.add(n) );

List<String> result = Stream.of(1,2,3,4,5)

.parallel()

.map(n -> "" + n)

.collect(Collectors.toList());

★Collectorsについて

double averageSalary = employees.stream()

.collect(averagingDouble(Employee::getSalary));

double totalSalary = employees.stream()

.collect(summingDouble(Employee::getSalary));

double maxSalary = employees.stream()

.collect(collectingAndThen(

maxBy(comparingDouble(Employee::getSalary)),

emp -> emp.get().getSalary()));

String averageSalary = employees.stream()

.collect(collectingAndThen(

averagingDouble(Employee::getSalary),

new DecimalFormat("'0.000")::format));

DoubleSummaryStatistics statistics = employees.stream()

.collect(summarizingDouble(Employee::getSalary));

statistics.getAverage()

statistics.getSum()

statistics.getMax()

statistics.getMin()

List<String> employeeNames = employees.stream()

.collect(mapping(Employee::getName, toList()));

String employeeNames = employees.stream()

.map(Employee::getName)

.collect(joining(","));

// prefix, suffix: "Employees = {...}"

String employeeNames = employees.stream()

.map(Employee::getName)

.collect(joining(", ", "Employees = {", "}"));

Map<String, List<Employee>> deptEmps = employees.stream()

.collect(groupingBy(Employee::getDepartment));

// {Sales=2, DevOps=3}

Map<String, Long> deptEmpsCount = employees.stream()

.collect(groupingBy(Employee::getDepartment, counting()));

Map<String, Double> averageSalaryDeptSorted = employees.stream()

.collect(groupingBy(Employee::getDepartment, TreeMap::new, averagingDouble(Employee::getSalary)));

Map<String, Long> deptEmpCount = employees.stream()

.collect(groupingByConcurrent(Employee::getDepartment, counting()));

Map<Boolean, List<Employee>> portionedEmployees = employees.stream()

.collect(partitioningBy(e -> e.getSalary() > averageSalary));

★Null対策

Outer outer = new Outer();

if (outer != null

&& outer.getNested() != null

&& outer.getNested().getInner() != null) {

System.out.println(outer.getNested().getInner().getFoo());

}

改善方法1

Optional.of(new Outer())

.map(Outer::getNested)

.map(Nested::getInner)

.map(Inner::getFoo)

.ifPresent(System.out::println);

改善方法2

Outer obj = new Outer();

resolve(() -> obj.getNested().getInner().getFoo());

.ifPresent(System.out::println);

public static <T> Optional<T> resolve(Supplier<T> resolver) {

try {

T result = resolver.get();

return Optional.ofNullable(result);

} catch (NullPointerException e) {

return Optional.empty();

}

}

★IntSummaryStatisticsについて

IntSummaryStatistics statistics = list.stream()

.mapToInt(Person::getAge)

.summaryStatistics();

int min = statistics.getMin();

int max = statistics.getMax();

★標準的な関数型インターフェース

Function(apply)系 引数があり、戻り値がある

Function R apply(T t)

IntFunction R apply(int value)

LongFunction R apply(long value)

DoubleFunction R apply(double value)

BiFunction R apply(T t, U u)

ToIntFunction(apply)系 引数があり、戻り値がint型

ToIntFunction int applyAsInt(T value)

LongToIntFunction int applyAsInt(long value)

DoubleToIntFunction int applyAsInt(double value)

ToIntBiFunction int applyAsInt(T t, U u)

ToLongFunction(apply)系 引数があり、戻り値がlong型

ToLongFunction long applyAsLong(T value)

IntToLongFunction long applyAsLong(int value)

DoubleToLongFunction long applyAsLong(double value)

ToLongBiFunction long applyAsLong(T t, U u)

ToDoubleFunction(apply)系 引数があり、戻り値がdouble型

ToDoubleFunction double applyAsDouble(T value)

IntToDoubleFunction double applyAsDouble(int value)

LongToDoubleFunction double applyAsDouble(long value)

ToDoubleBiFunction double applyAsDouble(T t, U u)

Consumer(accept)系 引数があり、戻り値がない

Consumer void accept(T t)

IntConsumer void accept(int value)

LongConsumer void accept(long value)

DoubleConsumer void accept(double value)

BiConsumer void accept(T t, U u)

ObjIntConsumer void accept(T t, int value)

ObjLongConsumer void accept(T t, long value)

ObjDoubleConsumer void accept(T t, double value)

Supplier(get)系 引数がなし、戻り値がある(遅延評価用)

Supplier T get()

BooleanSupplier boolean getAsBoolean()

IntSupplier int getAsInt()

LongSupplier long getAsLong()

DoubleSupplier double getAsDouble()

Predicate(test)系 引数があり、戻り値がboolean型(条件判定用)

Predicate boolean test(T t)

IntPredicate boolean test(int value)

LongPredicate boolean test(long value)

DoublePredicate boolean test(double value)

BiPredicate boolean test(T t, U u)

UnaryOperator(apply)系 引数(1つ)と戻り値の型が同じ

UnaryOperator T apply(T t)

IntUnaryOperator int applyAsInt(int operand)

LongUnaryOperator long applyAsLong(long operand)

DoubleUnaryOperator double applyAsDouble(double operand)

BinaryOperator(apply)系 引数(2つ)と戻り値の型が同じ

BinaryOperator T apply(T t, T u)

IntBinaryOperator int applyAsInt(int left, int right)

LongBinaryOperator long applyAsLong(long left, long right)

DoubleBinaryOperator double applyAsDouble(double left, double right)

★SQLとStreamの類比