CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第8章 その他の Java 8 機能を理解する : 問題 14 : requireNonNull(T, Supplier<String>) メソッド

問題

java.util.ObjectsrequireNonNull(T, Supplier<String>)メソッドは

  • 第1引数がnullかどうかをチェックし
  • nullのときは第2引数のラムダ式を評価して
  • それをエラーメッセージとするNullPointerExceptionをスローする

このメソッドによりもっと役立つエラーメッセージとなる方法を示せ。

疑問点

よりもっと役立つエラーメッセージとなる” の意味が分からない。

本文には、次のサンプルコードがあった。
■ 本文のサンプルコード

this.directions = Objects.requireNonNull(
    directions,
    () -> "directions for " + this.goal + " must not be null"
);

下のコードと比べれば、第2引数の文字列連結処理がnullのときしか実行されないというメリットはあるんだが…

this.directions = Objects.requireNonNull(
    directions,
    "directions for " + this.goal + " must not be null"
);

よりもっと役立つエラーメッセージ” って何だろう?

解答

本文に載っているコードは、あるクラスのコンストラクタの一部だろうと思う。
goal とか directions というメンバー変数から推測するに、このクラスは「迷路を歩き回る経路」を表わしているのだろう。

話を簡単にするために、経路を進む方向は東西南北の4つしかないとする。

■ 経路を進む方向

public enum Direction {
    North, East, South, West
}

requireNonNullを使わない経路クラス

public class Path {
    private Point2D start;           // 出発点
    private Direction[] directions;  // 経路を進む方向

    public Path(Point2D start, Direction[] directions) {
        this.start = start;
        this.directions = directions;
    }

    // ゴールを求める
    public Point2D getGoal() {
        if (directions == null) {
            return start;
        }
        Point2D goal = new Point2D(start.getX(), start.getY());
        for (Direction direction : directions) {
            switch (direction) {
            case North: goal = goal.add( 0.0, -1.0); break;
            case East:  goal = goal.add( 1.0,  0.0); break;
            case South: goal = goal.add( 0.0,  1.0); break;
            case West:  goal = goal.add(-1.0,  0.0); break;
            }
        }
        return goal;
    }
}

このコンストラクタにrequireNonNullメソッドを使ってnullチェックを行うと

requireNonNullを使ってnullチェック

public Path(Point2D start, Direction[] directions) {
    this.start = Objects.requireNonNull(start, "~");
    this.directions = Objects.requireNonNull(
        directions,
        () -> "directions for " + getGoal() + " must not be null"
    );
}

getGoal()メソッドは、directionsnullでないときはコストが掛かる。
NullPointerExceptionがスローされないときも律儀にゴールを計算するのは無駄である。

第8章 その他の Java 8 機能を理解する : 問題 13 : ソースレベルのアノテーション処理

問題

問題 12 で定義したTestCaseアノテーションを処理するソースレベルのアノテーションプロセッサを構築せよ。

このプロセッサーは実行されると、テストを実行するmainメソッドを持つソースを出力する。

解答

問題 12 で定義したTestCaseアノテーションを、もう一度見てみよう。
今回はパッケージ名が関係してくるので、パッケージ名を省略しないでコードを記述する。

TestCase

package cub;

// 本アノテーションは繰り返し宣言できる
@Repeatable(TestCases.class)
public @interface TestCase {
    /** 引数 */
    int param();
    /** 想定する戻り値 */
    int expected();
}

TestCaseアノテーションの繰り返し

package cub;

// 実行時にアノテーションを取得できなくてもよい
@Target(ElementType.METHOD)
public @interface TestCases {
    TestCase[] value();
}

このTestCaseは、テスト対象のオブジェクトの生成方法が指定されていない。
そこで、テストするメソッドは static に限定する。

TestCaseアノテーションでテストする対象

package cub;

public class TestTarget {
    @TestCase(param=4, expected=24)
    @TestCase(param=1, expected= 1)
    public static int factorial(int n) {
        return n <= 1 ? 1 : n * factorial(n - 1);
    }
}

TestTargetクラスをコンパイルしたときに、以下のようなテストコードを出力する。

TestTargetクラスのテストコード

package cub;

public class Test {
    public static void main(String[] args) {
        System.out.print("テストケース : 引数 = 4, 戻り値 = 24 : ");
        try {
            int ret = cub.TestTarget.factorial(4);
            if (ret == 24)
                System.out.println("OK");
            else
                System.out.println("NG, 戻り値 = " + ret);
        } catch (Exception ex) {
            System.out.println("NG, 例外 : " + ex);
        }
        // "param=1, expected= 1" も同様
    }
}

