第8章 その他の Java 8 機能を理解する : 問題 14 : requireNonNull(T, Supplier<String>) メソッド
問題
java.util.Objects
のrequireNonNull(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()
メソッドは、directions
がnull
でないときはコストが掛かる。
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 : 繰り返し指定できるアノテーション
問題
以下のようなプログラムを実装せよ。
引数と戻り値の型はint
と想定する。
解答
JUnit の簡易版を実装せよ、ってことですな。
引数と戻り値の型がString
のTestCase
アノテーションは、本文で定義してあるので、それを流用する。
■ 単純な 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
を生成する。
Scanner
からIterator
を生成Iterator
からSpliterator
を得る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
のネストクラスでCollections
のcheckedQueue
メソッドが返すクラスである。
解答
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()); }