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
★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の類比