では、上のテストコードを出力するプロセッサーを書いてみよう。

  • ソースレベルのアノテーション処理はjavax.annotation.processing.Processorインターフェースを実装しなければならない
    • そこでjavax.annotation.processing.AbstractProcessorの派生クラスを定義する
    • Override するメソッドはprocessだけで十分
  • ソースファイルの出力は自前でやるのではなくjavax.annotation.processing.Filerを使う
    • Filerオブジェクトはメンバーjavax.annotation.processing.ProcessingEnvironmentから取得
    • ソースファイルの出力はcreateSourceFile(CharSequence name, Element...)メソッドで
    • createSourceFileメソッドは、クラス名から所定のフォルダにファイルを作成するだけなので、パッケージ宣言やクラス宣言などは自前で出力する

■ テストコードを出力するプロセッサー

package cub;

@SupportedAnnotationTypes({"cub.TestCase","cub.TestCases"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class TestCaseProcessor extends AbstractProcessor {
    public boolean process(
        Set<? extends TypeElement> annotations,
        RoundEnvironment roundEnv
    ) {
        for (TypeElement type : annotations) {
            //
            // type は実質 TestCases アノテーションだが TestCases にキャストできないので
            // アノテーションを付けたメソッドから TestCases アノテーションを取得する
            //
            Filer filer = processingEnv.getFiler();
            try (Writer writer = filer.createSourceFile("cub.Test").openWriter()) {
                writer.write("package cub;\n\n");       // パッケージ宣言
                writer.write("public class Test {\n");  // クラス宣言
                                                        // main メソッド宣言
                writer.write("\tpublic static void main(String[] args) {\n");
                for (Element element : roundEnv.getElementsAnnotatedWith(type)) {
                    //
                    // element.toString() = "factorial(int)"
                    // element.getSimpleName() = "factorial"
                    // element.getKind() = MEHOD
                    // element.getEnclosingElement() = "cub.TestTarget"
                    // element.getEnclosedElements() はなし
                    //
                    String method = element.getEnclosingElement() + "."
                                  + element.getSimpleName();
                    TestCases testCases = element.getAnnotation(TestCases.class);
                    for (TestCase testCase : testCases.value()) {
                        String text = "テストケース : 引数 = " + testCase.param()
                                    + ", 戻り値 = " + testCase.expected() + " : ";
                        writer.write("\t\tSystem.out.print(\"" + text + "\");\n");
                        writer.write("\t\ttry {\n");
                        writer.write("\t\t\tint ret = " + method + "(" + testCase.param() + ");\n");
                        writer.write("\t\t\tif (ret == " + testCase.expected() + ")\n");
                        writer.write("\t\t\t\tSystem.out.println(\"OK\");\n");
                        writer.write("\t\t\telse\n");
                        writer.write("\t\t\t\tSystem.out.println(\"NG, 戻り値 = \" + ret);\n");
                        writer.write("\t\t} catch (Exception ex) {\n");
                        writer.write("\t\t\tSystem.out.println(\"NG, 例外 : \" + ex);\n");
                        writer.write("\t\t}\n");
                        writer.write("\n");
                    }
                }
                writer.write("\t}\n");                  // main メソッドを閉じる
                writer.write("}\n");                    // クラスを閉じる
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
}

このTestCaseProcessorコンパイルするのは普通に

javac cub/TestCaseProcessor.java cub/TestCases.java cub/TestCase.java

でよい。 TestCaseProcessorでソースを出力するには、javacコマンドで以下のオプションを指定する。

TestCaseProcessorによるアノテーション処理(実際には1行で)

javac -processorpath . -processor cub.TestCaseProcessor cub/TestTarget.java
       cub/TestCases.java cub/TestCase.java

第8章 その他の Java 8 機能を理解する : 問題 12 : 繰り返し指定できるアノテーション

問題

以下のようなプログラムを実装せよ。

  1. TestCaseアノテーションを定義し
  2. そのアノテーションを持つクラスをロードして
  3. アノテーションが付いたメソッドを呼び出し
  4. メソッドが期待した値を返すかを検査する

引数と戻り値の型はintと想定する。

解答

JUnit の簡易版を実装せよ、ってことですな。

引数と戻り値の型がStringTestCaseアノテーションは、本文で定義してあるので、それを流用する。

■ 単純な Test Case

// 本アノテーションは繰り返し宣言できる
@Repeatable(TestCases.class)
public @interface TestCase {
    /** 引数 */
    int param();
    /** 想定する戻り値 */
    int expected();
}

TestCaseアノテーションの繰り返し

@Retention(RetentionPolicy.RUNTIME)  // 実行時にアノテーションを取得できるように
@Target(ElementType.METHOD)
public @interface TestCases {
    TestCase[] value();
}

このTestCaseは、テスト対象のオブジェクトの生成方法が指定されていない。
そこで、テストするメソッドは static に限定する。

TestCaseアノテーションでテストする対象

public class TestTarget {
    @TestCase(param=4, expected=24)
    @TestCase(param=1, expected= 1)
    public static int factorial(int n) {
        return n <= 1 ? 1 : n * factorial(n - 1);
    }
}

では、TestCaseアノテーションを実行して検査するコードを書いてみよう。 仕様は、以下のようにする。

  • 入力は、検査対象のクラス名
  • 戻り値が想定する戻り値と一致するときは、"OK" と表示
  • 戻り値が想定する戻り値と一致しないときは、"NG" と表示
  • 例外が発生したときは、"NG" と表示

TestCaseアノテーションを実行して検査

public static void test(String className) throws Exception {
    Class<?> clazz = Class.forName(className);
    for (Method method : clazz.getMethods()) {
        TestCases testCases = method.getAnnotation(TestCases.class);
        if (testCases == null)
            continue;
        for (TestCase testCase : testCases.value()) {
            System.out.print(
                "テストケース : 引数 = " + testCase.param() +
                ", 戻り値 = " + testCase.expected() + " : "
            );
            try {
                int ret = (Integer)method.invoke(null, testCase.param());
                if (ret == testCase.expected()) {
                    System.out.println("OK");
                } else {
                    System.out.println("NG, 戻り値 = " + ret);
                }
            } catch (Exception ex) {
                System.out.println("NG, 例外 : " + ex);
            }
        }
    }
}

TestTargetを検査したときは、以下のように出力される。

テストケース : 引数 = 4, 戻り値 = 24 : OK
テストケース : 引数 = 1, 戻り値 = 1 : OK

第8章 その他の Java 8 機能を理解する : 問題 11 : Basic 認証

問題

パスワード保護(Basic 認証)された Web ページの内容を取得するプログラムを書け。

解答

ん~、一応コードは書くけど、Basic 認証しているサイトを知らないので、動作確認はなしね。

■ Basic 認証

private InputStream basicAuthentication(URL url, String user, String password)
    throws IOException {
    URLConnection connection = url.openConnection();
    // ユーザーコードとパスワードを Base64 でエンコード
    Base64.Encoder encoder = Base64.getEncoder();
    String auth = user + ":" + password;
    auth = encoder.encodeToString(auth.getBytes(StandardCharsets.UTF_8));

    connection.setRequestProperty("Authorization", "Basic " + auth);
    connection.connect();
    return connection.getInputStream();
}

第8章 その他の Java 8 機能を理解する : 問題 10 : Files.walk メソッド

問題

まず JDK の src.zip ファイルを解凍せよ。
Files.walkメソッドを使用して、予約語

  • transient
  • volatile

を含む Java のソースファイルを全て見つけよ。

解答

まず、ソースファイルにキーワードtransientまたはvolatileが含まれるかどうかをチェックするメソッドを用意します。

■ キーワードを含むかどうか?

private boolean hasKeywords(Path path) {
    try (Scanner scanner = new Scanner(path, "utf-8")) {
        while (scanner.hasNext()) {
            String word = scanner.next();
            if (word.equals("transient") || word.equals("volatile"))
                return true;
        }
        return false;
    } catch (IOException ex) {
        ex.printStackTrace();
        throw new RuntimeException(ex);  // 後で Stream にかけるのでチェック例外は不可
    }
}

ワードの抽出は、Scannerのデフォルトに任せます。
Java の言語解析をしてる訳ではないので、コメントに書かれた予約語も拾ってしまいますが、そこはご勘弁を…

では、予約語を含む Java のソースファイルをリストアップしましょう。

Path root = Paths.get("~");
try (Stream<Path> stream = Files.walk(root)) {
    stream
        .filter(p -> p.toFile().isFile())
        .filter(p -> p.toFile().getName().endsWith(".java"))
        .filter(p -> hasKeywords(p))
        .forEach(System.out::println);
} catch (IOException ex) {
    ex.printStackTrace();
}

■ ファイル一覧(492個)

com/sun/corba/se/impl/activation/RepositoryImpl.java
com/sun/corba/se/impl/activation/ServerMain.java
com/sun/corba/se/impl/encoding/CachedCodeBase.java
com/sun/corba/se/impl/io/FVDCodeBaseImpl.java
com/sun/corba/se/impl/io/ObjectStreamClass.java
com/sun/corba/se/impl/ior/ObjectReferenceFactoryImpl.java
com/sun/corba/se/impl/ior/ObjectReferenceProducerBase.java
com/sun/corba/se/impl/ior/ObjectReferenceTemplateImpl.java
com/sun/corba/se/impl/naming/cosnaming/NamingContextImpl.java
com/sun/corba/se/impl/naming/cosnaming/TransientNameServer.java
com/sun/corba/se/impl/naming/cosnaming/TransientNameService.java
com/sun/corba/se/impl/naming/pcosnaming/InternalBindingValue.java
com/sun/corba/se/impl/naming/pcosnaming/NameServer.java
com/sun/corba/se/impl/naming/pcosnaming/NamingContextImpl.java
com/sun/corba/se/impl/naming/pcosnaming/ServantManagerImpl.java
com/sun/corba/se/impl/oa/toa/TOA.java
com/sun/corba/se/impl/oa/toa/TOAImpl.java
com/sun/corba/se/impl/orb/ORBDataParserImpl.java
com/sun/corba/se/impl/orb/ORBSingleton.java
com/sun/corba/se/impl/orbutil/ObjectStreamClassUtil_1_3.java
com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java
com/sun/corba/se/impl/orbutil/threadpool/ThreadPoolImpl.java
com/sun/corba/se/impl/presentation/rmi/InvocationHandlerFactoryImpl.java
com/sun/corba/se/impl/presentation/rmi/StubInvocationHandlerImpl.java
com/sun/corba/se/impl/transport/SelectorImpl.java
com/sun/corba/se/impl/util/IdentityHashtable.java
com/sun/corba/se/spi/legacy/connection/ORBSocketFactory.java
com/sun/corba/se/spi/orb/ORB.java
com/sun/corba/se/spi/orb/ORBData.java
com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java
com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java
com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java
com/sun/javadoc/FieldDoc.java
com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
com/sun/jmx/mbeanserver/JmxMBeanServer.java
com/sun/jmx/mbeanserver/Repository.java
com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java
com/sun/jmx/remote/internal/ClientNotifForwarder.java
com/sun/jmx/snmp/agent/SnmpMib.java
com/sun/jmx/snmp/agent/SnmpMibAgent.java
com/sun/jmx/snmp/agent/SnmpMibTable.java
com/sun/jmx/snmp/daemon/CommunicatorServer.java
com/sun/jmx/snmp/daemon/SnmpAdaptorServer.java
com/sun/jmx/snmp/daemon/SnmpInformRequest.java
com/sun/jmx/snmp/daemon/SnmpRequestHandler.java
com/sun/jmx/snmp/daemon/SnmpSession.java
com/sun/jmx/snmp/daemon/SnmpSocket.java
com/sun/jmx/snmp/internal/SnmpEngineImpl.java
com/sun/jmx/snmp/SnmpEngine.java
com/sun/org/apache/bcel/internal/classfile/JavaClass.java
com/sun/org/apache/regexp/internal/RE.java
com/sun/org/apache/xalan/internal/utils/SecuritySupport.java
com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
com/sun/org/apache/xerces/internal/dom/AttrImpl.java
com/sun/org/apache/xerces/internal/dom/CharacterDataImpl.java
com/sun/org/apache/xerces/internal/dom/ChildNode.java
com/sun/org/apache/xerces/internal/dom/CoreDocumentImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredAttrImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredAttrNSImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredCDATASectionImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredCommentImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredDocumentImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredDocumentTypeImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredElementDefinitionImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredElementImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredElementNSImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredEntityImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredEntityReferenceImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredNotationImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredProcessingInstructionImpl.java
com/sun/org/apache/xerces/internal/dom/DeferredTextImpl.java
com/sun/org/apache/xerces/internal/dom/ElementNSImpl.java
com/sun/org/apache/xerces/internal/dom/ParentNode.java
com/sun/org/apache/xerces/internal/impl/dtd/models/DFAContentModel.java
com/sun/org/apache/xerces/internal/impl/dv/xs/AbstractDateTimeDV.java
com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java
com/sun/org/apache/xerces/internal/impl/xpath/regex/RegularExpression.java
com/sun/org/apache/xerces/internal/impl/xs/models/XSDFACM.java
com/sun/org/apache/xerces/internal/impl/xs/XSComplexTypeDecl.java
com/sun/org/apache/xerces/internal/util/SymbolTable.java
com/sun/org/apache/xerces/internal/utils/SecuritySupport.java
com/sun/org/apache/xerces/internal/xni/XMLString.java
com/sun/org/apache/xml/internal/dtm/ref/dom2dtm/DOM2DTM.java
com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM.java
com/sun/org/apache/xml/internal/security/utils/XMLUtils.java
com/sun/org/apache/xml/internal/utils/ThreadControllerWrapper.java
com/sun/org/apache/xpath/internal/axes/AxesWalker.java
com/sun/org/apache/xpath/internal/axes/ChildTestIterator.java
com/sun/org/apache/xpath/internal/axes/DescendantIterator.java
com/sun/org/apache/xpath/internal/axes/FilterExprIterator.java
com/sun/org/apache/xpath/internal/axes/FilterExprIteratorSimple.java
com/sun/org/apache/xpath/internal/axes/FilterExprWalker.java
com/sun/org/apache/xpath/internal/axes/LocPathIterator.java
com/sun/org/apache/xpath/internal/axes/PredicatedNodeTest.java
com/sun/org/apache/xpath/internal/compiler/XPathParser.java
com/sun/org/apache/xpath/internal/functions/FuncExtFunctionAvailable.java
com/sun/org/apache/xpath/internal/NodeSet.java
com/sun/org/apache/xpath/internal/NodeSetDTM.java
com/sun/org/apache/xpath/internal/XPath.java
com/sun/security/auth/X500Principal.java
java/applet/Applet.java
java/awt/AWTEvent.java
java/awt/Button.java
java/awt/Checkbox.java
java/awt/CheckboxMenuItem.java
java/awt/Choice.java
java/awt/color/ColorSpace.java
java/awt/color/ICC_ColorSpace.java
java/awt/color/ICC_Profile.java
java/awt/Component.java
java/awt/Container.java
java/awt/ContainerOrderFocusTraversalPolicy.java
java/awt/Cursor.java
java/awt/datatransfer/DataFlavor.java
java/awt/Dialog.java
java/awt/dnd/DragGestureEvent.java
java/awt/dnd/DragGestureRecognizer.java
java/awt/dnd/DragSource.java
java/awt/dnd/DragSourceContext.java
java/awt/dnd/DropTarget.java
java/awt/dnd/DropTargetContext.java
java/awt/event/FocusEvent.java
java/awt/event/InputEvent.java
java/awt/event/InputMethodEvent.java
java/awt/event/InvocationEvent.java
java/awt/event/KeyEvent.java
java/awt/event/MouseEvent.java
java/awt/event/WindowEvent.java
java/awt/Event.java
java/awt/EventDispatchThread.java
java/awt/EventQueue.java
java/awt/font/FontRenderContext.java
java/awt/font/NumericShaper.java
java/awt/Font.java
java/awt/geom/AffineTransform.java
java/awt/geom/Path2D.java
java/awt/GridBagConstraints.java
java/awt/GridBagLayout.java
java/awt/ImageCapabilities.java
java/awt/KeyboardFocusManager.java
java/awt/List.java
java/awt/MenuComponent.java
java/awt/MenuItem.java
java/awt/peer/ComponentPeer.java
java/awt/PopupMenu.java
java/awt/Robot.java
java/awt/Scrollbar.java
java/awt/ScrollPaneAdjustable.java
java/awt/SystemColor.java
java/awt/SystemTray.java
java/awt/TextComponent.java
java/awt/TextField.java
java/awt/Toolkit.java
java/awt/TrayIcon.java
java/awt/WaitDispatchSupport.java
java/awt/Window.java
java/beans/beancontext/BeanContextChildSupport.java
java/beans/beancontext/BeanContextServicesSupport.java
java/beans/beancontext/BeanContextSupport.java
java/beans/Beans.java
java/beans/ThreadGroupContext.java
java/beans/Transient.java
java/beans/WeakIdentityMap.java
java/io/BufferedInputStream.java
java/io/File.java
java/io/FileInputStream.java
java/io/FileOutputStream.java
java/io/FilePermission.java
java/io/FilterInputStream.java
java/io/ObjectInputStream.java
java/io/ObjectOutputStream.java
java/io/ObjectStreamClass.java
java/io/PipedInputStream.java
java/io/RandomAccessFile.java
java/lang/Class.java
java/lang/ClassValue.java
java/lang/invoke/CallSite.java
java/lang/invoke/LambdaForm.java
java/lang/invoke/MethodHandleImpl.java
java/lang/invoke/MutableCallSite.java
java/lang/invoke/SwitchPoint.java
java/lang/invoke/VolatileCallSite.java
java/lang/Package.java
java/lang/ref/Finalizer.java
java/lang/ref/Reference.java
java/lang/ref/ReferenceQueue.java
java/lang/reflect/AccessibleObject.java
java/lang/reflect/Constructor.java
java/lang/reflect/Executable.java
java/lang/reflect/Field.java
java/lang/reflect/Method.java
java/lang/reflect/Modifier.java
java/lang/reflect/Parameter.java
java/lang/StringBuffer.java
java/lang/System.java
java/lang/Thread.java
java/lang/Throwable.java
java/math/BigDecimal.java
java/math/BigInteger.java
java/net/Inet6Address.java
java/net/InetAddress.java
java/net/InetSocketAddress.java
java/net/SocketPermission.java
java/net/URI.java
java/net/URL.java
java/net/URLPermission.java
java/nio/Bits.java
java/nio/channels/SelectionKey.java
java/nio/channels/spi/AbstractInterruptibleChannel.java
java/nio/channels/spi/AbstractSelectionKey.java
java/nio/charset/Charset.java
java/nio/file/attribute/AclEntry.java
java/nio/file/spi/FileSystemProvider.java
java/rmi/activation/ActivationID.java
java/rmi/server/RemoteObject.java
java/security/BasicPermission.java
java/security/cert/CertificateRevokedException.java
java/security/cert/X509Certificate.java
java/security/cert/X509CRL.java
java/security/CodeSigner.java
java/security/CodeSource.java
java/security/KeyFactory.java
java/security/KeyPairGenerator.java
java/security/KeyStore.java
java/security/PermissionCollection.java
java/security/Permissions.java
java/security/Provider.java
java/security/SecureRandom.java
java/security/Timestamp.java
java/security/UnresolvedPermission.java
java/security/UnresolvedPermissionCollection.java
java/sql/DriverManager.java
java/sql/SQLException.java
java/text/DateFormatSymbols.java
java/text/DecimalFormat.java
java/text/DecimalFormatSymbols.java
java/text/MergeCollation.java
java/text/RuleBasedCollator.java
java/text/SimpleDateFormat.java
java/time/chrono/ChronoLocalDateTimeImpl.java
java/time/chrono/ChronoZonedDateTimeImpl.java
java/time/chrono/HijrahChronology.java
java/time/chrono/HijrahDate.java
java/time/chrono/JapaneseDate.java
java/time/chrono/JapaneseEra.java
java/time/chrono/MinguoDate.java
java/time/chrono/ThaiBuddhistDate.java
java/time/format/DateTimeFormatterBuilder.java
java/time/temporal/JulianFields.java
java/time/temporal/WeekFields.java
java/time/zone/ZoneRules.java
java/time/ZoneOffset.java
java/time/ZoneRegion.java
java/util/AbstractList.java
java/util/AbstractMap.java
java/util/ArrayDeque.java
java/util/ArrayList.java
java/util/BitSet.java
java/util/Calendar.java
java/util/Collections.java
java/util/concurrent/ArrayBlockingQueue.java
java/util/concurrent/atomic/AtomicBoolean.java
java/util/concurrent/atomic/AtomicInteger.java
java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
java/util/concurrent/atomic/AtomicLong.java
java/util/concurrent/atomic/AtomicLongFieldUpdater.java
java/util/concurrent/atomic/AtomicMarkableReference.java
java/util/concurrent/atomic/AtomicReference.java
java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
java/util/concurrent/atomic/AtomicStampedReference.java
java/util/concurrent/atomic/Striped64.java
java/util/concurrent/CompletableFuture.java
java/util/concurrent/ConcurrentHashMap.java
java/util/concurrent/ConcurrentLinkedDeque.java
java/util/concurrent/ConcurrentLinkedQueue.java
java/util/concurrent/ConcurrentSkipListMap.java
java/util/concurrent/CopyOnWriteArrayList.java
java/util/concurrent/CountedCompleter.java
java/util/concurrent/DelayQueue.java
java/util/concurrent/Exchanger.java
java/util/concurrent/ExecutorCompletionService.java
java/util/concurrent/ForkJoinPool.java
java/util/concurrent/ForkJoinTask.java
java/util/concurrent/FutureTask.java
java/util/concurrent/LinkedBlockingDeque.java
java/util/concurrent/LinkedBlockingQueue.java
java/util/concurrent/LinkedTransferQueue.java
java/util/concurrent/locks/AbstractOwnableSynchronizer.java
java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
java/util/concurrent/locks/AbstractQueuedSynchronizer.java
java/util/concurrent/locks/ReentrantReadWriteLock.java
java/util/concurrent/locks/StampedLock.java
java/util/concurrent/Phaser.java
java/util/concurrent/PriorityBlockingQueue.java
java/util/concurrent/ScheduledThreadPoolExecutor.java
java/util/concurrent/SynchronousQueue.java
java/util/concurrent/ThreadLocalRandom.java
java/util/concurrent/ThreadPoolExecutor.java
java/util/Currency.java
java/util/Date.java
java/util/EnumMap.java
java/util/EventObject.java
java/util/GregorianCalendar.java
java/util/HashMap.java
java/util/HashSet.java
java/util/Hashtable.java
java/util/IdentityHashMap.java
java/util/JapaneseImperialCalendar.java
java/util/jar/JarFile.java
java/util/jar/JarVerifier.java
java/util/LinkedHashMap.java
java/util/LinkedList.java
java/util/Locale.java
java/util/logging/Handler.java
java/util/logging/Level.java
java/util/logging/Logger.java
java/util/logging/LogManager.java
java/util/logging/LogRecord.java
java/util/logging/MemoryHandler.java
java/util/logging/StreamHandler.java
java/util/PriorityQueue.java
java/util/PropertyPermission.java
java/util/regex/Pattern.java
java/util/ResourceBundle.java
java/util/Scanner.java
java/util/SimpleTimeZone.java
java/util/stream/AbstractShortCircuitTask.java
java/util/stream/SliceOps.java
java/util/TimeZone.java
java/util/TreeMap.java
java/util/TreeSet.java
java/util/WeakHashMap.java
java/util/zip/ZipFile.java
javax/accessibility/AccessibleContext.java
javax/accessibility/AccessibleState.java
javax/lang/model/element/UnknownAnnotationValueException.java
javax/lang/model/element/UnknownElementException.java
javax/lang/model/type/MirroredTypeException.java
javax/lang/model/type/MirroredTypesException.java
javax/lang/model/type/UnknownTypeException.java
javax/management/AttributeList.java
javax/management/ImmutableDescriptor.java
javax/management/loading/MLet.java
javax/management/MBeanConstructorInfo.java
javax/management/MBeanFeatureInfo.java
javax/management/MBeanInfo.java
javax/management/MBeanNotificationInfo.java
javax/management/MBeanOperationInfo.java
javax/management/MBeanPermission.java
javax/management/MBeanServerPermission.java
javax/management/modelmbean/DescriptorSupport.java
javax/management/modelmbean/RequiredModelMBean.java
javax/management/monitor/Monitor.java
javax/management/ObjectName.java
javax/management/openmbean/ArrayType.java
javax/management/openmbean/CompositeType.java
javax/management/openmbean/OpenMBeanAttributeInfoSupport.java
javax/management/openmbean/OpenMBeanConstructorInfoSupport.java
javax/management/openmbean/OpenMBeanInfoSupport.java
javax/management/openmbean/OpenMBeanOperationInfoSupport.java
javax/management/openmbean/OpenMBeanParameterInfoSupport.java
javax/management/openmbean/OpenType.java
javax/management/openmbean/SimpleType.java
javax/management/openmbean/TabularDataSupport.java
javax/management/openmbean/TabularType.java
javax/management/relation/RoleList.java
javax/management/relation/RoleUnresolvedList.java
javax/management/remote/JMXServiceURL.java
javax/management/remote/rmi/RMIConnector.java
javax/management/StandardMBean.java
javax/management/timer/Timer.java
javax/naming/CompositeName.java
javax/naming/CompoundName.java
javax/naming/directory/BasicAttribute.java
javax/naming/directory/BasicAttributes.java
javax/naming/ldap/LdapName.java
javax/naming/ldap/Rdn.java
javax/print/attribute/HashAttributeSet.java
javax/print/DocFlavor.java
javax/print/event/PrintJobEvent.java
javax/print/MimeType.java
javax/rmi/CORBA/Stub.java
javax/security/auth/kerberos/DelegationPermission.java
javax/security/auth/kerberos/KerberosKey.java
javax/security/auth/kerberos/KerberosPrincipal.java
javax/security/auth/kerberos/KerberosTicket.java
javax/security/auth/kerberos/KeyImpl.java
javax/security/auth/kerberos/ServicePermission.java
javax/security/auth/PrivateCredentialPermission.java
javax/security/auth/Subject.java
javax/security/auth/x500/X500Principal.java
javax/sql/rowset/BaseRowSet.java
javax/sql/rowset/serial/SerialJavaObject.java
javax/sql/rowset/spi/SyncFactory.java
javax/swing/AbstractAction.java
javax/swing/AbstractButton.java
javax/swing/AbstractCellEditor.java
javax/swing/AbstractSpinnerModel.java
javax/swing/ActionMap.java
javax/swing/ActionPropertyChangeListener.java
javax/swing/AncestorNotifier.java
javax/swing/BoxLayout.java
javax/swing/colorchooser/DefaultColorSelectionModel.java
javax/swing/DefaultBoundedRangeModel.java
javax/swing/DefaultButtonModel.java
javax/swing/DefaultDesktopManager.java
javax/swing/DefaultSingleSelectionModel.java
javax/swing/event/EventListenerList.java
javax/swing/ImageIcon.java
javax/swing/InputMap.java
javax/swing/JComponent.java
javax/swing/JDesktopPane.java
javax/swing/JFileChooser.java
javax/swing/JLayer.java
javax/swing/JList.java
javax/swing/JMenuBar.java
javax/swing/JOptionPane.java
javax/swing/JPopupMenu.java
javax/swing/JProgressBar.java
javax/swing/JSlider.java
javax/swing/JSpinner.java
javax/swing/JTabbedPane.java
javax/swing/JTable.java
javax/swing/JTree.java
javax/swing/JViewport.java
javax/swing/LegacyGlueFocusTraversalPolicy.java
javax/swing/MenuSelectionManager.java
javax/swing/plaf/basic/BasicLookAndFeel.java
javax/swing/plaf/basic/BasicPopupMenuUI.java
javax/swing/plaf/basic/BasicScrollBarUI.java
javax/swing/plaf/basic/BasicSliderUI.java
javax/swing/plaf/basic/BasicTabbedPaneUI.java
javax/swing/plaf/basic/BasicTextUI.java
javax/swing/plaf/basic/BasicTreeUI.java
javax/swing/plaf/basic/LazyActionMap.java
javax/swing/plaf/metal/MetalBumps.java
javax/swing/plaf/metal/MetalIconFactory.java
javax/swing/plaf/nimbus/AbstractRegionPainter.java
javax/swing/plaf/synth/SynthContext.java
javax/swing/plaf/synth/SynthSliderUI.java
javax/swing/Popup.java
javax/swing/PopupFactory.java
javax/swing/RepaintManager.java
javax/swing/SortingFocusTraversalPolicy.java
javax/swing/SwingWorker.java
javax/swing/table/DefaultTableColumnModel.java
javax/swing/table/JTableHeader.java
javax/swing/table/TableColumn.java
javax/swing/text/AbstractDocument.java
javax/swing/text/DefaultCaret.java
javax/swing/text/DefaultFormatter.java
javax/swing/text/DefaultStyledDocument.java
javax/swing/text/GapContent.java
javax/swing/text/html/CSS.java
javax/swing/text/html/HTMLEditorKit.java
javax/swing/text/InternationalFormatter.java
javax/swing/text/JTextComponent.java
javax/swing/text/MaskFormatter.java
javax/swing/text/PlainDocument.java
javax/swing/text/SimpleAttributeSet.java
javax/swing/text/StringContent.java
javax/swing/text/StyleContext.java
javax/swing/Timer.java
javax/swing/TimerQueue.java
javax/swing/ToolTipManager.java
javax/swing/tree/DefaultMutableTreeNode.java
javax/swing/tree/DefaultTreeCellEditor.java
javax/swing/tree/DefaultTreeCellRenderer.java
javax/swing/tree/DefaultTreeSelectionModel.java
javax/xml/bind/annotation/XmlAccessType.java
javax/xml/bind/annotation/XmlAnyAttribute.java
javax/xml/bind/annotation/XmlElement.java
javax/xml/bind/annotation/XmlElements.java
javax/xml/bind/annotation/XmlElementWrapper.java
javax/xml/bind/annotation/XmlID.java
javax/xml/bind/annotation/XmlIDREF.java
javax/xml/bind/annotation/XmlType.java
javax/xml/bind/annotation/XmlValue.java
javax/xml/bind/DatatypeConverter.java
javax/xml/bind/JAXB.java
javax/xml/bind/JAXBException.java
javax/xml/bind/TypeConstraintException.java
javax/xml/datatype/FactoryFinder.java
javax/xml/parsers/FactoryFinder.java
javax/xml/stream/FactoryFinder.java
javax/xml/stream/XMLStreamReader.java
javax/xml/transform/FactoryFinder.java
javax/xml/validation/SchemaFactoryFinder.java
javax/xml/xpath/XPathFactoryFinder.java
org/omg/CORBA/portable/ObjectImpl.java
org/omg/PortableServer/POAOperations.java
org/omg/PortableServer/Servant.java

第8章 その他の Java 8 機能を理解する : 問題 9 : Scanner から Stream を生成

問題

Scannerを、単語, 行, 整数, または double のStreamに変換するメソッドを書け。

解答

以下の手順でStreamを生成する。

  1. ScannerからIteratorを生成
  2. IteratorからSpliteratorを得る
  3. SpliteratorからStreamを生成

まず、IteratorからStreamを生成するメソッドを定義する。

private static <T> Stream<T> createStream(Iterator<T> iterator) {
    Spliterator<T> spliterator = 
        Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED);
    return StreamSupport.stream(spliterator, false);
}

■ 単語のStream

public static Stream<String> wordStream(Scanner scanner) {
    return createStream(scanner);
}

■ 行のStream

public static Stream<String> lineStream(Scanner scanner) {
    Iterator<String> iterator = new Iterator<String>() {
        public String next() {
            return scanner.nextLine();
        }
        public boolean hasNext() {
            return scanner.hasNextLine();
        }
    };
    return createStream(iterator);
}

■ 整数のStream

public static IntStream intStream(Scanner scanner) {
    Iterator<Integer> iterator = new Iterator<Integer>() {
        public Integer next() {
            return scanner.nextInt();
        }
        public boolean hasNext() {
            return scanner.hasNextInt();
        }
    };
    return createStream(iterator).mapToInt(Integer::intValue);
}

■ double のStream

public static DoubleStream doubleStream(Scanner scanner) {
    Iterator<Double> iterator = new Iterator<Double>() {
        public Double next() {
            return scanner.nextDouble();
        }
        public boolean hasNext() {
            return scanner.hasNextDouble();
        }
    };
    return createStream(iterator).mapToDouble(Double::doubleValue);
}

第8章 その他の Java 8 機能を理解する : 問題 8 : Collections.CheckedQueue クラス

問題

CheckedQueueクラスの利点を示すプログラムを書け。

補足

CheckedQueueクラスは、公開されていない。
これはjava.util.CollectionsのネストクラスでCollectionscheckedQueueメソッドが返すクラスである。

解答

CheckedQueueクラスは、実行時に要素の型チェックを行うQueueである。
普通にジェネリックQueue<E>と宣言しても、コンパイル時に型がチェックされるだけで、実行時はノーチェックである。

例えば、Queueを引数にとる次のようなメソッドを定義する。

private static void getMoreWork(Queue queue) {
    queue.offer(Paths.get("alice.txt"));  // 正しい型の要素を追加
    queue.offer("war-and-peace.txt");     // 間違った型の要素を追加
}

このようなコードだと、コンパイラーは警告を出すが、コンパイル自体はできてしまう。
■ 通常のケース

Queue<Path> queue = new ArrayDeque<Path>();
getMoreWork(queue);
Object value;
while ((value = queue.poll()) != null) {
    System.out.println(((Path)value).isAbsolute());  // ← ここでキャストエラー
}

CheckedQueueを使ったケース

Queue<Path> queue = new ArrayDeque<Path>();
queue = Collections.checkedQueue(queue, Path.class);
getMoreWork(queue);  // ← このメソッド内でキャストエラー
Object value;
while ((value = queue.poll()) != null) {
    System.out.println(((Path)value).isAbsolute());
}