├── .gitignore ├── LICENSE ├── README.md ├── SUMMARY.md ├── docs ├── annotations.md ├── appendix.md ├── basics.md ├── classes-and-objects.md ├── collection-framework.md ├── concurrency-Guarded Blocks.md ├── concurrency-High Level Concurrency Objects.md ├── concurrency-Immutable Objects.md ├── concurrency-Liveness.md ├── concurrency-Processes and Threads.md ├── concurrency-Synchronization.md ├── concurrency.md ├── control-flow.md ├── exceptions-advantages.md ├── exceptions-catch-and-handle.md ├── exceptions-catch-or-specify.md ├── exceptions-chained-exceptions.md ├── exceptions-create-exception-class.md ├── exceptions-specify-exceptions-thrown.md ├── exceptions-throw.md ├── exceptions-unchecked-exception.md ├── exceptions.md ├── expressions.md ├── file-io.md ├── generics.md ├── getstarted.md ├── io-model.md ├── io-streams.md ├── io.md ├── jdbc.md ├── keywords.md ├── networking.md ├── oop.md ├── operators.md ├── overview.md ├── socket.md └── variables.md ├── images ├── basics │ ├── conversion.jpg │ ├── objects-tenElementArray.gif │ ├── primitive-data-types-conversion.jpg │ └── primitive-data-types.jpg ├── exception │ ├── exceptions-callstack.gif │ ├── exceptions-errorOccurs.gif │ ├── exceptions-hierarchy.gif │ └── exceptions-throwable.gif ├── generics │ ├── generics-listParent.gif │ ├── generics-payloadListHierarchy.gif │ ├── generics-sampleHierarchy.gif │ ├── generics-subtypeRelationship.gif │ └── generics-wildcardSubtyping.gif ├── io │ ├── byteStream.gif │ ├── io-dirStructure.gif │ ├── io-spec.gif │ ├── io-symlink.gif │ └── io-trav.gif ├── net │ ├── 1-10 signal-driven-io.png │ ├── 1-11 aio.png │ ├── 1-12 Comparison of the five IO models.png │ ├── 1-7 bio.png │ ├── 1-8 nio.png │ ├── 1-9 io-multiplexing.png │ ├── 1netw.gif │ ├── 2tcp.gif │ ├── 3tcpudp.gif │ ├── 5connect.gif │ └── 6connect.gif ├── oop │ ├── base-derived.jpg │ ├── concepts-bicycleObject.gif │ ├── concepts-bikeHierarchy.gif │ ├── concepts-object.gif │ ├── cooling-system.jpg │ ├── has-a.jpg │ ├── light.jpg │ ├── shape-iteration.jpg │ ├── shape-overriding.jpg │ └── shape.jpg └── overview │ └── jvm.jpg ├── java_logo.jpg └── samples └── essential-java-demos ├── .classpath ├── .project ├── resources ├── characteroutput.txt ├── invoicedata.txt ├── outagain.txt ├── usnumbers.txt └── xanadu.txt └── src └── com └── waylau └── essentialjava ├── annotation ├── AnnotationDemo.java ├── MyAnnotation.java └── package-info.java ├── array └── arraydemo │ ├── ArrayCopyDemo.java │ ├── ArrayCopyOfDemo.java │ ├── ArrayDemo.java │ ├── MultiDimArrayDemo.java │ └── package-info.java ├── concurrency ├── Consumer.java ├── Counter.java ├── Deadlock.java ├── Drop.java ├── ForkBlur.java ├── HelloRunnable.java ├── HelloThread.java ├── ImmutableRGB.java ├── MsLunch.java ├── Producer.java ├── ProducerConsumerExample.java ├── Safelock.java ├── SimpleThreads.java ├── SleepMessages.java ├── SynchronizedCounter.java ├── SynchronizedRGB.java └── package-info.java ├── exception ├── ListOfNumbers.java └── trywithresources │ ├── Demo.java │ ├── Demo2.java │ └── package-info.java ├── expression └── blockdemo │ ├── BlockDemo.java │ ├── ShareExceptionHandler.java │ └── package-info.java ├── flow ├── branchdemo │ ├── BreakDemo.java │ ├── BreakWithLabelDemo.java │ └── package-info.java ├── continuedemo │ ├── ContinueDemo.java │ ├── ContinueWithLabelDemo.java │ └── package-info.java ├── fordemo │ ├── EnhancedForDemo.java │ ├── ForDemo.java │ └── package-info.java ├── ifelsedemo │ ├── IfElseDemo.java │ └── package-info.java ├── switchdemo │ ├── StringSwitchDemo.java │ ├── SwitchDemo.java │ ├── SwitchDemo2.java │ ├── SwitchDemoFallThrough.java │ └── package-info.java └── whiledemo │ ├── DoWhileDemo.java │ ├── WhileDemo.java │ └── package-info.java ├── generic ├── boxdemo │ ├── Box.java │ └── package-info.java └── generic │ └── boxdemo │ ├── Box.java │ └── package-info.java ├── io ├── bytestream │ ├── CopyBytes.java │ └── package-info.java ├── characterstream │ ├── CopyCharacters.java │ ├── CopyLines.java │ └── package-info.java ├── commandline │ ├── Password.java │ └── package-info.java ├── datastream │ ├── DataStreams.java │ └── package-info.java ├── formatting │ ├── Format.java │ ├── Root.java │ ├── Root2.java │ └── package-info.java ├── objectstream │ ├── ObjectStreams.java │ └── package-info.java ├── package-info.java ├── path │ ├── Copy.java │ ├── FileTest.java │ └── package-info.java └── scanning │ ├── ScanSum.java │ ├── ScanXan.java │ └── package-info.java ├── net ├── echo │ ├── AsyncEchoServer.java │ ├── EchoClient.java │ ├── EchoServer.java │ ├── EchoServerHandler.java │ ├── MultiThreadEchoServer.java │ ├── NonBlokingEchoServer.java │ ├── ThreadPoolEchoServer.java │ └── package-info.java └── package-info.java ├── object ├── bicycledemo │ ├── Bicycle.java │ ├── BicycleDemo.java │ ├── MountainBike.java │ └── package-info.java ├── enumdemo │ ├── Day.java │ ├── EnumTest.java │ ├── Planet.java │ └── package-info.java └── interfacebiycledemo │ ├── ACMEBicycle.java │ ├── Bicycle.java │ └── package-info.java ├── operator ├── arithmeticdemo │ ├── ArithmeticDemo.java │ ├── ConcatDemo.java │ └── package-info.java ├── bitdemo │ ├── BitDemo.java │ └── package-info.java ├── conditionaldemo │ ├── ConditionalDemo1.java │ ├── ConditionalDemo2.java │ └── package-info.java ├── instanceofdemo │ ├── InstanceofDemo.java │ └── package-info.java ├── relationaldemo │ ├── ComparisonDemo.java │ └── package-info.java └── unarydemo │ ├── PrePostDemo.java │ ├── UnaryDemo.java │ └── package-info.java └── package-info.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | /target/ 14 | /.idea/ 15 | /.settings/ 16 | .classpath 17 | .project -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Way Lau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Essential Java.《Java 编程要点》 2 | 3 | ![](java_logo.jpg) 4 | 5 | Essential Java, is a book about the Essentials of Java Programming. 6 | 7 | There is also a GitBook version of this book: . 8 | 9 | 10 | 《Java 编程要点》是一本 Java 的开源学习教程,主要介绍 Java 中应用广泛的部分(言外之意,本书不涉 Applet 以及 GUI 框架)。本书包括最新版本 Java 8 中的新特性,以及部分 JDK 9里面的内容,图文并茂,并通过大量实例带你走近 Java 的世界! 11 | 12 | 本书业余时间所著,水平有限、时间紧张,难免疏漏,欢迎指正, 13 | 14 | ### Get start 如何开始阅读 15 | 16 | 选择下面入口之一: 17 | 18 | * 的 [SUMMARY.md](https://github.com/waylau/essential-java/blob/master/SUMMARY.md) 19 | * 的 Read 按钮 20 | 21 | ### Code 源码 22 | 23 | 书中所有示例源码,移步至的 `samples` 目录下,代码遵循《[Java 编码规范]()》 24 | 25 | ### Issue 意见、建议 26 | 27 | 如有勘误、意见或建议欢迎拍砖 28 | 29 | ### Contact 联系作者: 30 | 31 | * Blog: [waylau.com](http://waylau.com) 32 | * Gmail: [waylau521(at)gmail.com](mailto:waylau521@gmail.com) 33 | * Weibo: [waylau521](http://weibo.com/waylau521) 34 | * Twitter: [waylau521](https://twitter.com/waylau521) 35 | * Github : [waylau](https://github.com/waylau) -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [快速开始](docs/getstarted.md) 5 | * [Java概述](docs/overview.md) 6 | * [面向对象编程](docs/oop.md) 7 | * [语言基础](docs/basics.md) 8 | * [变量](docs/variables.md) 9 | * [运算符](docs/operators.md) 10 | * [表达式、语句和块](docs/expressions.md) 11 | * [控制流程语句](docs/control-flow.md) 12 | * [类和对象](docs/classes-and-objects.md) 13 | * [注解](docs/annotations.md) 14 | * [泛型](docs/generics.md) 15 | * [关键字](docs/keywords.md) 16 | * [IO](docs/io.md) 17 | * [I/O 流](docs/io-streams.md) 18 | * [文件 I/O](docs/file-io.md) 19 | * [并发](docs/concurrency.md) 20 | * [进程(Processes )和线程(Threads)](docs/concurrency-Processes%20and%20Threads.md) 21 | * [同步](docs/concurrency-Synchronization.md) 22 | * [活跃度(Liveness)](docs/concurrency-Liveness.md) 23 | * [Guarded Blocks](docs/concurrency-Guarded%20Blocks.md) 24 | * [不可变对象(Immutable Objects)](docs/concurrency-Immutable%20Objects.md) 25 | * [高级并发对象](docs/concurrency-High%20Level%20Concurrency%20Objects.md) 26 | * [集合框架](docs/collection-framework.md) 27 | * 网络编程 28 | * [网络基础](docs/networking.md) 29 | * [Socket](docs/socket.md) 30 | * [I/O 模型的演进](docs/io-model.md) 31 | * [JDBC](docs/jdbc.md) 32 | * [异常](docs/exceptions.md) 33 | * [异常捕获与处理](docs/exceptions-catch-and-handle.md) 34 | * [通过方法声明异常抛出](docs/exceptions-specify-exceptions-thrown.md) 35 | * [如何抛出异常](docs/exceptions-throw.md) 36 | * [异常链](docs/exceptions-chained-exceptions.md) 37 | * [创建异常类](docs/exceptions-create-exception-class.md) 38 | * [未检查异常](docs/exceptions-unchecked-exception.md) 39 | * [使用异常带来的优势](docs/exceptions-advantages.md) 40 | * [附录](docs/appendix.md) 41 | * To be continued ...未完待续... 42 | 43 | -------------------------------------------------------------------------------- /docs/appendix.md: -------------------------------------------------------------------------------- 1 | # 附录 2 | 3 | ## 参考引用 4 | 5 | * [Core Java Tenth Edition](http://www.amazon.com/Core-Java-I--Fundamentals-10th/dp/0134177304) 6 | * [Thinking in Java Fourth Edition](http://mindview.net/Books/TIJ4) 7 | * [The Well-Grounded Java Developer](http://www.amazon.com/The-Well-Grounded-Java-Developer-programming/dp/1617290068) 8 | * [The Java Tutorial, Sixth Edition](http://www.amazon.com/The-Java-Tutorial-Course-Edition/dp/0134034082) 9 | * TCP/IP Illustrated Volume 1: The Protocols 10 | * [Java Network Programming, 4th Edition](http://my.safaribooksonline.com/book/programming/java/9781449365936) 11 | * [Pro Java 7 NIO.2](http://www.amazon.com/Pro-Java-NIO-2-Experts-Voice/dp/1430240113) 12 | * [Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition)](http://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551/ref=sr_1_1?ie=UTF8&qid=1456823747&sr=8-1&keywords=unix+network+programming) -------------------------------------------------------------------------------- /docs/basics.md: -------------------------------------------------------------------------------- 1 | # 语言基础 2 | 3 | 本章介绍 Java 的语言基础。 4 | 5 | -------------------------------------------------------------------------------- /docs/classes-and-objects.md: -------------------------------------------------------------------------------- 1 | # 类和对象 2 | 3 | ## 枚举类型(Enum Type) 4 | 5 | 枚举类型是一种特殊的数据类型,使一个变量是一组预定义的常量。变量必须等于已预先定义的值之一。常见的例子包括罗盘方向( NORTH, SOUTH, EAST 和 WEST)和星期几。 6 | 7 | 使用关键字 enum ,下面是一个星期几的枚举列子: 8 | 9 | ``` 10 | public enum Day { 11 | SUNDAY, MONDAY, TUESDAY, WEDNESDAY, 12 | THURSDAY, FRIDAY, SATURDAY 13 | } 14 | ``` 15 | 16 | 使用枚举类型,需要一组固定的常数。这包括自然枚举类型,如在我们的太阳系的行星,菜单上的选项,命令行标志,等等。 17 | 18 | 下面是一些代码,展示如何使用上面定义的 Day 枚举: 19 | 20 | ```java 21 | class EnumTest { 22 | 23 | Day day; 24 | 25 | public EnumTest(Day day) { 26 | this.day = day; 27 | } 28 | 29 | public void tellItLikeItIs() { 30 | switch (day) { 31 | case MONDAY: 32 | System.out.println("Mondays are bad."); 33 | break; 34 | 35 | case FRIDAY: 36 | System.out.println("Fridays are better."); 37 | break; 38 | 39 | case SATURDAY: case SUNDAY: 40 | System.out.println("Weekends are best."); 41 | break; 42 | 43 | default: 44 | System.out.println("Midweek days are so-so."); 45 | break; 46 | } 47 | } 48 | 49 | public static void main(String[] args) { 50 | EnumTest firstDay = new EnumTest(Day.MONDAY); 51 | firstDay.tellItLikeItIs(); 52 | EnumTest thirdDay = new EnumTest(Day.WEDNESDAY); 53 | thirdDay.tellItLikeItIs(); 54 | EnumTest fifthDay = new EnumTest(Day.FRIDAY); 55 | fifthDay.tellItLikeItIs(); 56 | EnumTest sixthDay = new EnumTest(Day.SATURDAY); 57 | sixthDay.tellItLikeItIs(); 58 | EnumTest seventhDay = new EnumTest(Day.SUNDAY); 59 | seventhDay.tellItLikeItIs(); 60 | } 61 | } 62 | ``` 63 | 64 | 输出为: 65 | 66 | ``` 67 | Mondays are bad. 68 | Midweek days are so-so. 69 | Fridays are better. 70 | Weekends are best. 71 | Weekends are best. 72 | ``` 73 | 74 | 下面是一个 Planet 示例,展示了 枚举值的 for-each 遍历: 75 | 76 | ```java 77 | public enum Planet { 78 | MERCURY (3.303e+23, 2.4397e6), 79 | VENUS (4.869e+24, 6.0518e6), 80 | EARTH (5.976e+24, 6.37814e6), 81 | MARS (6.421e+23, 3.3972e6), 82 | JUPITER (1.9e+27, 7.1492e7), 83 | SATURN (5.688e+26, 6.0268e7), 84 | URANUS (8.686e+25, 2.5559e7), 85 | NEPTUNE (1.024e+26, 2.4746e7); 86 | 87 | private final double mass; // in kilograms 88 | private final double radius; // in meters 89 | Planet(double mass, double radius) { 90 | this.mass = mass; 91 | this.radius = radius; 92 | } 93 | private double mass() { return mass; } 94 | private double radius() { return radius; } 95 | 96 | // universal gravitational constant (m3 kg-1 s-2) 97 | public static final double G = 6.67300E-11; 98 | 99 | double surfaceGravity() { 100 | return G * mass / (radius * radius); 101 | } 102 | double surfaceWeight(double otherMass) { 103 | return otherMass * surfaceGravity(); 104 | } 105 | public static void main(String[] args) { 106 | if (args.length != 1) { 107 | System.err.println("Usage: java Planet "); 108 | System.exit(-1); 109 | } 110 | double earthWeight = Double.parseDouble(args[0]); 111 | double mass = earthWeight/EARTH.surfaceGravity(); 112 | for (Planet p : Planet.values()) 113 | System.out.printf("Your weight on %s is %f%n", 114 | p, p.surfaceWeight(mass)); 115 | } 116 | } 117 | ``` 118 | 119 | 在命令行,输入参数为 175 时, 120 | 输出如下: 121 | 122 | ``` 123 | $ java Planet 175 124 | Your weight on MERCURY is 66.107583 125 | Your weight on VENUS is 158.374842 126 | Your weight on EARTH is 175.000000 127 | Your weight on MARS is 66.279007 128 | Your weight on JUPITER is 442.847567 129 | Your weight on SATURN is 186.552719 130 | Your weight on URANUS is 158.397260 131 | Your weight on NEPTUNE is 199.207413 132 | ``` -------------------------------------------------------------------------------- /docs/collection-framework.md: -------------------------------------------------------------------------------- 1 | # 集合框架 2 | -------------------------------------------------------------------------------- /docs/concurrency-Guarded Blocks.md: -------------------------------------------------------------------------------- 1 | ## Guarded Blocks 2 | 3 | 多线程之间经常需要协同工作,最常见的方式是使用 Guarded Blocks,它循环检查一个条件(通常初始值为 true),直到条件发生变化才跳出循环继续执行。在使用 Guarded Blocks 时有以下几个步骤需要注意: 4 | 5 | 假设 guardedJoy 方法必须要等待另一线程为共享变量 joy 设值才能继续执行。那么理论上可以用一个简单的条件循环来实现,但在等待过程中 guardedJoy 方法不停的检查循环条件实际上是一种资源浪费。 6 | 7 | public void guardedJoy() { 8 | // Simple loop guard. Wastes 9 | // processor time. Don't do this! 10 | while(!joy) {} 11 | System.out.println("Joy has been achieved!"); 12 | } 13 | 14 | 更加高效的保护方法是调用 [Object.wait](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--) 将当前线程挂起,直到有另一线程发起事件通知(尽管通知的事件不一定是当前线程等待的事件)。 15 | 16 | public synchronized void guardedJoy() { 17 | // This guard only loops once for each special event, which may not 18 | // be the event we're waiting for. 19 | while(!joy) { 20 | try { 21 | wait(); 22 | } catch (InterruptedException e) {} 23 | } 24 | System.out.println("Joy and efficiency have been achieved!"); 25 | } 26 | 27 | 28 | *注意:一定要在循环里面调用 wait 方法,不要想当然的认为线程唤醒后循环条件一定发生了改变。* 29 | 30 | 和其他可以暂停线程执行的方法一样,wait 方法会抛出 InterruptedException,在上面的例子中,因为我们关心的是 joy 的值,所以忽略了 InterruptedException。 31 | 32 | 为什么 guardedJoy 是 synchronized 的?假设 d 是用来调用 wait 的对象,当一个线程调用 d.wait,它必须要拥有 d的内部锁(否则会抛出异常),获得 d 的内部锁的最简单方法是在一个 synchronized 方法里面调用 wait。 33 | 34 | 当一个线程调用 wait 方法时,它释放锁并挂起。然后另一个线程请求并获得这个锁并调用 Object.notifyAll 通知所有等待该锁的线程。 35 | 36 | public synchronized notifyJoy() { 37 | joy = true; 38 | notifyAll(); 39 | } 40 | 41 | 当第二个线程释放这个该锁后,第一个线程再次请求该锁,从 wait 方法返回并继续执行。 42 | 43 | 注意:还有另外一个通知方法,notify(),它只会唤醒一个线程。但由于它并不允许指定哪一个线程被唤醒,所以一般只在大规模并发应用(即系统有大量相似任务的线程)中使用。因为对于大规模并发应用,我们其实并不关心哪一个线程被唤醒。 44 | 45 | 现在我们使用 Guarded blocks 创建一个生产者/消费者应用。这类应用需要在两个线程之间共享数据:生产者生产数据,消费者使用数据。两个线程通过共享对象通信。在这里,线程协同工作的关键是:生产者发布数据之前,消费者不能够去读取数据;消费者没有读取旧数据前,生产者不能发布新数据。 46 | 47 | 在下面的例子中,数据通过 Drop 对象共享的一系列文本消息: 48 | 49 | ```java 50 | public class Drop { 51 | // Message sent from producer 52 | // to consumer. 53 | private String message; 54 | // True if consumer should wait 55 | // for producer to send message, 56 | // false if producer should wait for 57 | // consumer to retrieve message. 58 | private boolean empty = true; 59 | 60 | public synchronized String take() { 61 | // Wait until message is 62 | // available. 63 | while (empty) { 64 | try { 65 | wait(); 66 | } catch (InterruptedException e) {} 67 | } 68 | // Toggle status. 69 | empty = true; 70 | // Notify producer that 71 | // status has changed. 72 | notifyAll(); 73 | return message; 74 | } 75 | 76 | public synchronized void put(String message) { 77 | // Wait until message has 78 | // been retrieved. 79 | while (!empty) { 80 | try { 81 | wait(); 82 | } catch (InterruptedException e) {} 83 | } 84 | // Toggle status. 85 | empty = false; 86 | // Store message. 87 | this.message = message; 88 | // Notify consumer that status 89 | // has changed. 90 | notifyAll(); 91 | } 92 | } 93 | ``` 94 | 95 | Producer 是生产者线程,发送一组消息,字符串 DONE 表示所有消息都已经发送完成。为了模拟现实情况,生产者线程还会在消息发送时随机的暂停。 96 | 97 | ```java 98 | public class Producer implements Runnable { 99 | private Drop drop; 100 | 101 | public Producer(Drop drop) { 102 | this.drop = drop; 103 | } 104 | 105 | public void run() { 106 | String importantInfo[] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", 107 | "A kid will eat ivy too" }; 108 | Random random = new Random(); 109 | 110 | for (int i = 0; i < importantInfo.length; i++) { 111 | drop.put(importantInfo[i]); 112 | try { 113 | Thread.sleep(random.nextInt(5000)); 114 | } catch (InterruptedException e) { 115 | } 116 | } 117 | drop.put("DONE"); 118 | } 119 | } 120 | ``` 121 | 122 | 123 | Consumer 是消费者线程,读取消息并打印出来,直到读取到字符串 DONE 为止。消费者线程在消息读取时也会随机的暂停。 124 | 125 | ```java 126 | public class Consumer implements Runnable { 127 | private Drop drop; 128 | 129 | public Consumer(Drop drop) { 130 | this.drop = drop; 131 | } 132 | 133 | public void run() { 134 | Random random = new Random(); 135 | for (String message = drop.take(); !message.equals("DONE"); message = drop.take()) { 136 | System.out.format("MESSAGE RECEIVED: %s%n", message); 137 | try { 138 | Thread.sleep(random.nextInt(5000)); 139 | } catch (InterruptedException e) { 140 | } 141 | } 142 | } 143 | } 144 | ``` 145 | 146 | ProducerConsumerExample 是主线程,它启动生产者线程和消费者线程。 147 | 148 | ```java 149 | public class ProducerConsumerExample { 150 | public static void main(String[] args) { 151 | Drop drop = new Drop(); 152 | (new Thread(new Producer(drop))).start(); 153 | (new Thread(new Consumer(drop))).start(); 154 | } 155 | } 156 | ``` 157 | -------------------------------------------------------------------------------- /docs/concurrency-Immutable Objects.md: -------------------------------------------------------------------------------- 1 | ## 不可变对象(Immutable Objects) 2 | 3 | 如果一个对象它被构造后其,状态不能改变,则这个对象被认为是不可变的(immutable )。不可变对象的好处是可以创建简单的、可靠的代码。 4 | 5 | 不可变对象在并发应用种特别有用。因为他们不能改变状态,它们不能被线程干扰所中断或者被其他线程观察到内部不一致的状态。 6 | 7 | 程序员往往不愿使用不可变对象,因为他们担心创建一个新的对象要比更新对象的成本要高。实际上这种开销常常被过分高估,而且使用不可变对象所带来的一些效率提升也抵消了这种开销。例如:使用不可变对象降低了垃圾回收所产生的额外开销,也减少了用来确保使用可变对象不出现并发错误的一些额外代码。 8 | 9 | 接下来看一个可变对象的类,然后转化为一个不可变对象的类。通过这个例子说明转化的原则以及使用不可变对象的好处。 10 | 11 | ### 一个同步类的例子 12 | 13 | SynchronizedRGB 是表示颜色的类,每一个对象代表一种颜色,使用三个整形数表示颜色的三基色,字符串表示颜色名称。 14 | 15 | ```java 16 | public class SynchronizedRGB { 17 | // Values must be between 0 and 255. 18 | private int red; 19 | private int green; 20 | private int blue; 21 | private String name; 22 | 23 | private void check(int red, 24 | int green, 25 | int blue) { 26 | if (red < 0 || red > 255 27 | || green < 0 || green > 255 28 | || blue < 0 || blue > 255) { 29 | throw new IllegalArgumentException(); 30 | } 31 | } 32 | 33 | public SynchronizedRGB(int red, 34 | int green, 35 | int blue, 36 | String name) { 37 | check(red, green, blue); 38 | this.red = red; 39 | this.green = green; 40 | this.blue = blue; 41 | this.name = name; 42 | } 43 | 44 | public void set(int red, 45 | int green, 46 | int blue, 47 | String name) { 48 | check(red, green, blue); 49 | synchronized (this) { 50 | this.red = red; 51 | this.green = green; 52 | this.blue = blue; 53 | this.name = name; 54 | } 55 | } 56 | 57 | public synchronized int getRGB() { 58 | return ((red << 16) | (green << 8) | blue); 59 | } 60 | 61 | public synchronized String getName() { 62 | return name; 63 | } 64 | 65 | public synchronized void invert() { 66 | red = 255 - red; 67 | green = 255 - green; 68 | blue = 255 - blue; 69 | name = "Inverse of " + name; 70 | } 71 | } 72 | ``` 73 | 使用 SynchronizedRGB 时需要小心,避免其处于不一致的状态。例如一个线程执行了以下代码: 74 | 75 | SynchronizedRGB color = 76 | new SynchronizedRGB(0, 0, 0, "Pitch Black"); 77 | ... 78 | int myColorInt = color.getRGB(); //Statement 1 79 | String myColorName = color.getName(); //Statement 2 80 | 81 | 82 | 如果有另外一个线程在 Statement 1 之后、Statement 2 之前调用了 color.set 方法,那么 myColorInt 的值和 myColorName 的值就会不匹配。为了避免出现这样的结果,必须要像下面这样把这两条语句绑定到一块执行: 83 | 84 | synchronized (color) { 85 | int myColorInt = color.getRGB(); 86 | String myColorName = color.getName(); 87 | } 88 | 89 | 这种不一致的问题只可能发生在可变对象上。 90 | 91 | ### 定义不可变对象的策略 92 | 93 | 以下的一些创建不可变对象的简单策略。并非所有不可变类都完全遵守这些规则,不过这不是编写这些类的程序员们粗心大意造成的,很可能的是他们有充分的理由确保这些对象在创建后不会被修改。但这需要非常复杂细致的分析,并不适用于初学者。 94 | 95 | * 不要提供 setter 方法。(包括修改字段的方法和修改字段引用对象的方法) 96 | * 将类的所有字段定义为 final、private 的。 97 | * 不允许子类重写方法。简单的办法是将类声明为 final,更好的方法是将构造函数声明为私有的,通过工厂方法创建对象。 98 | * 如果类的字段是对可变对象的引用,不允许修改被引用对象。 99 | * 不提供修改可变对象的方法。 100 | * 不共享可变对象的引用。当一个引用被当做参数传递给构造函数,而这个引用指向的是一个外部的可变对象时,一定不要保存这个引用。如果必须要保存,那么创建可变对象的拷贝,然后保存拷贝对象的引用。同样如果需要返回内部的可变对象时,不要返回可变对象本身,而是返回其拷贝。 101 | 102 | 将这一策略应用到 SynchronizedRGB 有以下几步: 103 | 104 | * SynchronizedRGB 类有两个 setter 方法。第一个 set 方法只是简单的为字段设值,第二个 invert 方法修改为创建一个新对象,而不是在原有对象上修改。 105 | * 所有的字段都已经是私有的,加上 final 即可。 106 | * 将类声明为 final 的 107 | * 只有一个字段是对象引用,并且被引用的对象也是不可变对象。 108 | 109 | 经过以上这些修改后,我们得到了 ImmutableRGB: 110 | 111 | ```java 112 | public class ImmutableRGB { 113 | // Values must be between 0 and 255. 114 | final private int red; 115 | final private int green; 116 | final private int blue; 117 | final private String name; 118 | 119 | private void check(int red, 120 | int green, 121 | int blue) { 122 | if (red < 0 || red > 255 123 | || green < 0 || green > 255 124 | || blue < 0 || blue > 255) { 125 | throw new IllegalArgumentException(); 126 | } 127 | } 128 | 129 | public ImmutableRGB(int red, 130 | int green, 131 | int blue, 132 | String name) { 133 | check(red, green, blue); 134 | this.red = red; 135 | this.green = green; 136 | this.blue = blue; 137 | this.name = name; 138 | } 139 | 140 | 141 | public int getRGB() { 142 | return ((red << 16) | (green << 8) | blue); 143 | } 144 | 145 | public String getName() { 146 | return name; 147 | } 148 | 149 | public ImmutableRGB invert() { 150 | return new ImmutableRGB(255 - red, 151 | 255 - green, 152 | 255 - blue, 153 | "Inverse of " + name); 154 | } 155 | } 156 | ``` 157 | 158 | -------------------------------------------------------------------------------- /docs/concurrency-Liveness.md: -------------------------------------------------------------------------------- 1 | ## 活跃度(Liveness) 2 | 3 | 一个并行应用程序的及时执行能力被称为它的活跃度(liveness)。本节将介绍最常见的一种活跃度的问题——死锁,以及另外两个活跃度的问题——饥饿和活锁。 4 | 5 | ### 死锁(Deadlock) 6 | 7 | 死锁是指两个或两个以上的线程永远被阻塞,一直等待对方的资源。 8 | 9 | 下面是一个例子。 10 | 11 | Alphonse 和 Gaston 是朋友,都很有礼貌。礼貌的一个严格的规则是,当你给一个朋友鞠躬时,你必须保持鞠躬,直到你的朋友鞠躬回给你。不幸的是,这条规则有个缺陷,那就是如果两个朋友同一时间向对方鞠躬,那就永远不会完了。这个示例应用程序中,死锁模型是这样的: 12 | 13 | ```java 14 | public class Deadlock { 15 | static class Friend { 16 | private final String name; 17 | 18 | public Friend(String name) { 19 | this.name = name; 20 | } 21 | 22 | public String getName() { 23 | return this.name; 24 | } 25 | 26 | public synchronized void bow(Friend bower) { 27 | System.out.format("%s: %s" + " has bowed to me!%n", this.name, bower.getName()); 28 | bower.bowBack(this); 29 | } 30 | 31 | public synchronized void bowBack(Friend bower) { 32 | System.out.format("%s: %s" + " has bowed back to me!%n", this.name, bower.getName()); 33 | } 34 | } 35 | 36 | public static void main(String[] args) { 37 | final Friend alphonse = new Friend("Alphonse"); 38 | final Friend gaston = new Friend("Gaston"); 39 | new Thread(new Runnable() { 40 | public void run() { 41 | alphonse.bow(gaston); 42 | } 43 | }).start(); 44 | new Thread(new Runnable() { 45 | public void run() { 46 | gaston.bow(alphonse); 47 | } 48 | }).start(); 49 | } 50 | } 51 | ``` 52 | 53 | 当他们尝试调用 bowBack 两个线程将被阻塞。无论是哪个线程永远不会结束,因为每个线程都在等待对方鞠躬。这就是死锁了。 54 | 55 | ### 饥饿和活锁(Starvation and Livelock) 56 | 57 | 饥饿和活锁虽比死锁问题稍微不常见点,但这些是在并发软件种每一个设计师仍然可能会遇到的问题。 58 | 59 | #### 饥饿(Starvation) 60 | 61 | 饥饿描述了这样一个情况,一个线程不能获得定期访问共享资源,于是无法继续执行。这种情况一般出现在共享资源被某些“贪婪”线程占用,而导致资源长时间不被其他线程可用。例如,假设一个对象提供一个同步的方法,往往需要很长时间返回。如果一个线程频繁调用该方法,其他线程若也需要频繁的同步访问同一个对象通常会被阻塞。 62 | 63 | #### 活锁(Livelock) 64 | 65 | 一个线程常常处于响应另一个线程的动作,如果其他线程也常常处于该线程的动作,那么就可能出现活锁。与死锁、活锁的线程一样,程序无法进一步执行。然而,线程是不会阻塞的,他们只是会忙于应对彼此的恢复工作。现实种的例子是,两人面对面试图通过一条走廊: Alphonse 移动到他的左则让路给 Gaston ,而 Gaston 移动到他的右侧想让 Alphonse 过去,两个人同时让路,但其实两人都挡住了对方没办法过去,他们仍然彼此阻塞。 66 | -------------------------------------------------------------------------------- /docs/concurrency-Processes and Threads.md: -------------------------------------------------------------------------------- 1 | ## 进程(Processes )和线程(Threads) 2 | 3 | 进程和线程是并发编程的两个基本的执行单元。在 Java 中,并发编程主要涉及线程。 4 | 5 | 一个计算机系统通常有许多活动的进程和线程。在给定的时间内,每个处理器只能有一个线程得到真正的运行。对于单核处理器来说,处理时间是通过时间切片来在进程和线程之间进行共享的。 6 | 7 | 现在多核处理器或多进程的电脑系统越来越流行。这大大增强了系统的进程和线程的并发执行能力。但即便是没有多处理器或多进程的系统中,并发仍然是可能的。 8 | 9 | ### 进程 10 | 11 | 进程有一个独立的执行环境。进程通常有一个完整的、私人的基本运行时资源;特别是,每个进程都有其自己的内存空间。 12 | 13 | 进程往往被视为等同于程序或应用程序。然而,用户将看到一个单独的应用程序可能实际上是一组合作的进程。大多数操作系统都支持进程间通信( Inter Process Communication,简称 IPC)资源,如管道和套接字。IPC 不仅用于同个系统的进程之间的通信,也可以用在不同系统的进程。 14 | 15 | 大多数 Java 虚拟机的实现作为一个进程运行。Java 应用程序可以使用 [ProcessBuilder](https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessBuilder.html) 对象创建额外的进程。多进程应用程序超出了本书的讲解范围。 16 | 17 | ### 线程 18 | 19 | 线程有时被称为轻量级进程。进程和线程都提供一个执行环境,但创建一个新的线程比创建一个新的进程需要更少的资源。 20 | 21 | 线程中存在于进程中,每个进程都至少一个线程。线程共享进程的资源,包括内存和打开的文件。这使得工作变得高效,但也存在了一个潜在的问题——通信。 22 | 23 | 多线程执行是 Java 平台的一个重要特点。每个应用程序都至少有一个线程,或者几个,如果算上“系统”的线程(负责内存管理和信号处理)那就更多。但从程序员的角度来看,你启动只有一个线程,称为主线程。这个线程有能力创建额外的线程。 24 | 25 | ## 线程对象 26 | 27 | 每个线程都与 [Thread](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html) 类的一个实例相关联。有两种使用线程对象来创建并发应用程序的基本策略: 28 | 29 | * 为了直接控制线程的创建和管理,简单地初始化线程,应用程序每次需要启动一个异步任务。 30 | * 通过传递给应用程序任务给一个 executor,从而从应用程序的其他部分抽象出线程管理。 31 | 32 | ### 定义和启动一个线程 33 | 34 | Java 中有两种方式创建 Thread 的实例: 35 | 36 | * 提供 Runnable 对象。Runnable 接口定义了一个方法 run ,用来包含线程要执行的代码。如 HelloRunnable 所示: 37 | 38 | ```java 39 | public class HelloRunnable implements Runnable { 40 | /* (non-Javadoc) 41 | * @see java.lang.Runnable#run() 42 | */ 43 | @Override 44 | public void run() { 45 | System.out.println("Hello from a thread!"); 46 | } 47 | 48 | /** 49 | * @param args 50 | */ 51 | public static void main(String[] args) { 52 | (new Thread(new HelloRunnable())).start(); 53 | } 54 | } 55 | ``` 56 | 57 | * 继承 Thread。Thread 类本身是实现 Runnable,虽然它的 run 方法啥都没干。HelloThread 示例如下: 58 | 59 | ```java 60 | public class HelloThread extends Thread { 61 | 62 | public void run() { 63 | System.out.println("Hello from a thread!"); 64 | } 65 | /** 66 | * @param args 67 | */ 68 | public static void main(String[] args) { 69 | (new HelloThread()).start(); 70 | } 71 | } 72 | ``` 73 | 74 | 请注意,这两个例子调用 start 来启动线程。 75 | 76 | 第一种方式,它使用 Runnable 对象,在实际应用中更普遍,因为 Runnable 对象可以继承 Thread 以外的类。第二种方式,在简单的应用程序更容易使用,但受限于你的任务类必须是一个 Thread 的后代。本书推荐使用第一种方法,将 Runnable 任务从 Thread 对象分离来执行任务。这不仅更灵活,而且它适用于高级线程管理 API。 77 | 78 | Thread 类还定义了大量的方法用于线程管理。 79 | 80 | ### Sleep 来暂停执行 81 | 82 | Thread.sleep 可以让当前线程执行暂停一个时间段,这样处理器时间就可以给其他线程使用。 83 | 84 | sleep 有两种重载形式:一个是指定睡眠时间为毫秒,另外一个是指定睡眠时间为纳秒级。然而,这些睡眠时间不能保证是精确的,因为它们是通过由操作系统来提供的,并受其限制,因而不能假设 sleep 的睡眠时间是精确的。此外,睡眠周期也可以通过中断终止,我们将在后面的章节中看到。 85 | 86 | SleepMessages 示例使用 sleep 每隔4秒打印一次消息: 87 | 88 | ```java 89 | public class SleepMessages { 90 | 91 | /** 92 | * @param args 93 | */ 94 | public static void main(String[] args) throws InterruptedException { 95 | String importantInfo[] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", 96 | "A kid will eat ivy too" }; 97 | 98 | for (int i = 0; i < importantInfo.length; i++) { 99 | 100 | // Pause for 4 seconds 101 | Thread.sleep(4000); 102 | 103 | // Print a message 104 | System.out.println(importantInfo[i]); 105 | } 106 | } 107 | } 108 | ``` 109 | 110 | 请注意 main 声明抛出 InterruptedException。当 sleep 是激活的时候,若有另一个线程中断当前线程时,则 sleep 抛出异常。由于该应用程序还没有定义的另一个线程来引起的中断,所以考虑捕捉 InterruptedException。 111 | 112 | ### 中断(interrupt) 113 | 114 | 中断是表明一个线程,它应该停止它正在做和将要做的事。线程通过在 Thread 对象调用 [interrupt](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#interrupt--) 来实现线程的中断。为了中断机制能正常工作,被中断的线程必须支持自己的中断。 115 | 116 | #### 支持中断 117 | 118 | 如何实现线程支持自己的中断?这要看是它目前正在做什么。如果线程调用方法频繁抛出 InterruptedException 异常,那么它只要在 run 方法捕获了异常之后返回即可。例如 : 119 | 120 | for (int i = 0; i < importantInfo.length; i++) { 121 | 122 | // Pause for 4 seconds 123 | try { 124 | Thread.sleep(4000); 125 | } catch (InterruptedException e) { 126 | 127 | // We've been interrupted: no more messages. 128 | return; 129 | } 130 | 131 | // Print a message 132 | System.out.println(importantInfo[i]); 133 | } 134 | 135 | 很多方法都会抛出 InterruptedException,如 sleep,被设计成在收到中断时立即取消他们当前的操作并返回。 136 | 137 | 若线程长时间没有调用方法抛出 InterruptedException 的话,那么它必须定期调用 Thread.interrupted ,该方法在接收到中断后将返回 true。 138 | 139 | for (int i = 0; i < inputs.length; i++) { 140 | 141 | heavyCrunch(inputs[i]); 142 | 143 | if (Thread.interrupted()) { 144 | 145 | // We've been interrupted: no more crunching. 146 | return; 147 | } 148 | } 149 | 150 | 在这个简单的例子中,代码简单地测试该中断,如果已接收到中断线程就退出。在更复杂的应用程序,它可能会更有意义抛出一个 InterruptedException: 151 | 152 | if (Thread.interrupted()) { 153 | throw new InterruptedException(); 154 | } 155 | 156 | #### 中断状态标志 157 | 158 | 中断机制是使用被称为中断状态的内部标志实现的。调用 Thread.interrupt 可以设置该标志。当一个线程通过调用静态方法 Thread.interrupted 来检查中断,中断状态被清除。非静态 isInterrupted 方法,它是用于线程来查询另一个线程的中断状态,而不会改变中断状态标志。 159 | 160 | 按照惯例,任何方法因抛出一个 InterruptedException 而退出都会清除中断状态。当然,它可能因为另一个线程调用 interrupt 而让那个中断状态立即被重新设置回来。 161 | 162 | ### join 方法 163 | 164 | join 方法允许一个线程等待另一个完成。假设 t 是一个正在执行的 Thread 对象,那么 165 | 166 | t.join(); 167 | 168 | 它会导致当前线程暂停执行直到 t 线程终止。join 允许程序员指定一个等待周期。与 sleep 一样,等待时间是依赖于操作系统的时间,同时不能假设 join 等待时间是精确的。 169 | 170 | 像 sleep 一样,join 并通过 InterruptedException 退出来响应中断。 171 | 172 | ### SimpleThreads 示例 173 | 174 | SimpleThreads 示例由两个线程。第一个线程是每个 Java 应用程序都有的主线程。主线程创建的 Runnable 对象 MessageLoop,并等待它完成。如果 MessageLoop 需要很长时间才能完成,主线程就中断它。 175 | 176 | 该 MessageLoop 线程打印出一系列消息。如果中断之前就已经打印了所有消息,则 MessageLoop 线程打印一条消息并退出。 177 | 178 | ```java 179 | public class SimpleThreads { 180 | 181 | // Display a message, preceded by 182 | // the name of the current thread 183 | static void threadMessage(String message) { 184 | String threadName = 185 | Thread.currentThread().getName(); 186 | System.out.format("%s: %s%n", 187 | threadName, 188 | message); 189 | } 190 | 191 | private static class MessageLoop 192 | implements Runnable { 193 | public void run() { 194 | String importantInfo[] = { 195 | "Mares eat oats", 196 | "Does eat oats", 197 | "Little lambs eat ivy", 198 | "A kid will eat ivy too" 199 | }; 200 | try { 201 | for (int i = 0; i < importantInfo.length; i++) { 202 | 203 | // Pause for 4 seconds 204 | Thread.sleep(4000); 205 | 206 | // Print a message 207 | threadMessage(importantInfo[i]); 208 | } 209 | } catch (InterruptedException e) { 210 | threadMessage("I wasn't done!"); 211 | } 212 | } 213 | } 214 | 215 | public static void main(String args[]) 216 | throws InterruptedException { 217 | 218 | // Delay, in milliseconds before 219 | // we interrupt MessageLoop 220 | // thread (default one hour). 221 | long patience = 1000 * 60 * 60; 222 | 223 | // If command line argument 224 | // present, gives patience 225 | // in seconds. 226 | if (args.length > 0) { 227 | try { 228 | patience = Long.parseLong(args[0]) * 1000; 229 | } catch (NumberFormatException e) { 230 | System.err.println("Argument must be an integer."); 231 | System.exit(1); 232 | } 233 | } 234 | 235 | threadMessage("Starting MessageLoop thread"); 236 | long startTime = System.currentTimeMillis(); 237 | Thread t = new Thread(new MessageLoop()); 238 | t.start(); 239 | 240 | threadMessage("Waiting for MessageLoop thread to finish"); 241 | 242 | // loop until MessageLoop 243 | // thread exits 244 | while (t.isAlive()) { 245 | threadMessage("Still waiting..."); 246 | 247 | // Wait maximum of 1 second 248 | // for MessageLoop thread 249 | // to finish. 250 | 251 | t.join(1000); 252 | if (((System.currentTimeMillis() - startTime) > patience) 253 | && t.isAlive()) { 254 | threadMessage("Tired of waiting!"); 255 | t.interrupt(); 256 | 257 | // Shouldn't be long now 258 | // -- wait indefinitely 259 | t.join(); 260 | } 261 | } 262 | threadMessage("Finally!"); 263 | } 264 | } 265 | ``` 266 | 267 | -------------------------------------------------------------------------------- /docs/concurrency-Synchronization.md: -------------------------------------------------------------------------------- 1 | ## 同步(Synchronization) 2 | 3 | 线程间的通信主要是通过共享访问字段以及其字段所引用的对象来实现的。这种形式的通信是非常有效的,但可能导致2种可能的错误:线程干扰(thread interference)和内存一致性错误(memory consistency errors)。同步就是要需要避免这些错误的工具。 4 | 5 | 但是,同步可以引入线程竞争(thread contention),当两个或多个线程试图同时访问相同的资源时,并导致了 Java 运行时执行一个或多个线程更慢,或甚至暂停他们的执行。饥饿(Starvation)和活锁 (livelock) 是线程竞争的表现形式。 6 | 7 | ### 线程干扰 8 | 9 | 描述当多个线程访问共享数据时是错误如何出现。 10 | 11 | 考虑下面的一个简单的类 Counter: 12 | 13 | ```java 14 | public class Counter { 15 | private int c = 0; 16 | 17 | public void increment() { 18 | c++; 19 | } 20 | 21 | public void decrement() { 22 | c--; 23 | } 24 | 25 | public int value() { 26 | return c; 27 | } 28 | } 29 | ``` 30 | 31 | 其中的 increment 方法用来对 c 加1;decrement 方法用来对 c 减 1。然而,有多个线程中都存在对某个 Counter 对象的引用,那么线程间的干扰就可能导致出现我们不想要的结果。 32 | 33 | 线程间的干扰出现在多个线程对同一个数据进行多个操作的时候,也就是出现了“交错”。这就意味着操作是由多个步骤构成的,而此时,在这多个步骤的执行上出现了叠加。 34 | 35 | Counter类对象的操作貌似不可能出现这种“交错(interleave)”,因为其中的两个关于c 的操作都很简单,只有一条语句。然而,即使是一条语句也是会被虚拟机翻译成多个步骤的。在这里,我们不深究虚拟机具体上上面的操作翻译成了什么样的步骤。只需要知道即使简单的 c++ 这样的表达式也是会被翻译成三个步骤的: 36 | 37 | 1. 获取 c 的当前值。 38 | 2. 对其当前值加 1。 39 | 3. 将增加后的值存储到 c 中。 40 | 41 | 表达式 c-- 也是会被按照同样的方式进行翻译,只不过第二步变成了减1,而不是加1。 42 | 43 | 假定线程 A 中调用 increment 方法,线程 B 中调用 decrement 方法,而调用时间基本上相同。如果 c 的初始值为 0,那么这两个操作的“交错”顺序可能如下: 44 | 45 | 1. 线程A:获取 c 的值。 46 | 2. 线程B:获取 c 的值。 47 | 3. 线程A:对获取到的值加1;其结果是1。 48 | 4. 线程B:对获取到的值减1;其结果是-1。 49 | 5. 线程A:将结果存储到 c 中;此时c的值是1。 50 | 6. 线程B:将结果存储到 c 中;此时c的值是-1。 51 | 52 | 这样线程 A 计算的值就丢失了,也就是被线程 B 的值覆盖了。上面的这种“交错”只是其中的一种可能性。在不同的系统环境中,有可能是 B 线程的结果丢失了,或者是根本就不会出现错误。由于这种“交错”是不可预测的,线程间相互干扰造成的 bug 是很难定位和修改的。 53 | 54 | ### 内存一致性错误 55 | 56 | 介绍了通过共享内存出现的不一致的错误。 57 | 58 | 内存一致性错误(Memory consistency errors)发生在不同线程对同一数据产生不同的“看法”。导致内存一致性错误的原因很复杂,超出了本书的描述范围。庆幸的是,程序员并不需要知道出现这些原因的细节。我们需要的是一种可以避免这种错误的方法。 59 | 60 | 避免出现内存一致性错误的关键在于理解 happens-before 关系。这种关系是一种简单的方法,能够确保一条语句对内存的写操作对于其它特定的语句都是可见的。为了理解这点,我们可以考虑如下的示例。假定定义了一个简单的 int 类型的字段并对其进行了初始化: 61 | 62 | int counter = 0; 63 | 64 | 该字段由两个线程共享:A 和 B。假定线程 A 对 counter 进行了自增操作: 65 | 66 | counter++; 67 | 68 | 然后,线程 B 打印 counter 的值: 69 | 70 | System.out.println(counter); 71 | 72 | 如果以上两条语句是在同一个线程中执行的,那么输出的结果自然是1。但是如果这两条语句是在两个不同的线程中,那么输出的结构有可能是0。这是因为没有保证线程 A 对 counter 的修改对线程 B 来说是可见的。除非程序员在这两条语句间建立了一定的 happens-before 关系。 73 | 74 | 我们可以采取多种方式建立这种 happens-before 关系。使用同步就是其中之一,这点我们将会在下面的小节中看到。 75 | 76 | 到目前为止,我们已经看到了两种建立这种 happens-before 的方式: 77 | 78 | * 当一条语句中调用了 Thread.start 方法,那么每一条和该语句已经建立了 happens-before 的语句都和新线程中的每一条语句有着这种 happens-before。引入并创建这个新线程的代码产生的结果对该新线程来说都是可见的。 79 | * 当一个线程终止了并导致另外的线程中调用 Thread.join 的语句返回,那么此时这个终止了的线程中执行了的所有语句都与随后的 join 语句随后的所有语句建立了这种 happens-before 。也就是说终止了的线程中的代码效果对调用 join 方法的线程来说是可见。 80 | 81 | 关于哪些操作可以建立这种 happens-before,更多的信息请参阅“[java.util.concurrent 包的概要说明](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility)”。 82 | 83 | ### 同步方法 84 | 85 | 描述了一个简单的做法,可以有效防止线程干扰和内存一致性错误。 86 | 87 | Java 编程语言中提供了两种基本的同步用语:同步方法(synchronized methods)和同步语句(synchronized statements)。同步语句相对而言更为复杂一些,我们将在下一小节中进行描述。本节重点讨论同步方法。 88 | 89 | 我们只需要在声明方法的时候增加关键字 synchronized 即可: 90 | 91 | ```java 92 | public class SynchronizedCounter { 93 | private int c = 0; 94 | 95 | public synchronized void increment() { 96 | c++; 97 | } 98 | 99 | public synchronized void decrement() { 100 | c--; 101 | } 102 | 103 | public synchronized int value() { 104 | return c; 105 | } 106 | } 107 | ``` 108 | 109 | 如果 count 是 SynchronizedCounter 类的实例,设置其方法为同步方法将有两个效果: 110 | 111 | * 首先,不可能出现对同一对象的同步方法的两个调用的“交错”。当一个线程在执行一个对象的同步方式的时候,其他所有的调用该对象的同步方法的线程都会被挂起,直到第一个线程对该对象操作完毕。 112 | * 其次,当一个同步方法退出时,会自动与该对象的同步方法的后续调用建立 happens-before 关系。这就确保了对该对象的修改对其他线程是可见的。 113 | 114 | 注意:构造函数不能是 synchronized ——在构造函数前使用 synchronized 关键字将导致语义错误。同步构造函数是没有意义的。这是因为只有创建该对象的线程才能调用其构造函数。 115 | 116 | 警告:在创建多个线程共享的对象时,要特别小心对该对象的引用不能过早地“泄露”。例如,假定我们想要维护一个保存类的所有实例的列表 instances。我们可能会在构造函数中这样写到: 117 | 118 | instances.add(this); 119 | 120 | 但是,其他线程可会在该对象的构造完成之前就访问该对象。 121 | 122 | 同步方法是一种简单的可以避免线程相互干扰和内存一致性错误的策略:如果一个对象对多个线程都是可见的,那么所有对该对象的变量的读写都应该是通过同步方法完成的(一个例外就是 final 字段,他在对象创建完成后是不能被修改的,因此,在对象创建完毕后,可以通过非同步的方法对其进行安全的读取)。这种策略是有效的,但是可能导致“活跃度(liveness)”问题。这点我们会在本课程的后面进行描述。 123 | 124 | 125 | ### 内部锁和同步 126 | 127 | 描述了一个更通用的同步方法,并介绍了同步是如何基于内部锁的。 128 | 129 | 同步是构建在被称为“内部锁(intrinsic lock)”或者是“监视锁(monitor lock)”的内部实体上的。(在 API 中通常被称为是“监视器(monitor)”。)内部锁在两个方面都扮演着重要的角色:保证对对象状态访问的排他性和建立也对象可见性相关的重要的“ happens-before。 130 | 131 | 每一个对象都有一个与之相关联动的内部锁。按照传统的做法,当一个线程需要对一个对象的字段进行排他性访问并保持访问的一致性时,他必须在访问前先获取该对象的内部锁,然后才能访问之,最后释放该内部锁。在线程获取对象的内部锁到释放对象的内部锁的这段时间,我们说该线程拥有该对象的内部锁。只要有一个线程已经拥有了一个内部锁,其他线程就不能再拥有该锁了。其他线程将会在试图获取该锁的时候被阻塞了。 132 | 133 | 当一个线程释放了一个内部锁,那么就会建立起该动作和后续获取该锁之间的 happens-before 关系。 134 | 135 | #### 同步方法中的锁 136 | 137 | 当一个线程调用一个同步方法的时候,他就自动地获得了该方法所属对象的内部锁,并在方法返回的时候释放该锁。即使是由于出现了没有被捕获的异常而导致方法返回,该锁也会被释放。 138 | 139 | 我们可能会感到疑惑:当调用一个静态的同步方法的时候会怎样了,静态方法是和类相关的,而不是和对象相关的。在这种情况下,线程获取的是该类的类对象的内部锁。这样对于静态字段的方法是通过一个和类的实例的锁相区分的另外的锁来进行的。 140 | 141 | #### 同步语句 142 | 143 | 另外一种创建同步代码的方式就是使用同步语句。和同步方法不同,使用同步语句是必须指明是要使用哪个对象的内部锁: 144 | 145 | public void addName(String name) { 146 | synchronized(this) { 147 | lastName = name; 148 | nameCount++; 149 | } 150 | nameList.add(name); 151 | } 152 | 153 | 在上面的示例中,方法 addName 需要对 lastName 和 nameCount 的修改进行同步,还要避免同步调用其他对象的方法(在同步代码段中调用其他对象的方法可能导致“活跃度(Liveness)”中描述的问题)。如果没有使用同步语句,那么将不得不使用一个单独的,未同步的方法来完成对 nameList.add 的调用。 154 | 155 | 在改善并发性时,巧妙地使用同步语句能起到很大的帮助作用。例如,我们假定类 MsLunch 有两个实例字段,c1 和 c2,这两个变量绝不会一起使用。所有对这两个变量的更新都需要进行同步。但是没有理由阻止对 c1 的更新和对 c2 的更新出现交错——这样做会创建不必要的阻塞,进而降低并发性。此时,我们没有使用同步方法或者使用和this 相关的锁,而是创建了两个单独的对象来提供锁。 156 | 157 | ``` 158 | public class MsLunch { 159 | private long c1 = 0; 160 | private long c2 = 0; 161 | private Object lock1 = new Object(); 162 | private Object lock2 = new Object(); 163 | 164 | public void inc1() { 165 | synchronized(lock1) { 166 | c1++; 167 | } 168 | } 169 | 170 | public void inc2() { 171 | synchronized(lock2) { 172 | c2++; 173 | } 174 | } 175 | } 176 | ``` 177 | 178 | 采用这种方式时需要特别的小心。我们必须绝对确保相关字段的访问交错是完全安全的。 179 | 180 | #### 重入同步(Reentrant Synchronization) 181 | 182 | 回忆前面提到的:线程不能获取已经被别的线程获取的锁。但是线程可以获取自身已经拥有的锁。允许一个线程能重复获得同一个锁就称为重入同步(reentrant synchronization)。它是这样的一种情况:在同步代码中直接或者间接地调用了还有同步代码的方法,两个同步代码段中使用的是同一个锁。如果没有重入同步,在编写同步代码时需要额外的小心,以避免线程将自己阻塞。 183 | 184 | 185 | ### 原子访问 186 | 187 | 介绍了不会被其他线程干扰的做法的总体思路。 188 | 189 | 在编程中,原子性动作就是指一次性有效完成的动作。原子性动作是不能在中间停止的:要么一次性完全执行完毕,要么就不执行。在动作没有执行完毕之前,是不会产生可见结果的。 190 | 191 | 通过前面的示例,我们已经发现了诸如 c++ 这样的自增表达式并不属于原子操作。即使是非常简单的表达式也包含了复杂的动作,这些动作可以被解释成许多别的动作。然而,的确存在一些原子操作的: 192 | 193 | * 对几乎所有的原生数据类型变量(除了 long 和 double)的读写以及引用变量的读写都是原子的。 194 | * 对所有声明为 volatile 的变量的读写都是原子的,包括 long 和 double 类型。 195 | 196 | 原子性动作是不会出现交错的,因此,使用这些原子性动作时不用考虑线程间的干扰。然而,这并不意味着可以移除对原子操作的同步。因为内存一致性错误还是有可能出现的。使用 volatile 变量可以减少内存一致性错误的风险,因为任何对 volatile 变 量的写操作都和后续对该变量的读操作建立了 happens-before 关系。这就意味着对 volatile 类型变量的修改对于别的线程来说是可见的。更重要的是,这意味着当一个线程读取一个 volatile 类型的变量时,他看到的不仅仅是对该变量的最后一次修改,还看到了导致这种修改的代码带来的其他影响。 197 | 198 | 使用简单的原子变量访问比通过同步代码来访问变量更高效,但是需要程序员的更多细心考虑,以避免内存一致性错误。这种额外的付出是否值得完全取决于应用程序的大小和复杂度。 199 | 200 | -------------------------------------------------------------------------------- /docs/concurrency.md: -------------------------------------------------------------------------------- 1 | # 并发 2 | 3 | 计算机用户想当然地认为他们的系统在一个时间可以做多件事。他们认为,他们可以工作在一个字处理器,而其他应用程序在下载文件,管理打印队列和音频流。即使是单一的应用程序通常也是被期望在一个时间来做多件事。例如,音频流应用程序必须同时读取数字音频,解压,管理播放,并更新显示。即使字处理器应该随时准备响应键盘和鼠标事件,不管多么繁忙,它总是能格式化文本或更新显示。可以做这样的事情的软件称为并发软件(concurrent software)。 4 | 5 | 在 Java 平台是完全支持并发编程。自从 5.0 版本以来,这个平台还包括高级并发 API, 主要集中在 java.util.concurrent 包。 6 | 7 | 8 | ## 源码 9 | 10 | 本章例子的源码,可以在 中 com.waylau.essentialjava.concurrency 包下找到。 -------------------------------------------------------------------------------- /docs/exceptions-advantages.md: -------------------------------------------------------------------------------- 1 | # 使用异常带来的优势 2 | 3 | 现在你知道什么是异常,以及如何使用它们,现在是时候了解在程序中使用异常的优点。 4 | 5 | ## 优点1:将错误处理代码与“常规”代码分离 6 | 7 | 异常提供了一种方法来分离当一个程序的主逻辑发生异常情况时应该做什么的细节。 在传统的编程中,错误检测、报告和处理常常导致混淆意大利面条代码(spaghetti code)。 例如,考虑这里的伪代码方法将整个文件读入内存。 8 | 9 | ```java 10 | readFile { 11 | open the file; 12 | determine its size; 13 | allocate that much memory; 14 | read the file into memory; 15 | close the file; 16 | } 17 | ``` 18 | 19 | 乍一看,这个功能看起来很简单,但它忽略了以下所有潜在错误。 20 | 21 | * 如果无法打开文件会发生什么? 22 | * 如果无法确定文件的长度,会发生什么? 23 | * 如果不能分配足够的内存,会发生什么? 24 | * 如果读取失败会发生什么? 25 | * 如果文件无法关闭会怎么样? 26 | 27 | 28 | 为了处理这种情况,readFile函数必须有更多的代码来执行错误检测\报告和处理。 这里是一个示例,来展示该函数可能会是什么样子。 29 | 30 | 31 | ```java 32 | errorCodeType readFile { 33 | initialize errorCode = 0; 34 | 35 | open the file; 36 | if (theFileIsOpen) { 37 | determine the length of the file; 38 | if (gotTheFileLength) { 39 | allocate that much memory; 40 | if (gotEnoughMemory) { 41 | read the file into memory; 42 | if (readFailed) { 43 | errorCode = -1; 44 | } 45 | } else { 46 | errorCode = -2; 47 | } 48 | } else { 49 | errorCode = -3; 50 | } 51 | close the file; 52 | if (theFileDidntClose && errorCode == 0) { 53 | errorCode = -4; 54 | } else { 55 | errorCode = errorCode and -4; 56 | } 57 | } else { 58 | errorCode = -5; 59 | } 60 | return errorCode; 61 | } 62 | ``` 63 | 64 | 这里面会有很多错误检测、报告的细节,使得原来的七行代码被淹没在这杂乱的代码中。 更糟的是,代码的逻辑流也已经丢失,因此很难判断代码是否正确:如果函数无法分配足够的内存,文件是否真的被关闭? 在编写方法三个月后修改方法时,更难以确保代码能够继续正确的操作。 因此,许多程序员通过简单地忽略它来解决这个问题。这样当他们的程序崩溃时,就生成了报告错误。 65 | 66 | 异常使您能够编写代码的主要流程,并处理其他地方的特殊情况。 如果readFile函数使用异常而不是传统的错误管理技术,它将看起来更像下面。 67 | 68 | ```java 69 | readFile { 70 | try { 71 | open the file; 72 | determine its size; 73 | allocate that much memory; 74 | read the file into memory; 75 | close the file; 76 | } catch (fileOpenFailed) { 77 | doSomething; 78 | } catch (sizeDeterminationFailed) { 79 | doSomething; 80 | } catch (memoryAllocationFailed) { 81 | doSomething; 82 | } catch (readFailed) { 83 | doSomething; 84 | } catch (fileCloseFailed) { 85 | doSomething; 86 | } 87 | } 88 | ``` 89 | 90 | 91 | 请注意,异常不会减少你在法执行检测、报告和处理错误方面的工作,但它们可以帮助您更有效地组织工作。 92 | 93 | ## 优点2:将错误沿调用推栈向上传递 94 | 95 | 异常的第二个优点是能够在方法的调用堆栈上将错误向上传递。 假设 readFile 方法是由主程序进行的一系列嵌套方法调用中的第四个方法:method1调用method2,它调用了method3,最后调用readFile。 96 | 97 | ```java 98 | method1 { 99 | call method2; 100 | } 101 | 102 | method2 { 103 | call method3; 104 | } 105 | 106 | method3 { 107 | call readFile; 108 | } 109 | ``` 110 | 111 | 还假设method1是对readFile中可能发生的错误感兴趣的唯一方法。 传统的错误通知技术强制method2和method3将readFile返回的错误代码传递到调用堆栈,直到错误代码最终到达method1 - 对它们感兴趣的唯一方法。 112 | 113 | ```java 114 | method1 { 115 | errorCodeType error; 116 | error = call method2; 117 | if (error) 118 | doErrorProcessing; 119 | else 120 | proceed; 121 | } 122 | 123 | errorCodeType method2 { 124 | errorCodeType error; 125 | error = call method3; 126 | if (error) 127 | return error; 128 | else 129 | proceed; 130 | } 131 | 132 | errorCodeType method3 { 133 | errorCodeType error; 134 | error = call readFile; 135 | if (error) 136 | return error; 137 | else 138 | proceed; 139 | } 140 | ``` 141 | 142 | 回想一下,Java运行时环境通过调用堆栈向后搜索以找到任何对处理特定异常感兴趣的方法。 一个方法可以阻止在其中抛出的任何异常,从而允许一个方法在调用栈上更远的地方来捕获它。 因此,只有关心错误的方法才需要担心检测错误。 143 | 144 | ```java 145 | method1 { 146 | try { 147 | call method2; 148 | } catch (exception e) { 149 | doErrorProcessing; 150 | } 151 | } 152 | 153 | method2 throws exception { 154 | call method3; 155 | } 156 | 157 | method3 throws exception { 158 | call readFile; 159 | } 160 | ``` 161 | 162 | 然而,如伪代码所示,抛弃异常需要中间人方法的一些努力。 任何可以在方法中抛出的已检查异常都必须在其throws子句中指定。 163 | 164 | 165 | 166 | ## 优点3:对错误类型进行分组和区分 167 | 168 | 169 | 因为在程序中抛出的所有异常都是对象,异常的分组或分类是类层次结构的自然结果。 Java平台中一组相关异常类的示例是java.io - IOException中定义的那些异常类及其后代。 IOException是最常见的,表示执行I/O时可能发生的任何类型的错误。 它的后代表示更具体的错误。 例如,FileNotFoundException意味着文件无法在磁盘上找到。 170 | 171 | 一个方法可以编写可以处理非常特定异常的特定处理程序。 FileNotFoundException类没有后代,因此下面的处理程序只能处理一种类型的异常。 172 | 173 | ```java 174 | catch (FileNotFoundException e) { 175 | ... 176 | } 177 | ``` 178 | 179 | 方法可以通过在catch语句中指定任何异常的超类来基于其组或常规类型捕获异常。 例如,为了捕获所有I/O异常,无论其具体类型如何,异常处理程序都会指定一个IOException参数。 180 | 181 | ```java 182 | catch (IOException e) { 183 | ... 184 | } 185 | ``` 186 | 187 | 这个处理程序将能够捕获所有I/O异常,包括FileNotFoundException、EOFException等等。 您可以通过查询传递给异常处理程序的参数来查找有关发生的详细信息。 例如,使用以下命令打印堆栈跟踪。 188 | 189 | ```java 190 | catch (IOException e) { 191 | // Output goes to System.err. 192 | e.printStackTrace(); 193 | // Send trace to stdout. 194 | e.printStackTrace(System.out); 195 | } 196 | ``` 197 | 198 | 199 | 下面例子可以处理所有的异常: 200 | 201 | ```java 202 | // A (too) general exception handler 203 | catch (Exception e) { 204 | ... 205 | } 206 | ``` 207 | 208 | Exception 类接近Throwable类层次结构的顶部。因此,这个处理程序将会捕获除处理程序想要捕获的那些异常之外的许多其他异常。在程序中如果是以这种方式来处理异常,那么你程序一般的做法就是,例如,是打印出一个错误消息给用户,然后退出。 209 | 210 | 在大多数情况下,异常处理程序应该尽可能的具体。原因是处理程序必须做的第一件事是在选择最佳恢复策略之前,首先要确定发生的是什么类型的异常。实际上,如果不捕获特定的错误,处理程序必须适应任何可能性。太过通用的异常处理程序可能会捕获和处理程序员不期望的并且处理程序不想要的异常,从而使代码更容易出错。 211 | 212 | 如上所述,您可以以常规方式创建异常分组来处理异常,也可以使用特定的异常类型来区分异常从而可以以确切的方式来处理异常。 213 | -------------------------------------------------------------------------------- /docs/exceptions-catch-and-handle.md: -------------------------------------------------------------------------------- 1 | # 异常捕获与处理 2 | 3 | 本节介绍如何使用三个异常处理程序组件(try、catch 和 finally)来编写异常处理程序。 然后,介绍了 Java SE 7中引入的 try-with-resources 语句。 try-with-resources 语句特别适合于使用`Closeable`的资源(例如流)的情况。 4 | 5 | 本节的最后一部分将通过一个示例来分析在各种情况下发生的情况。 6 | 7 | 以下示例定义并实现了一个名为ListOfNumbers的类。 构造时,ListOfNumbers 创建一个ArrayList,其中包含10个序列值为0到9的整数元素。ListOfNumbers类还定义了一个名为writeList的方法,该方法将数列表写入一个名为`OutFile.txt`的文本文件中。 此示例使用在`java.io`中定义的输出类,这些类包含在基本I/O中。 8 | 9 | ```java 10 | // Note: This class will not compile yet. 11 | import java.io.*; 12 | import java.util.List; 13 | import java.util.ArrayList; 14 | 15 | public class ListOfNumbers { 16 | 17 | private List list; 18 | private static final int SIZE = 10; 19 | 20 | public ListOfNumbers () { 21 | list = new ArrayList(SIZE); 22 | for (int i = 0; i < SIZE; i++) { 23 | list.add(new Integer(i)); 24 | } 25 | } 26 | 27 | public void writeList() { 28 | // The FileWriter constructor throws IOException, which must be caught. 29 | PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt")); 30 | 31 | for (int i = 0; i < SIZE; i++) { 32 | // The get(int) method throws IndexOutOfBoundsException, which must be caught. 33 | out.println("Value at: " + i + " = " + list.get(i)); 34 | } 35 | out.close(); 36 | } 37 | } 38 | ``` 39 | 40 | 41 | 构造函数 FileWriter 初始化文件上的输出流。如果文件无法打开,构造函数会抛出一个IOException异常。第二个对ArrayList类的get方法的调用,如果其参数的值太小(小于0)或太大(超过ArrayList当前包含的元素数量),它将抛出 IndexOutOfBoundsException。 42 | 43 | 如果尝试编译ListOfNumbers类,则编译器将打印有关FileWriter构造函数抛出的异常的错误消息。但是,它不显示有关get抛出的异常的错误消息。原因是构造函数IOException抛出的异常是一个检查异常,而get方法IndexOutOfBoundsException抛出的异常是未检查的异常。 44 | 45 | 现在,我们已经熟悉ListOfNumbers类,并且知道了其中那些地方可能抛出异常。下一步我们就可以编写异常处理程序来捕获和处理这些异常。 46 | 47 | 48 | ## try块 49 | 50 | 51 | 构造异常处理程序的第一步是封装可能在try块中抛出异常的代码。 一般来说,try块看起来像下面这样: 52 | 53 | ```java 54 | try { 55 | code 56 | } 57 | catch and finally blocks . . . 58 | ``` 59 | 60 | 示例标记 `code` 中的段可以包含一个或多个可能抛出的异常。 61 | 62 | 每行可能抛出异常的代码都可以用单独的一个 try 块,或者多个异常放置在一个 try 块中。 以下示例由于非常简短,所有使用一个try块。 63 | 64 | ```java 65 | private List list; 66 | private static final int SIZE = 10; 67 | 68 | public void writeList() { 69 | PrintWriter out = null; 70 | try { 71 | System.out.println("Entered try statement"); 72 | out = new PrintWriter(new FileWriter("OutFile.txt")); 73 | for (int i = 0; i < SIZE; i++) { 74 | out.println("Value at: " + i + " = " + list.get(i)); 75 | } 76 | } 77 | catch and finally blocks . . . 78 | } 79 | ``` 80 | 81 | 82 | 如果在try块中发生异常,那么该异常由与其相关联的异常处理程序将会进行处理。 要将异常处理程序与try块关联,必须在其后面放置一个catch块。 83 | 84 | ## catch块 85 | 86 | 通过在try块之后直接提供一个或多个catch块,可以将异常处理程序与try块关联。 在try块的结尾和第一个catch块的开始之间没有代码。 87 | 88 | ```java 89 | try { 90 | 91 | } catch (ExceptionType name) { 92 | 93 | } catch (ExceptionType name) { 94 | 95 | } 96 | ``` 97 | 98 | 99 | 每个catch块是一个异常处理程序,处理由其参数指示的异常类型。 参数类型ExceptionType声明了处理程序可以处理的异常类型,并且必须是从Throwable类继承的类的名称。 处理程序可以使用名称引用异常。 100 | 101 | catch块包含了在调用异常处理程序时执行的代码。 当处理程序是调用堆栈中第一个与ExceptionType匹配的异常抛出的类型时,运行时系统将调用异常处理程序。 如果抛出的对象可以合法地分配给异常处理程序的参数,则系统认为它是匹配。 102 | 103 | 以下是writeList方法的两个异常处理程序: 104 | 105 | ```java 106 | try { 107 | 108 | } catch (IndexOutOfBoundsException e) { 109 | System.err.println("IndexOutOfBoundsException: " + e.getMessage()); 110 | } catch (IOException e) { 111 | System.err.println("Caught IOException: " + e.getMessage()); 112 | } 113 | ``` 114 | 115 | 异常处理程序可以做的不仅仅是打印错误消息或停止程序。 它们可以执行错误恢复,提示用户做出决定,或者使用异常链将错误传播到更高级别的处理程序,如“异常链”部分所述。 116 | 117 | ### 在一个异常处理程序中处理多个类型的异常 118 | 119 | 120 | 在Java SE 7和更高版本中,单个catch块可以处理多种类型的异常。 此功能可以减少代码重复,并减少定义过于宽泛的异常。 121 | 122 | 在catch子句中,多个类型的异常使用竖线(|)分隔每个异常类型: 123 | 124 | 125 | ```java 126 | catch (IOException|SQLException ex) { 127 | logger.log(ex); 128 | throw ex; 129 | } 130 | ``` 131 | 132 | 注意:如果catch块处理多个异常类型,则catch参数将隐式为final。 在本示例中,catch参数ex是final,因此您不能在catch块中为其分配任何值。 133 | 134 | ## finally 块 135 | 136 | finally块总是在try块退出时执行。这确保即使发生意外异常也会执行finally块。但 finally 的用处不仅仅是异常处理 - 它允许程序员避免清理代码意外绕过 return、continue 或 break 。将清理代码放在finally块中总是一个好的做法,即使没有预期的异常。 137 | 138 | 注意:如果在执行try或catch代码时JVM退出,则finally块可能无法执行。同样,如果执行try或catch代码的线程被中断或杀死,则finally块可能不执行,即使应用程序作为一个整体继续。 139 | 140 | 141 | writeList方法的try块打开一个PrintWriter。程序应该在退出writeList方法之前关闭该流。这提出了一个有点复杂的问题,因为writeList的try块可以以三种方式中的一种退出。 142 | 143 | * new FileWriter语句失败并抛出IOException。 144 | * list.get(i)语句失败,并抛出IndexOutOfBoundsException。 145 | * 一切成功,try块正常退出。 146 | 147 | 运行时系统总是执行finally块内的语句,而不管try块内发生了什么。所以它是执行清理的完美场所。 148 | 149 | 下面的finally块为writeList方法清理,然后关闭PrintWriter。 150 | 151 | ```java 152 | finally { 153 | if (out != null) { 154 | System.out.println("Closing PrintWriter"); 155 | out.close(); 156 | } else { 157 | System.out.println("PrintWriter not open"); 158 | } 159 | } 160 | ``` 161 | 162 | 重要:finally块是防止资源泄漏的关键工具。 当关闭文件或恢复资源时,将代码放在finally块中,以确保资源始终恢复。 163 | 164 | 考虑在这些情况下使用try-with-resources语句,当不再需要时自动释放系统资源。 165 | 166 | ### 源码 167 | 168 | 本章例子的源码,可以在 中 `com.waylau.essentialjava.exception` 包下找到。 169 | 170 | 171 | ## try-with-resources 语句 172 | 173 | try-with-resources 是 JDK 7 中一个新的异常处理机制,它能够很容易地关闭在 try-catch 语句块中使用的资源。所谓的资源(resource)是指在程序完成后,必须关闭的对象。try-with-resources 语句确保了每个资源在语句结束时关闭。所有实现了 [java.lang.AutoCloseable](http://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html) 接口(其中,它包括实现了 [java.io.Closeable](http://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) 的所有对象),可以使用作为资源。 174 | 175 | 例如,我们自定义一个资源类 176 | 177 | ```java 178 | public class Demo { 179 | public static void main(String[] args) { 180 | try(Resource res = new Resource()) { 181 | res.doSome(); 182 | } catch(Exception ex) { 183 | ex.printStackTrace(); 184 | } 185 | } 186 | } 187 | 188 | class Resource implements AutoCloseable { 189 | void doSome() { 190 | System.out.println("do something"); 191 | } 192 | @Override 193 | public void close() throws Exception { 194 | System.out.println("resource is closed"); 195 | } 196 | } 197 | ``` 198 | 199 | 执行输出如下: 200 | 201 | do something 202 | resource is closed 203 | 204 | 可以看到,资源终止被自动关闭了。 205 | 206 | 再来看一个例子,是同时关闭多个资源的情况: 207 | 208 | ```java 209 | public class Main2 { 210 | public static void main(String[] args) { 211 | try(ResourceSome some = new ResourceSome(); 212 | ResourceOther other = new ResourceOther()) { 213 | some.doSome(); 214 | other.doOther(); 215 | } catch(Exception ex) { 216 | ex.printStackTrace(); 217 | } 218 | } 219 | } 220 | 221 | class ResourceSome implements AutoCloseable { 222 | void doSome() { 223 | System.out.println("do something"); 224 | } 225 | @Override 226 | public void close() throws Exception { 227 | System.out.println("some resource is closed"); 228 | } 229 | } 230 | 231 | class ResourceOther implements AutoCloseable { 232 | void doOther() { 233 | System.out.println("do other things"); 234 | } 235 | @Override 236 | public void close() throws Exception { 237 | System.out.println("other resource is closed"); 238 | } 239 | } 240 | ``` 241 | 242 | 最终输出为: 243 | 244 | do something 245 | do other things 246 | other resource is closed 247 | some resource is closed 248 | 249 | 在 try 语句中越是最后使用的资源,越是最早被关闭。 250 | 251 | ### try-with-resources 在 JDK 9 中的改进 252 | 253 | 作为 [Milling Project Coin](http://openjdk.java.net/jeps/213) 的一部分, try-with-resources 声明在 JDK 9 已得到改进。如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。 254 | 255 | 例如,给定资源的声明 256 | 257 | // A final resource 258 | final Resource resource1 = new Resource("resource1"); 259 | // An effectively final resource 260 | Resource resource2 = new Resource("resource2"); 261 | 262 | 老方法编写代码来管理这些资源是类似的: 263 | 264 | // Original try-with-resources statement from JDK 7 or 8 265 | try (Resource r1 = resource1; 266 | Resource r2 = resource2) { 267 | // Use of resource1 and resource 2 through r1 and r2. 268 | } 269 | 270 | 而新方法可以是 271 | 272 | // New and improved try-with-resources statement in JDK 9 273 | try (resource1; 274 | resource2) { 275 | // Use of resource1 and resource 2. 276 | } 277 | 278 | 看上去简洁很多吧。对 Java 未来的发展信心满满。 279 | 280 | 愿意尝试 JDK 9 这种新语言特性的可以下载使用 [JDK 9 快照](https://jdk9.java.net/download/)。Enjoy! 281 | 282 | ### 源码 283 | 284 | 本章例子的源码,可以在 中 `com.waylau.essentialjava.exception.trywithresources` 包下找到。 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /docs/exceptions-catch-or-specify.md: -------------------------------------------------------------------------------- 1 | # 捕获或者声明(Catch or Specify Requirement) 2 | 3 | 有效的Java编程语言代码必须满足异常的捕获或者声明(Catch or Specify Requirement) 。 可能抛出异常的代码必须是下列两种处理方式之一: 4 | 5 | * 使用 try 捕获异常。try 必须提供处理器来处理异常,详见“[异常捕获和处理](exceptions-catch-and-handle.md)”; 6 | * 通过在方法签名中利用 throws 关键字,声明异常可以将异常抛出,将异常传递给调用者,自己可以不用处理。详见“[通过方法声明异常抛出](exceptions-specify-exceptions-thrown.md)”。 7 | 8 | 所编写的代码如果不满足捕获或者声明异常将不会编译成功。 9 | 10 | 并非所有的异常都满足捕获或者声明异常 的约束。 为了理解为什么,我们需要看看三个基本类别的例外,其中只有一个符合要求。 11 | 12 | ## 三个不同的异常 13 | 14 | ### 1. 已检查异常(checked exception) 15 | 16 | 已检查异常是一个良好的应用程序应该预期和恢复的特殊条件。例如,假设应用程序提示用户输入文件名,然后通过将名称传递给`java.io.FileReader`的构造函数来打开该文件。通常,用户提供现有可读文件的名称,这样`FileReader`对象才能构造成功,应用程序才能执行正常进行。但有时用户提供不存在的文件的名称,并且构造函数抛出`java.io.FileNotFoundException`。一个编写良好的程序将捕获此异常并通知用户该错误,并可能地提示用户需要修正文件名。 17 | 18 | 已检查异常受限于捕获或者声明异常。除了 Error、RuntimeException 和它们的子类以外,所有异常都是已检查异常。 19 | 20 | ### 2. 错误(error) 21 | 22 | 错误是应用程序外部的特殊条件,是应用程序通常无法预期或恢复的。例如,假设应用程序成功打开文件以进行输入,但由于硬件或系统故障而无法读取该文件。未成功读取将抛出`java.io.IOError`。应用程序可能选择捕获此异常,以便将该问题通知给用户 ,当然程序也可以选择打印堆栈跟踪并退出。 23 | 24 | 错误不受捕获或者声明异常的限制。错误是由 Error 及其子类指示的异常。 25 | 26 | ### 3. 运行时异常(runtime exception) 27 | 28 | 运行时异常是应用程序内部的特殊情况,应用程序通常无法预期或恢复。这些通常表示编程错误,例如逻辑错误或API的不当使用。例如,考虑前面描述的将文件名传递给`FileReader`的构造函数的应用程序。如果一个逻辑错误导致一个null传递给构造函数,构造函数将抛出`NullPointerException`。应用程序可以捕获此异常,但也可能更有意义,以消除导致异常发生的错误。 29 | 30 | 31 | 运行时异常不受捕获或者声明异常的限制。运行时异常是由 RuntimeException 及其子类指示的异常。 32 | 33 | 34 | 错误和运行时异常统称为未检查异常(unchecked exceptions)。 35 | 36 | ## 绕过捕获或者声明异常 37 | 38 | 一些程序员认为不受捕获或者声明异常是异常机制的严重缺陷,并试图通过使用未检查的异常代替已检查异常来绕过它。 一般来说,这是不推荐。 “[未检查的异常](exceptions-unchecked-exception.md)”部分讨论何时使用未检查异常是恰当的。 -------------------------------------------------------------------------------- /docs/exceptions-chained-exceptions.md: -------------------------------------------------------------------------------- 1 | # 异常链 2 | 3 | 应用程序通常会通过抛出另一个异常来响应异常。 实际上,第一个异常引起第二个异常。 它可以是非常有助于用户知道什么时候一个异常导致另一个异常。 “异常链(Chained Exceptions)”帮助程序员做到这一点。 4 | 5 | 以下是Throwable中支持异常链的方法和构造函数。 6 | 7 | ```java 8 | Throwable getCause() 9 | Throwable initCause(Throwable) 10 | Throwable(String, Throwable) 11 | Throwable(Throwable) 12 | ``` 13 | 14 | 15 | 16 | initCause和Throwable构造函数的Throwable参数是导致当前异常的异常。 getCause返回导致当前异常的异常,initCause设置当前异常的原因。 17 | 18 | 以下示例显示如何使用异常链。 19 | 20 | ```java 21 | try { 22 | 23 | } catch (IOException e) { 24 | throw new SampleException("Other IOException", e); 25 | } 26 | ``` 27 | 28 | 29 | 在此示例中,当捕获到IOException时,将创建一个新的SampleException异常,并附加原始的异常原因,并将异常链抛出到下一个更高级别的异常处理程序。 30 | 31 | ## 访问堆栈跟踪信息 32 | 33 | 现在让我们假设更高级别的异常处理程序想要以自己的格式转储堆栈跟踪。 34 | 35 | 定义:堆栈跟踪(stack trace)提供有关当前线程的执行历史的信息,并列出在异常发生时调用的类和方法的名称。 堆栈跟踪是一个有用的调试工具,通常在抛出异常时会利用它。 36 | 37 | 以下代码显示了如何在异常对象上调用getStackTrace方法。 38 | 39 | ```java 40 | catch (Exception cause) { 41 | StackTraceElement elements[] = cause.getStackTrace(); 42 | for (int i = 0, n = elements.length; i < n; i++) { 43 | System.err.println(elements[i].getFileName() 44 | + ":" + elements[i].getLineNumber() 45 | + ">> " 46 | + elements[i].getMethodName() + "()"); 47 | } 48 | } 49 | ``` 50 | 51 | ## 日志 API 52 | 53 | 54 | 如果要记录catch块中所发生异常,最好不要手动解析堆栈跟踪并将输出发送到 System.err(),而是使用[java.util.logging](https://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html)包中的日志记录工具将输出发送到文件。 55 | 56 | 57 | ```java 58 | try { 59 | Handler handler = new FileHandler("OutFile.log"); 60 | Logger.getLogger("").addHandler(handler); 61 | 62 | } catch (IOException e) { 63 | Logger logger = Logger.getLogger("package.name"); 64 | StackTraceElement elements[] = e.getStackTrace(); 65 | for (int i = 0, n = elements.length; i < n; i++) { 66 | logger.log(Level.WARNING, elements[i].getMethodName()); 67 | } 68 | } 69 | ``` 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /docs/exceptions-create-exception-class.md: -------------------------------------------------------------------------------- 1 | # 创建异常类 2 | 3 | 当面对选择抛出异常的类型时,您可以使用由别人编写的异常 - Java平台提供了许多可以使用的异常类 - 或者您可以编写自己的异常类。 如果您对任何以下问题回答“是”,您应该编写自己的异常类;否则,你可以使用别人的。 4 | 5 | * 你需要一个Java平台中没有表示的异常类型吗? 6 | * 如果用户能够区分你的异常与由其他供应商编写的类抛出的异常吗? 7 | * 你的代码是否抛出不止一个相关的异常? 8 | * 如果您使用他人的例外,用户是否可以访问这些异常? 一个类似的问题是你的包是独立只提供自己使用吗? 9 | 10 | 11 | ## 一个例子 12 | 13 | 假设你正在写一个链表类。该类支持以下方法: 14 | 15 | * objectAt(int n) - 返回列表中第n个位置的对象。如果参数小于0或大于当前列表中的对象数,则抛出异常。 16 | * firstObject() - 返回列表中的第一个对象。如果列表不包含对象,则抛出异常。 17 | * indexOf(Object o) - 搜索指定对象的列表,并返回其在列表中的位置。如果传入方法的对象不在列表中,则抛出异常。 18 | 19 | 链表类可以抛出多个异常,使用一个异常处理程序捕获链表所抛出的所有异常是很方便的。此外,如果您计划在包中分发链表,所有相关代码都应打包在一起。因此,链表应该提供自己的一组异常类。 20 | 21 | 下图说明了链表抛出的异常的一个可能的类层次结构。 22 | 23 | ![](../images/exception/exceptions-hierarchy.gif) 24 | 25 | 26 | ## 选择超类 27 | 28 | 任何 Exception 子类都可以用作 LinkedListException 的父类。 然而,但这些子类有些专用的,有些又与 LinkedListException 完全无关。 因此,LinkedListException的父类应该是Exception。 29 | 30 | 你编写的大多数applet和应用程序都会抛出 Exception 对象。 Error 通常用于系统中严重的硬错误,例如阻止JVM运行的错误。 31 | 32 | 注意:对于可读代码,最好将字符串Exception附加到从异常类继承(直接或间接)的所有类的名称。 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/exceptions-specify-exceptions-thrown.md: -------------------------------------------------------------------------------- 1 | # 通过方法声明异常抛出 2 | 3 | 上一节展示了如何为ListOfNumbers类中的writeList方法编写异常处理程序。 有时,它适合代码捕获可能发生在其中的异常。 但在其他情况下,最好让一个方法进一步推给上层来调用堆栈处理异常。 例如,如果您将ListOfNumbers类提供为类包的一部分,则可能无法预期包的所有用户的需求。 在这种情况下,最好不要捕获异常,并允许一个方法进一步推给上层来调用堆栈来处理它。 4 | 5 | 如果writeList方法没有捕获其中可能发生的已检查异常,则writeList方法必须指定它可以抛出这些异常。 让我们修改原始的writeList方法来指定它可以抛出的异常,而不是捕捉它们。 请注意,下面是不能编译的writeList方法的原始版本。 6 | 7 | 8 | ``` 9 | public void writeList() { 10 | PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt")); 11 | for (int i = 0; i < SIZE; i++) { 12 | out.println("Value at: " + i + " = " + list.get(i)); 13 | } 14 | out.close(); 15 | } 16 | ``` 17 | 18 | 19 | 要指定writeList可以抛出两个异常,请为writeList方法的方法声明添加一个throws子句。 throws子句包含throws关键字,后面是由该方法抛出的所有异常的逗号分隔列表。 该子句在方法名和参数列表之后,在定义方法范围的大括号之前。这里是一个例子。 20 | 21 | ``` 22 | public void writeList() throws IOException, IndexOutOfBoundsException { 23 | ``` 24 | 25 | 记住 IndexOutOfBoundsException是未检查异常(unchecked exception),包括它在throws子句中不是强制性的。 你可以写成下面这样 26 | 27 | ``` 28 | public void writeList() throws IOException { 29 | ``` -------------------------------------------------------------------------------- /docs/exceptions-throw.md: -------------------------------------------------------------------------------- 1 | # 如何抛出异常 2 | 3 | 在你可以捕获异常之前,一些代码必须抛出一个异常。任何代码都可能会抛出异常:您的代码,来自其他人编写的包(例如Java平台附带的包)或Java运行时环境的代码。无论是什么引发的异常,它总是通过 throw 语句抛出。 4 | 5 | 您可能已经注意到,Java平台提供了许多异常类。所有类都是Throwable类的后代,并且都允许程序区分在程序执行期间可能发生的各种类型的异常。 6 | 7 | 您还可以创建自己的异常类来表示在您编写的类中可能发生的问题。事实上,如果您是包开发人员,您可能必须创建自己的一组异常类,以允许用户区分包中可能发生的错误与Java平台或其他包中发生的错误。 8 | 9 | 您还可以创建异常链。有关更多信息,请参阅“异常链”部分。 10 | 11 | ## throw语句 12 | 13 | 所有方法都使用throw语句抛出异常。 throw语句需要一个参数:throwable 对象。 Throwable 对象是Throwable类的任何子类的实例。 这里是一个throw 语句的例子。 14 | 15 | ```java 16 | throw someThrowableObject; 17 | ``` 18 | 19 | 让我们来看一下上下文中的throw语句。 以下pop方法取自实现公共堆栈对象的类。 该方法从堆栈中删除顶层元素并返回对象。 20 | 21 | ```java 22 | public Object pop() { 23 | Object obj; 24 | 25 | if (size == 0) { 26 | throw new EmptyStackException(); 27 | } 28 | 29 | obj = objectAt(size - 1); 30 | setObjectAt(size - 1, null); 31 | size--; 32 | return obj; 33 | } 34 | ``` 35 | 36 | pop 方法将会检查栈中的元素。如果栈是空的(它的size等于0),则pop实例化一个 EmptyStackException对象(java.util的成员)并抛出它。 本章中的“创建异常类”部分介绍如何创建自己的异常类。 现在,所有你需要记住的是,你可以只抛出继承自java.lang.Throwable类的对象。 37 | 38 | 注意,pop方法的声明不包含throws子句。 EmptyStackException不是已检查异常,因此不需要pop来声明它可能发生。 39 | 40 | ### Throwable类及其子类 41 | 42 | 继承自Throwable类的对象包括直接后代(直接从Throwable类继承的对象)和间接后代(从Throwable类的子代或孙代继承的对象)。 下图说明了Throwable类及其最重要的子类的类层次结构。 正如你所看到的,Throwable有两个直接的后代:Error和Exception。 43 | 44 | 45 | ![](../images/exception/exceptions-throwable.gif) 46 | 47 | 48 | ### Error 类 49 | 50 | 当Java虚拟机中发生动态链接故障或其他硬故障时,虚拟机会抛出 Error。简单的程序通常不捕获或抛出Error。 51 | 52 | ### Exception 类 53 | 54 | 大多数程序抛出和捕获从 Exception 类派生的对象。Exception 表示发生了问题,但它不是严重的系统问题。你编写的大多数程序将抛出并捕获Exception而不是 Error。 55 | 56 | Java平台定义了 Exception 类的许多后代。这些后代表示可能发生的各种类型的异常。例如,IllegalAccessException表示找不到特定方法,NegativeArraySizeException表示程序尝试创建一个负大小的数组。 57 | 58 | 一个 Exception 子类RuntimeException保留用于指示不正确使用API​​的异常。运行时异常的一个示例是NullPointerException,当方法尝试通过空引用访问对象的成员时,会发生此异常。“未检查异常”章节讨论了为什么大多数应用程序不应该抛出运行时异常或RuntimeException的子类。 -------------------------------------------------------------------------------- /docs/exceptions-unchecked-exception.md: -------------------------------------------------------------------------------- 1 | # 未检查异常 2 | 3 | 因为Java编程语言不需要捕获方法或声明未检查异常(包括 RuntimeException、Error及其子类),程序员可能会试图编写只抛出未检查异常的代码,或使所有异常子类继承自RuntimeException。这两个快捷方式都允许程序员编写代码,而不必担心编译器错误,也不用担心声明或捕获任何异常。虽然这对于程序员似乎很方便,但它避开了捕获或者声明异常的需求,并且可能会导致其他人在使用您的类而产生问题。 4 | 5 | 为什么设计人员决定强制一个方法来指定所有可以抛出的未捕获的已检查异常?任何可以由方法抛出的 Exception 都是方法的公共编程接口的一部分。调用方法的人必须知道一个方法可以抛出的异常,以便他们可以决定如何处理它们。这些异常是该方法的编程接口的一部分,作为它的参数和 return 值。 6 | 7 | 下一个问题可能是:“既然一个方法的API已经做好了很好的记录,包括它可以抛出的异常,为什么不指定运行时异常?”运行时异常展示的是编程问题的结果,因此,API用户可能会用不合理方式来处理它们。这样就有可能产生问题,包括算术异常,例如除以零;指针异常,例如试图通过空引用访问对象;索引异常,例如尝试通过太大或太小的索引访问数组元素。 8 | 9 | 运行时异常可能发生在程序中的任何地方,在典型的程序中它们可以非常多。必须在每个方法声明中添加运行时异常则会降低程序的清晰度。因此,编译器不需要捕获或声明运行时异常(尽管可以是可以做到)。 10 | 11 | 一种情况是,通常的做法是当用户调用一个方法不正确时,抛出一个RuntimeException。例如,一个方法可以检查其中一个参数是否不正确为null。如果参数为null,那么该方法可能会抛出NullPointerException异常,这是一个未检查异常。 12 | 13 | 一般来说,不要抛出一个RuntimeException或创建一个RuntimeException的子类,这样你就不会被声明哪些方法可以抛出的异常所困扰。 14 | 15 | 一个底线原则是:如果客户端可以合理地从期望异常中恢复,那么使其成为一个已检查异常。如果客户端无法从异常中恢复,请将其设置为未检查异常。 -------------------------------------------------------------------------------- /docs/exceptions.md: -------------------------------------------------------------------------------- 1 | # 异常 2 | 3 | 在Java语言中,是使用“异常(exception)”来处理错误及其他异常事件。术语“异常”是短语“异常事件(exceptional event)”的缩写。 4 | 5 | **异常**是在程序执行期间发生的事件,它会中断程序指令的正常流程。 6 | 7 | 8 | 当在方法中发生错误时,该方法创建一个对象并将其移交给运行时系统。 该对象称为“异常对象(exception object)”,包含有关错误的信息,包括错误发生时其类型和程序的状态。 创建异常对象并将其移交给运行时系统,这个过程被称为“抛出异常(throwing an exception)”。 9 | 10 | 在方法抛出异常后,运行时系统会尝试寻找一些方式来处理它。 这个方法列表被叫做“调用堆栈(call stack)”,调用方式如下图所示(参见下图)。 11 | 12 | ![](../images/exception/exceptions-callstack.gif) 13 | 14 | 15 | 运行时系统搜寻包含能够处理异常的代码块的方法所请求的堆栈。这个代码块叫做“异常处理器( exception handler)”,搜寻首先从发生的方法开始,然后依次按着调用方法的倒序检索调用堆栈。当找到一个相应的处理器时,运行时系统就把异常传递给这个处理器。一个异常处理器要适当地考虑抛出的异常对象的类型与异常处理器所处理的异常的类型是否匹配。 16 | 17 | 当异常处理器被选中时,称为“捕获异常(catch the exception)”。异常被捕获以后,异常处理器关闭。如果运行时系统搜寻了这个方法的所有调用堆栈,而没有找到相应的异常处理器,如下图所示,运行进系统将终止执行。 18 | 19 | ![](../images/exception/exceptions-errorOccurs.gif) 20 | 21 | 22 | 使用异常来管理错误比传统的错误管理技术有一些优势。见“[使用异常带来的优势](exceptions-advantages.md)”一节。 -------------------------------------------------------------------------------- /docs/expressions.md: -------------------------------------------------------------------------------- 1 | # 表达式、语句和块 2 | 3 | 运算符用于计算构建成了表达式(expressions),而表达式是语句(statements)的核心组成,而语句是组织形式为块(blocks)。 4 | 5 | ## 表达式 6 | 7 | 表达式是由变量、运算符以及方法调用所构成的结构,如下: 8 | 9 | ```java 10 | int cadence = 0; 11 | anArray[0] = 100; 12 | System.out.println("Element 1 at index 0: " + anArray[0]); 13 | 14 | int result = 1 + 2; // result is now 3 15 | if (value1 == value2) 16 | System.out.println("value1 == value2"); 17 | ``` 18 | 19 | 表达式返回的数据类型取决于表达式中的元素。表达式`cadence = 0`返回一个int,因为赋值运算符将返回相同的数据类型作为其左侧操作数的值;在这种情况下,cadence 是一个 int。 20 | 21 | 下面是一个复合表达式: 22 | 23 | ``` 24 | 1 * 2 * 3 25 | ``` 26 | 27 | 表达式应该尽量避免歧义,比如: 28 | 29 | ``` 30 | x + y / 100 31 | ``` 32 | 33 | 有歧义,推荐写成 `(x + y) / 100` 或 `x + (y / 100)`。 34 | 35 | ## 语句 36 | 37 | 语句相当于自然语言中的句子。一条语句就是一个执行单元。用分号(;)结束一条语句。下面是表达式语句(expression statements),包括: 38 | 39 | * 赋值表达式(Assignment expressions) 40 | * ++ 或者 --(Any use of ++ or --) 41 | * 方法调用(Method invocations—) 42 | * 对象创建(Object creation expressions) 43 | 44 | 下面是表达式语句的例子 45 | 46 | ```java 47 | // assignment statement 48 | aValue = 8933.234; 49 | // increment statement 50 | aValue++; 51 | // method invocation statement 52 | System.out.println("Hello World!"); 53 | // object creation statement 54 | Bicycle myBike = new Bicycle(); 55 | ``` 56 | 57 | 除了表达式语句,其他的还有声明语句(declaration statements): 58 | 59 | ```java 60 | // declaration statement 61 | double aValue = 8933.234; 62 | ``` 63 | 64 | 以及[控制流程语句](../docs/control-flow.md)(control flow statements): 65 | 66 | ``` 67 | if (isMoving) 68 | currentSpeed--; 69 | ``` 70 | 71 | ## 块 72 | 73 | 块是一组零个或多个成对大括号之间的语句,并可以在任何地方允许使用一个单独的语句。下面的 BlockDemo 例子: 74 | 75 | ```java 76 | class BlockDemo { 77 | 78 | /** 79 | * @param args 80 | */ 81 | public static void main(String[] args) { 82 | boolean condition = true; 83 | if (condition) { // begin block 1 84 | System.out.println("Condition is true."); 85 | } // end block one 86 | else { // begin block 2 87 | System.out.println("Condition is false."); 88 | } // end block 2 89 | } 90 | } 91 | ``` 92 | 93 | ## 源码 94 | 95 | 本章例子的源码,可以在 `com.waylau.essentialjava.expression` 包下找到。 -------------------------------------------------------------------------------- /docs/getstarted.md: -------------------------------------------------------------------------------- 1 | # 快速开始 2 | 3 | 本章介绍了如何下载、安装、配置和调试 JDK。 4 | 5 | ## 下载、安装 JDK 6 | 7 | JDK(Java Development Kit)是用于 Java 开发的工具箱。 8 | 9 | 在下载 10 | 11 | JDK 支持如下操作系统的安装: 12 | 13 | 操作系统类型 | 文件大小 | 文件 14 | ---- | ---- | ---- 15 | Linux x86 | 154.67 MB | jdk-8u66-linux-i586.rpm 16 | Linux x86 | 174.83 MB | jdk-8u66-linux-i586.tar.gz 17 | Linux x64 | 152.69 MB | jdk-8u66-linux-x64.rpm 18 | Linux x64 | 172.89 MB | jdk-8u66-linux-x64.tar.gz 19 | Mac OS X x64 | 227.12 MB | jdk-8u66-macosx-x64.dmg 20 | Solaris SPARC 64-bit (SVR4 package) | 139.65 MB | jdk-8u66-solaris-sparcv9.tar.Z 21 | Solaris SPARC 64-bit | 99.05 MB | jdk-8u66-solaris-sparcv9.tar.gz 22 | Solaris x64 (SVR4 package) | 140 MB | jdk-8u66-solaris-x64.tar.Z 23 | Solaris x64 | 96.2 MB | jdk-8u66-solaris-x64.tar.gz 24 | Windows x86 | 181.33 MB | jdk-8u66-windows-i586.exe 25 | Windows x64 | 186.65 MB | jdk-8u66-windows-x64.exe 26 | 27 | 安装路径默认安装在 `C:\Program Files\Java\jdk1.8.0_66` 或者 `usr/local/java/jdk1.8.0_66` 28 | 29 | **注:**本书中所使用JDK版本为:Java Platform (JDK) 8u66。 30 | 本书所使用的操作系统为:Win7 Sp1 x64。本书的示例是在 Eclipse Mars.1 Release (4.5.1) 工具下编写。 31 | 32 | ### 基于 RPM 的 Linux 33 | 34 | (1)下载安装文件 35 | 36 | 文件名类似于`jdk-8uversion-linux-x64.rpm`。 37 | 38 | 39 | (2)切换到 root 用户身份 40 | 41 | (3)检查当前的安装情况。卸载老版本的 JDK 42 | 43 | 检查当前的安装情况,比如: 44 | 45 | ```shell 46 | $ rpm -qa | grep jdk 47 | jdk1.8.0_102-1.8.0_102-fcs.x86_64 48 | ``` 49 | 50 | 若有老版本 JDK,则需先卸载老版本: 51 | 52 | ```shell 53 | $ rpm -e package_name 54 | ``` 55 | 56 | 比如: 57 | 58 | ```shell 59 | $ rpm -e jdk1.8.0_102-1.8.0_102-fcs.x86_64 60 | ``` 61 | 62 | (4)安装 63 | 64 | ```shell 65 | $ rpm -ivh jdk-8uversion-linux-x64.rpm 66 | ``` 67 | 68 | 比如: 69 | 70 | ```shell 71 | $ rpm -ivh jdk-8u102-linux-x64.rpm 72 | Preparing... ########################################### [100%] 73 | 1:jdk1.8.0_102 ########################################### [100%] 74 | Unpacking JAR files... 75 | tools.jar... 76 | plugin.jar... 77 | javaws.jar... 78 | deploy.jar... 79 | rt.jar... 80 | jsse.jar... 81 | charsets.jar... 82 | localedata.jar... 83 | ``` 84 | 85 | (5)升级 86 | 87 | ```shell 88 | $ rpm -Uvh jdk-8uversion-linux-x64.rpm 89 | ``` 90 | 91 | 安装完成后,可以删除`.rpm`文件,以节省空间。 安装完后,无需重启主机,即可使用 JDK。 92 | 93 | 94 | ## 设置执行路径 95 | 96 | 97 | ### Windows 98 | 99 | 增加一个 `JAVA_HOME` 环境变量,值是 JDK 的安装目录。如 `C:\Program Files\Java\jdk1.8.0_66` ,注意后边不带分号 100 | 101 | 在 `PATH` 的环境变量里面增加 `%JAVA_HOME%\bin;` 102 | 103 | 在 `CLASSPATH`增加`.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;`(前面有点号和分号,后边结尾也有分号。 104 | 或者可以写成`.;%JAVA_HOME%\lib`如图所示,一样的效果。 105 | 106 | ### UNIX 107 | 108 | 包括 Linux、Mac OS X 和 Solaris 环境下,在`~/.profile`、`~/.bashrc`或 `~/.bash_profile` 文件末尾添加: 109 | 110 | ``` 111 | export JAVA_HOME=/usr/java/jdk1.8.0_66 112 | export PATH=$JAVA_HOME/bin:$PATH 113 | export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 114 | ``` 115 | 116 | 其中: 117 | 118 | * JAVA_HOME 是 JDK 安装目录 119 | * Linux 下用冒号“:”来分隔路径 120 | * $PATH 、$CLASSPATH、 $JAVA_HOME 是用来引用原来的环境变量的值 121 | * export 是把这三个变量导出为全局变量 122 | 123 | 比如,在 CentOS 下,需编辑`/etc/profile`文件。 124 | 125 | ## 测试 126 | 127 | 测试安装是否正确,可以在 shell 窗口,键入: 128 | 129 | ```shell 130 | $ java -version 131 | ``` 132 | 133 | 若能看到如下信息,则说明 JDK 安装成功: 134 | 135 | ``` 136 | java version "1.8.0_66" 137 | Java(TM) SE Runtime Environment (build 1.8.0_66-b17) 138 | Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode) 139 | ``` 140 | 141 | 最好再执行下`javac`,以测试环境变量是否设置正确: 142 | 143 | ```shell 144 | $ javac 145 | 用法: javac 146 | 其中, 可能的选项包括: 147 | -g 生成所有调试信息 148 | -g:none 不生成任何调试信息 149 | -g:{lines,vars,source} 只生成某些调试信息 150 | -nowarn 不生成任何警告 151 | -verbose 输出有关编译器正在执行的操作的消息 152 | -deprecation 输出使用已过时的 API 的源位置 153 | -classpath <路径> 指定查找用户类文件和注释处理程序的位置 154 | -cp <路径> 指定查找用户类文件和注释处理程序的位置 155 | -sourcepath <路径> 指定查找输入源文件的位置 156 | -bootclasspath <路径> 覆盖引导类文件的位置 157 | -extdirs <目录> 覆盖所安装扩展的位置 158 | -endorseddirs <目录> 覆盖签名的标准路径的位置 159 | -proc:{none,only} 控制是否执行注释处理和/或编译。 160 | -processor [,,...] 要运行的注释处理程序的名称; 绕过默认的搜索进程 161 | -processorpath <路径> 指定查找注释处理程序的位置 162 | -parameters 生成元数据以用于方法参数的反射 163 | -d <目录> 指定放置生成的类文件的位置 164 | -s <目录> 指定放置生成的源文件的位置 165 | -h <目录> 指定放置生成的本机标头文件的位置 166 | -implicit:{none,class} 指定是否为隐式引用文件生成类文件 167 | -encoding <编码> 指定源文件使用的字符编码 168 | -source <发行版> 提供与指定发行版的源兼容性 169 | -target <发行版> 生成特定 VM 版本的类文件 170 | -profile <配置文件> 请确保使用的 API 在指定的配置文件中可用 171 | -version 版本信息 172 | -help 输出标准选项的提要 173 | -A关键字[=值] 传递给注释处理程序的选项 174 | -X 输出非标准选项的提要 175 | -J<标记> 直接将 <标记> 传递给运行时系统 176 | -Werror 出现警告时终止编译 177 | @<文件名> 从文件读取选项和文件名 178 | ``` 179 | 180 | 有读者反映有时候`java -version`能够执行成功,但`javac`命令不成功的情况,一般是环境变量配置问题,请参阅上面“设置执行路径”章节内容,再仔细检测环境变量的配置。 181 | 182 | 183 | 更多安装细节,可以参考 ,以及 184 | -------------------------------------------------------------------------------- /docs/io.md: -------------------------------------------------------------------------------- 1 | # IO 2 | 3 | 本章交要讲解基本的 I/O 。它首先集中在 “I/O流”(I/O Streams),一个强大的概念用于简化 I/O 操作。本文还讲解了序列化,它可以让程序将整个对象转出为流,然后再从流读回来。随后介绍文件 I/O 和文件系统的操作,其中包括了随机访问文件。 4 | 5 | 大多数涵盖 I/O流 的类都在`java.io`包。大多数涵盖文件 I/O 的类都在`java.nio.file`包。 -------------------------------------------------------------------------------- /docs/jdbc.md: -------------------------------------------------------------------------------- 1 | # JDBC 2 | 3 | 4 | JDBC的内容已经单独开了课程,见 -------------------------------------------------------------------------------- /docs/keywords.md: -------------------------------------------------------------------------------- 1 | # 关键字 2 | 3 | 下面是 Java 里面的关键字。不能使用以下任一作为您的程序标识符。关键字 const 和 goto 语句被保留,即使他们目前尚未使用。true, false, 和 null 似乎是关键字,但它们实际上是字面值;你不能使用它们作为你的程序标识符。 4 | 5 | ``` 6 | abstract continue for new switch 7 | assert*** default goto* package synchronized 8 | boolean do if private this 9 | break double implements protected throw 10 | byte else import public throws 11 | case enum**** instanceof return transient 12 | catch extends int short try 13 | char final interface static void 14 | class finally long strictfp** volatile 15 | const* float native super while 16 | ``` 17 | 18 | 其中:`*`表示未使用,`**`表示是 1.2版本加入,`***` 表示 1.4版本加入, 19 | `****` 表示5.0版本加入 -------------------------------------------------------------------------------- /docs/networking.md: -------------------------------------------------------------------------------- 1 | ## 网络基础 2 | 3 | 在互联网上之间的通信交流,一般是基于 TCP (Transmission Control Protocol,传输控制协议) 或者 UDP (User Datagram Protocol,用户数据报协议) ,如下图: 4 | 5 | ![](../images/net/1netw.gif) 6 | 7 | 编写 Java 应用,我们只需关注于应用层 (application layer),而不用关心 TCP 和 UDP 所在的传输层是如何实现的。java.net 包含了你编程所需的类,这些类是与操作系统无关的。比如 URL, URLConnection, Socket, 和 ServerSocket 类是使用 TCP 连接网络的, DatagramPacket, DatagramSocket, 和 MulticastSocket 类是用于 UDP 的。 8 | 9 | Java 支持的协议只有 TCP 和 UDP ,以及在建立在 TCP 和 UDP 之上其他应用层协议。所有其他传输层、网际层和更底层的协议,如 ICMP、IGMP、ARP、RARP、RSVP 和其他协议 在 Java 中只能链接到原生代码来实现。 10 | 11 | ## TCP 12 | 13 | TCP (Transmission Control Protocol) 是面向连接的、提供端到端可靠的数据流(flow of data)。TCP 提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。 14 | 15 | “面向连接”就是在正式通信前必须要与对方建立起连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。 16 | 17 | ### 三次握手 18 | 19 | TCP 是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。一个 TCP 连接必须要经过三次“握手”才能建立起来,简单的讲就是: 20 | 21 | 1. 主机 A 向主机 B 发出连接请求数据包:“我想给你发数据,可以吗?”; 22 | 2. 主机 B 向主机 A 发送同意连接和要求同步(同步就是两台主机一个在发送,一个在接收,协调工作)的数据包:“可以,你来吧”; 23 | 3. 主机 A 再发出一个数据包确认主机 B 的要求同步:“好的,我来也,你接着吧!” 24 | 25 | 三次“握手”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机 A 才向主机 B 正式发送数据。 26 | 27 | 可以详见[《TCP 协议的三次握手、四次分手》](http://www.waylau.com/tcp-connect-and-close/) 28 | 29 | ### 如何保证数据的可靠 30 | 31 | TCP 通过下列方式来提供可靠性: 32 | 33 | * 应用数据被分割成 TCP 认为最适合发送的数据块。这和 UDP 完全不同,应用程序产生的数据报长度将保持不变。由 TCP 传递给 IP 的信息单位称为报文段或段(segment)。 34 | * 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。(可自行了解 TCP 协议中自适应的超时及重传策略)。 35 | * 当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒。 36 | * TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错, TCP 将丢弃这个报文段和不确认收到此报文段(希望发送端超时并重发)。 37 | * 既然 TCP 报文段作为 IP 数据报来传输,而 IP 数据报的到达可能会失序,因此 TCP 报文段的到达也可能会失序。如果必要, TCP 将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。 38 | * 既然 IP 数据报会发生重复, TCP 的接收端必须丢弃重复的数据。 39 | * TCP 还能提供流量控制。TCP 连接的每一方都有固定大小的缓冲空间。 TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。 40 | 41 | ## UDP 42 | 43 | UDP (User Datagram Protocol) 不是面向连接的,主机发送独立的数据报(datagram)给其他主机,不保证数据到达。由于 UDP 在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。 44 | 45 | 而无连接是一开始就发送信息(严格说来,这是没有开始、结束的),只是一次性的传递,是先不需要接受方的响应,因而在一定程度上也无法保证信息传递的可靠性了,就像写信一样,我们只是将信寄出去,却不能保证收信人一定可以收到。 46 | 47 | ### TCP 和 UDP 如何抉择 48 | 49 | TCP 是面向连接的,有比较高的可靠性, 一些要求比较高的服务一般使用这个协议,如FTP、Telnet、SMTP、HTTP、POP3 等,而 UDP 是面向无连接的,使用这个协议的常见服务有 DNS、SNMP、QQ 等。对于 QQ 必须另外说明一下,QQ2003 以前是只使用UDP协议的,其服务器使用8000端口,侦听是否有信息传来,客户端使用 4000 端口,向外发送信息(这也就不难理解在一般的显IP的QQ版本中显示好友的IP地址信息中端口常为4000或其后续端口的原因了),即QQ程序既接受服务又提供服务,在以后的 QQ 版本中也支持使用 TCP 协议了。 50 | 51 | ## 端口 52 | 53 | 一般来说,一台计算机具有单个物理连接到网络。数据通过这个连接去往特定的计算机。然而,该数据可以被用于在计算机上运行的不同应用。那么,计算机知道哪个应用程序转发数据?通过使用端口。 54 | 55 | 在互联网上传输的数据是通过计算机的标识和端口来定位的。计算机的标识是 32-bit 的 IP 地址。端口由一个 16-bit 的数字。 56 | 57 | 在诸如面向连接的通信如 TCP,服务器应用将套接字绑定到一个特定端口号。这是向系统注册服务用来接受该端口的数据。然后,客户端可以在与服务器在服务器端口会合,如下图所示: 58 | 59 | ![](../images/net/2tcp.gif) 60 | 61 | TCP 和 UDP 协议使用的端口来将接收到的数据映射到一个计算机上运行的进程。 62 | 63 | 在基于数据报的通信,如 UDP,数据报包中包含它的目的地的端口号,然后 UDP 将数据包路由到相应的应用程序,如本图所示的端口号: 64 | 65 | ![](../images/net/3tcpudp.gif) 66 | 67 | 端口号取值范围是从 0 到 65535 (16-bit 长度),其中范围从 0 到 1023 是受限的,它们是被知名的服务所保留使用,例如 HTTP (端口是 80)和 FTP (端口是20、21)等系统服务。这些端口被称为众所周知的端口(well-known ports)。您的应用程序不应该试图绑定到他们。你可以访问 来查询各种常用的已经分配的端口号列表。 -------------------------------------------------------------------------------- /docs/overview.md: -------------------------------------------------------------------------------- 1 | # Java 概述 2 | 3 | Java 编程语言是一种通用的、并行的、基于类的、面向对象的语言。它被设计得非常简单,这样程序员可以在该语言上流畅的交流。Java 编程语言与 C 和 C++ 有关联,但组织却截然不同,其中也省略了其他语言的一些用法,比如指针。它的目的是作为一个生产性语言,而不是一个研究性语言,因此,在设计上避免了包括新的和未经考验的功能。 4 | 5 | Java 编程语言是强类型和静态类型,可以在编译时检测到编译时错误。编译时间通常由翻译程序到与机器无关的字节码表示的。运行时的活动包括加载和执行程序,可选机器代码生成和程序的动态优化所需的类的交联,和实际执行程序。 6 | 7 | Java 编程语言是一个比较高层次的语言,在机器表示的细节是无法通过该语言的。它包括自动存储管理,通常使用垃圾收集器,以避免明确释放的安全问题(就像 C 语言的 free 或 C++ 的 delete)。高性能垃圾回收的实现可具有有界的停顿,以支持系统的编程和实时应用。语言不包括任何不安全的结构,如没有索引检查的数组访问,因为这种不安全的结构会导致不可预知的程序行为。 8 | 9 | 其他让你选择 Java 的理由还包括: 10 | 11 | * 丰富的开发工具:有很多开发工具可以让你快速开始 Java 编程之旅,比如 [Eclipse](https://eclipse.org/)、[IntelliJ](https://www.jetbrains.com/idea/) 和 [Netbeans](https://netbeans.org/) 12 | * 庞大的社区: 在世界各地估计有[超过 9 百万的 Java 开发人员](https://plumbr.eu/blog/java/how-many-java-developers-in-the-world)。这个数字意味着 Java 开发者可选的能够提高自己能力的讨论会、书籍、在线资源、论坛及培训项目的数量是巨大的。在[最新的 TIOBE 编程语言排行榜](http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html)中, Java 已经晋升榜首 13 | * 快速发展的潜质:Oracle 在 [Java 8](http://www.oracle.com/technetwork/java/javase/overview/java8-2100321.html) 中引入 Lambda 表达式和 Streams。以及即将到来的 Java 9,我们预测 Java 的实用性将继续增加。 14 | * 对于移动平台的支持:Android 的火爆很大一部分原因是因为 Java。在 Android 上,[ART](https://source.android.com/devices/tech/dalvik/) 为高负荷计算提供了接近本地应用的性能。在 iOS 上,[RoboVM](https://robovm.com/) 使用 [LLVM](http://llvm.org/),其使用的是与 C/C++/Objective-C/Swift 相同的后端,提供了比 Objective-C 和 Swift 只高不低的性能。 15 | 16 | ## 语言起源 17 |    18 | Java平台和语言最开始只是SUN公司在1990年12月开始研究的一个内部项目。SUN公司的一个叫做帕特里克·诺顿的工程师被自己开发的C和C语言编译器搞得焦头烂额,因为其中的API极其难用。帕特里克决定改用NeXT,同时他也获得了研究公司的一个叫做“Stealth计划”的项目的机会。 19 | 20 | “Stealth计划”后来改名为“Green计划”,JGosling(詹姆斯·高斯林)和麦克·舍林丹也加入了帕特里克的工作小组。他们和其他几个工程师一起在加利福尼亚州门罗帕克市沙丘路的一个小工作室里面研究开发新技术,瞄准下一代智能家电(如微波炉)的程序设计,SUN公司预料未来科技将在家用电器领域大显身手。团队最初考虑使用C语言,但是很多成员包括SUN的首席科学家比尔·乔伊,发现C和可用的API在某些方面存在很大问题。 21 | 22 | 工作小组使用的是内嵌类型平台,可以用的资源极其有限。很多成员发现C太复杂以至很多开发者经常错误使用。他们发现C缺少垃圾回收系统,还有可移植的安全性、分布程序设计、和多线程功能。最后,他们想要一种易于移植到各种设备上的平台。 23 |    24 | 根据可用的资金,比尔·乔伊决定开发一种集C语言和Mesa语言搭成的新语言,在一份报告上,乔伊把它叫做“未来”,他提议SUN公司的工程师应该在C的基础上,开发一种面向对象的环境。最初,高斯林试图修改和扩展C的功能,他自己称这种新语言为C--,但是后来他放弃了。他将要创造出一种全新的语言,被他命名为“Oak”(橡树),以他的办公室外的树而命名。 25 |    26 | 就像很多开发新技术的秘密的工程一样,工作小组没日没夜地工作到了1992年的夏天,他们能够演示新平台的一部分了,包括Green操作系统,Oak的程序设计语言,类库,和其硬件。最初的尝试是面向一种类PDA设备,被命名为Star7,这种设备有鲜艳的图形界面和被称为“Duke”的智能代理来帮助用户。1992年12月3日,这台设备进行了展示。 27 |    28 | 同年11月,Green计划被转化成了“FirstPerson有限公司”,一个SUN公司的全资子公司,团队也被重新安排到了帕洛阿尔托。FirstPerson团队对建造一种高度互动的设备感兴趣,当时代华纳发布了一个关于电视机顶盒的征求提议书时(Requestforproposal),FirstPerson改变了他们的目标,作为对征求意见书的响应,提出了一个机顶盒平台的提议。但是有线电视业界觉得FirstPerson的平台给予用户过多地控制权,因此FirstPerson的投标败给了SGI。与3DO公司的另外一笔关于机顶盒的交易也没有成功,由于他们的平台不能在电视工业产生任何效益,公司再并回SUN公司。 29 |    30 | 1994年6、7月间,在经历了一场历时三天的头脑风暴的讨论之后,约翰·盖吉、詹姆斯·高斯林、比尔·乔伊、帕特里克·诺顿、韦恩·罗斯因和埃里克·斯库米,团队决定再一次改变了努力的目标,这次他们决定将该技术应用于万维网。他们认为随着Mosaic浏览器的到来,因特网正在向同样的高度互动的远景演变,而这一远景正是他们在有线电视网中看到的。作为原型,帕特里克·诺顿写了一个小型万维网浏览器,WebRunner,后来改名为HotJava。同年,Oak改名为Java。商标搜索显示,Oak已被一家显卡制造商注册,因此团队找到了一个新名字。这个名字是在很多成员常去的本地咖啡馆中杜撰出来的。名字是不是首字母缩写还不清楚,很大程度上来说不是。虽然有人声称是开发人员名字的组合:JamesGosling(詹姆斯·高斯林)ArthurVanHoff(阿瑟·凡·霍夫)AndyBechtolsheim(安迪·贝克托克姆),或“JustAnotherVagueAcronym”(只是另外一个含糊的缩写)。还有一种比较可信的说法是这个名字是出于对咖啡的喜爱,所以以Java咖啡来命名。类文件的前四个字节如果用十六进制阅读的话,分别为“CAFEBABE”,就会拼出两个单词“CAFEBABE”(咖啡宝贝)。 31 | 32 |    33 | 1994年10月,HotJava和Java平台为公司高层进行演示。1994年,Java1.0a版本已经可以提供下载,但是Java和HotJava浏览器的第一次公开发布却是在1995年5月23日SunWorld大会上进行的。SUN公司的科学指导约翰·盖吉宣告Java技术。这个发布是与网景公司的执行副总裁马克·安德森的惊人发布一起进行的,宣布网景将在其浏览器中包含对Java的支持。1996年1月,Sun公司成立了Java业务集团,专门开发Java技术。 34 | 35 | ## 发展简史 36 | 37 | * 1995年5月23日,Java语言诞生 38 | * 1996年1月,第一个JDK-JDK1.0诞生 39 | * 1996年4月,10个最主要的操作系统供应商申明将在其产品中嵌入JAVA技术 40 | * 1996年9月,约8.3万个网页应用了JAVA技术来制作 41 | * 1997年2月18日,JDK1.1发布 42 | * 1997年4月2日,JavaOne会议召开,参与者逾一万人,创当时全球同类会议规模之纪录 43 | * 1997年9月,JavaDeveloperConnection社区成员超过十万 44 | * 1998年2月,JDK1.1被下载超过2,000,000次 45 | * 1998年12月8日,JAVA2企业平台J2EE发布 46 | * 1999年6月,SUN公司发布Java的三个版本:标准版(JavaSE,以前是J2SE)、企业版(JavaEE以前是J2EE)和微型版(JavaME,以前是J2ME) 47 | * 2000年5月8日,JDK1.3发布 48 | * 2000年5月29日,JDK1.4发布 49 | * 2001年6月5日,NOKIA宣布,到2003年将出售1亿部支持Java的手机 50 | * 2001年9月24日,J2EE1.3发布 51 | * 2002年2月26日,J2SE1.4发布,自此Java的计算能力有了大幅提升 52 | * 2004年9月30日18:00PM,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性,J2SE1.5更名为JavaSE5.0 53 | * 2005年6月,JavaOne大会召开,SUN公司公开JavaSE6。此时,Java的各种版本已经更名,以取消其中的数字“2”:J2EE更名为JavaEE,J2SE更名为JavaSE,J2ME更名为JavaME 54 | * 2006年12月,SUN公司发布JRE6.0 55 | * 2009年4月7日GoogleAppEngine开始支持Java 56 | * 2009年04月20日,甲骨文74亿美元收购Sun。取得java的版权。 57 | * 2010年11月,由于甲骨文对于Java社区的不友善,因此Apache扬言将退出JCP。 58 | * 2011年7月28日,甲骨文发布java7.0的正式版。 59 | * 2014年3月19日,甲骨文公司发布java8.0的正式版。 60 | 61 | ## Java 语言与 Java 虚拟机的关系 62 | 63 | ### 什么是 Java 虚拟机 64 | 65 | Java 虚拟机(Java Virtual Machine,简称 JVM) 是整个 Java 平台的基石,实现硬件与操作系统无关,编译代码后生成出极小体积,保障用户机器免于恶意代码损害。 66 | 67 | JVM 可以看作是一台抽象的计算机。跟真实的计算机一样,它有自己的指令集以及各种运行时内存区域。使用虚拟机来实现一门程序设计语言有许多合理的理由,业界中流传最为久远的虚拟机可能是 UCSD Pascal 的 P-Code 虚拟机。 68 | 69 | 第一个 JVM 的原型机是由 Sun 公司实现的,它被用在一种类似 PDA(Personal Digital Assistant,俗称掌上电脑)的手持设备上仿真实现 JVM 指令集。时至今日,Oracle 已有许多 JVM 实现应用于移动设备、桌面电脑、服务器等领域。JVM 并不局限于特定的实现技术、主机硬件和操作系统。它不强求使用解释器来执行程序,也可以通过把自己的指令集编译为实际 CPU 的指令来实现,它可以通过微代码来实现,或者甚至直接实现在 CPU 中。 70 | 71 | ### Java 语言与 JVM 的关系 72 | 73 | JVM 与 Java 语言并没有必然的联系,它只与特定的二进制文件格式 class 文件格式所关联。class 文件中包含了 JVM 指令集(或者称为字节码、bytecodes)和符号表,还有一些其他辅助信息。 74 | 75 | 基于安全方面的考虑,JVM 要求在 class 文件中使用了许多强制性的语法和结构化约束,但任一门功能性语言都可以表示为一个能被 JVM 接收的有效的 class 文件。作为一个通用的、机器无关的执行平台,任何其他语言的实现者都可以将 JVM 作为他们语言的产品交付媒介。 76 | 77 | ![](../images/overview/jvm.jpg) 78 | 79 | 如上图所示,在 Java 编程语言和环境中,即时编译器(JIT compiler,just-in-time compiler)是一个把 Java 的字节码(包括需要被解释的指令的程序)转换成可以直接发送给处理器的指令的程序。当你写好一个 Java 程序后,源语言的语句将由Java 编译器编译成字节码,而不是编译成与某个特定的处理器硬件平台对应的指令代码(比如,Intel 的 Pentium 微处理器或 IBM 的 System/390 处理器)。字节码是可以发送给任何平台并且能在那个平台上运行的独立于平台的代码。 80 | 81 | 有关 JVNM 的相关内容,可参阅[《Java 虚拟机规范》](https://github.com/waylau/java-virtual-machine-specification) 。 82 | -------------------------------------------------------------------------------- /docs/socket.md: -------------------------------------------------------------------------------- 1 | # Socket 2 | 3 | ## 什么是 Socket 4 | 5 | Socket(套接字):是在网络上运行两个程序之间的双向通信链路的一个端点。socket绑定到一个端口号,使得 TCP 层可以标识数据最终要被发送到哪个应用程序。 6 | 7 | 正常情况下,一台服务器在特定计算机上运行,​​并具有被绑定到特定端口号的 socket。服务器只是等待,并监听用于客户发起的连接请求的 socket 。 8 | 9 | 在客户端:客户端知道服务器所运行的主机名称以及服务器正在侦听的端口号。建立连接请求时,客户端尝试与主机服务器和端口会合。客户端也需要在连接中将自己绑定到本地端口以便于给服务器做识别。本地端口号通常是由系统分配的。 10 | 11 | ![](../images/net/5connect.gif) 12 | 13 | 如果一切顺利的话,服务器接受连接。一旦接受,服务器获取绑定到相同的本地端口的新 socket ,并且还具有其远程端点设定为客户端的地址和端口。它需要一个新的socket,以便它可以继续监听原来用于客户端连接请求的 socket 。 14 | 15 | ![](../images/net/6connect.gif) 16 | 17 | 在客户端,如果连接被接受,则成功地创建一个套接字和客户端可以使用该 socket 与服务器进行通信。 18 | 19 | 客户机和服务器现在可以通过 socket 写入或读取来交互了。 20 | 21 | 端点是IP地址和端口号的组合。每个 TCP 连接可以通过它的两个端点被唯一标识。这样,你的主机和服务器之间可以有多个连接。 22 | 23 | java.net 包中提供了一个类 Socket,实现您的 Java 程序和网络上的其他程序之间的双向连接。 Socket 类隐藏任何特定系统的细节。通过使用 java.net.Socket 类,而不是依赖于原生代码,Java 程序可以用独立于平台的方式与网络进行通信。 24 | 25 | 此外,java.net 包含了 ServerSocket 类,它实现了服务器的 socket 可以侦监听和接受客户端的连接。下文将展示如何使用 Socket 和 ServerSocket 类。 26 | 27 | ## 实现一个 echo 服务器 28 | 29 | 让我们来看看这个例子,程序可以建立使用 Socket 类连接到服务器程序,客户端可以通过 socket 向服务器发送数据和接收数据。 30 | 31 | EchoClient 示例程序实现了一个客户端,连接到回声服务器。回声服务器从它的客户端接收数据并原样返回回来。EchoServer 实现了 echo 服务器。 (客户端可以连接到支持 [Echo 协议](http://tools.ietf.org/html/rfc862)的任何主机) 32 | 33 | EchoClient 创建一个 socket,从而得到回声服务器的连接。它从标准输入流中读取用户输入,然后通过 socket 转发该文本给回声服务器。服务器通过该 socket 将文本原样输入回给客户端。客户机程序读取并显示从服务器传递回给它的数据。 34 | 35 | 注意,EchoClient 例子既从 socket 写入又从 socket 中读取数据。 36 | 37 | EchoClient 代码: 38 | 39 | ```java 40 | public class EchoClient { 41 | public static void main(String[] args) throws IOException { 42 | 43 | if (args.length != 2) { 44 | System.err.println( 45 | "Usage: java EchoClient "); 46 | System.exit(1); 47 | } 48 | 49 | String hostName = args[0]; 50 | int portNumber = Integer.parseInt(args[1]); 51 | 52 | try ( 53 | Socket echoSocket = new Socket(hostName, portNumber); 54 | PrintWriter out = 55 | new PrintWriter(echoSocket.getOutputStream(), true); 56 | BufferedReader in = 57 | new BufferedReader( 58 | new InputStreamReader(echoSocket.getInputStream())); 59 | BufferedReader stdIn = 60 | new BufferedReader( 61 | new InputStreamReader(System.in)) 62 | ) { 63 | String userInput; 64 | while ((userInput = stdIn.readLine()) != null) { 65 | out.println(userInput); 66 | System.out.println("echo: " + in.readLine()); 67 | } 68 | } catch (UnknownHostException e) { 69 | System.err.println("Don't know about host " + hostName); 70 | System.exit(1); 71 | } catch (IOException e) { 72 | System.err.println("Couldn't get I/O for the connection to " + 73 | hostName); 74 | System.exit(1); 75 | } 76 | } 77 | } 78 | ``` 79 | 80 | EchoServer 代码: 81 | 82 | ```java 83 | public class EchoServer { 84 | public static void main(String[] args) throws IOException { 85 | 86 | if (args.length != 1) { 87 | System.err.println("Usage: java EchoServer "); 88 | System.exit(1); 89 | } 90 | 91 | int portNumber = Integer.parseInt(args[0]); 92 | 93 | try ( 94 | ServerSocket serverSocket = 95 | new ServerSocket(Integer.parseInt(args[0])); 96 | Socket clientSocket = serverSocket.accept(); 97 | PrintWriter out = 98 | new PrintWriter(clientSocket.getOutputStream(), true); 99 | BufferedReader in = new BufferedReader( 100 | new InputStreamReader(clientSocket.getInputStream())); 101 | ) { 102 | String inputLine; 103 | while ((inputLine = in.readLine()) != null) { 104 | out.println(inputLine); 105 | } 106 | } catch (IOException e) { 107 | System.out.println("Exception caught when trying to listen on port " 108 | + portNumber + " or listening for a connection"); 109 | System.out.println(e.getMessage()); 110 | } 111 | } 112 | } 113 | ``` 114 | 115 | 首先启动服务器,在命令行输入如下,设定一个端口号,比如 7(Echo 协议指定端口是 7): 116 | 117 | java EchoServer 7 118 | 119 | 而后启动客户端,echoserver.example.com 是你主机的名称,如果是本机的话,主机名称可以是 localhost 120 | 121 | java EchoClient echoserver.example.com 7 122 | 123 | 输出效果如下: 124 | 125 | 你好吗? 126 | echo: 你好吗? 127 | 我很好哦 128 | echo: 我很好哦 129 | 要过年了,www.waylau.com 祝你 猴年大吉,身体健康哦! 130 | echo: 要过年了,www.waylau.com 祝你 猴年大吉,身体健康哦! 131 | 132 | -------------------------------------------------------------------------------- /images/basics/conversion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/basics/conversion.jpg -------------------------------------------------------------------------------- /images/basics/objects-tenElementArray.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/basics/objects-tenElementArray.gif -------------------------------------------------------------------------------- /images/basics/primitive-data-types-conversion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/basics/primitive-data-types-conversion.jpg -------------------------------------------------------------------------------- /images/basics/primitive-data-types.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/basics/primitive-data-types.jpg -------------------------------------------------------------------------------- /images/exception/exceptions-callstack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/exception/exceptions-callstack.gif -------------------------------------------------------------------------------- /images/exception/exceptions-errorOccurs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/exception/exceptions-errorOccurs.gif -------------------------------------------------------------------------------- /images/exception/exceptions-hierarchy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/exception/exceptions-hierarchy.gif -------------------------------------------------------------------------------- /images/exception/exceptions-throwable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/exception/exceptions-throwable.gif -------------------------------------------------------------------------------- /images/generics/generics-listParent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/generics/generics-listParent.gif -------------------------------------------------------------------------------- /images/generics/generics-payloadListHierarchy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/generics/generics-payloadListHierarchy.gif -------------------------------------------------------------------------------- /images/generics/generics-sampleHierarchy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/generics/generics-sampleHierarchy.gif -------------------------------------------------------------------------------- /images/generics/generics-subtypeRelationship.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/generics/generics-subtypeRelationship.gif -------------------------------------------------------------------------------- /images/generics/generics-wildcardSubtyping.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/generics/generics-wildcardSubtyping.gif -------------------------------------------------------------------------------- /images/io/byteStream.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/io/byteStream.gif -------------------------------------------------------------------------------- /images/io/io-dirStructure.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/io/io-dirStructure.gif -------------------------------------------------------------------------------- /images/io/io-spec.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/io/io-spec.gif -------------------------------------------------------------------------------- /images/io/io-symlink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/io/io-symlink.gif -------------------------------------------------------------------------------- /images/io/io-trav.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/io/io-trav.gif -------------------------------------------------------------------------------- /images/net/1-10 signal-driven-io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/1-10 signal-driven-io.png -------------------------------------------------------------------------------- /images/net/1-11 aio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/1-11 aio.png -------------------------------------------------------------------------------- /images/net/1-12 Comparison of the five IO models.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/1-12 Comparison of the five IO models.png -------------------------------------------------------------------------------- /images/net/1-7 bio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/1-7 bio.png -------------------------------------------------------------------------------- /images/net/1-8 nio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/1-8 nio.png -------------------------------------------------------------------------------- /images/net/1-9 io-multiplexing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/1-9 io-multiplexing.png -------------------------------------------------------------------------------- /images/net/1netw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/1netw.gif -------------------------------------------------------------------------------- /images/net/2tcp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/2tcp.gif -------------------------------------------------------------------------------- /images/net/3tcpudp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/3tcpudp.gif -------------------------------------------------------------------------------- /images/net/5connect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/5connect.gif -------------------------------------------------------------------------------- /images/net/6connect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/net/6connect.gif -------------------------------------------------------------------------------- /images/oop/base-derived.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/base-derived.jpg -------------------------------------------------------------------------------- /images/oop/concepts-bicycleObject.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/concepts-bicycleObject.gif -------------------------------------------------------------------------------- /images/oop/concepts-bikeHierarchy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/concepts-bikeHierarchy.gif -------------------------------------------------------------------------------- /images/oop/concepts-object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/concepts-object.gif -------------------------------------------------------------------------------- /images/oop/cooling-system.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/cooling-system.jpg -------------------------------------------------------------------------------- /images/oop/has-a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/has-a.jpg -------------------------------------------------------------------------------- /images/oop/light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/light.jpg -------------------------------------------------------------------------------- /images/oop/shape-iteration.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/shape-iteration.jpg -------------------------------------------------------------------------------- /images/oop/shape-overriding.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/shape-overriding.jpg -------------------------------------------------------------------------------- /images/oop/shape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/oop/shape.jpg -------------------------------------------------------------------------------- /images/overview/jvm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/images/overview/jvm.jpg -------------------------------------------------------------------------------- /java_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/java_logo.jpg -------------------------------------------------------------------------------- /samples/essential-java-demos/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /samples/essential-java-demos/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | essential-java-demos 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /samples/essential-java-demos/resources/characteroutput.txt: -------------------------------------------------------------------------------- 1 | 字节流处理原始的二进制数据 I/O。输入输出的是8位字节,相关的类为 [InputStream](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html) 和 [OutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html). 2 | 3 | 字节流的类有许多。为了演示字节流的工作,我们将重点放在文件 I/O字节流 [FileInputStream](https://docs.oracle.com/javase/8/docs/api/java/io/FileInputStream.html) 和 [FileOutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/FileOutputStream.html) 上。其他种类的字节流用法类似,主要区别在于它们构造的方式,大家可以举一反三。 4 | -------------------------------------------------------------------------------- /samples/essential-java-demos/resources/invoicedata.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/essential-java/1212904f41ee82c263b0be6f8ae10dafc791f19f/samples/essential-java-demos/resources/invoicedata.txt -------------------------------------------------------------------------------- /samples/essential-java-demos/resources/outagain.txt: -------------------------------------------------------------------------------- 1 | 字节流处理原始的二进制数据 I/O。输入输出的是8位字节,相关的类为 [InputStream](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html) 和 [OutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html). 2 | 3 | 字节流的类有许多。为了演示字节流的工作,我们将重点放在文件 I/O字节流 [FileInputStream](https://docs.oracle.com/javase/8/docs/api/java/io/FileInputStream.html) 和 [FileOutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/FileOutputStream.html) 上。其他种类的字节流用法类似,主要区别在于它们构造的方式,大家可以举一反三。 -------------------------------------------------------------------------------- /samples/essential-java-demos/resources/usnumbers.txt: -------------------------------------------------------------------------------- 1 | 8.5 2 | 32,767 3 | 3.14159 4 | 1,000,000.1 -------------------------------------------------------------------------------- /samples/essential-java-demos/resources/xanadu.txt: -------------------------------------------------------------------------------- 1 | 字节流处理原始的二进制数据 I/O。输入输出的是8位字节,相关的类为 [InputStream](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html) 和 [OutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html). 2 | 3 | 字节流的类有许多。为了演示字节流的工作,我们将重点放在文件 I/O字节流 [FileInputStream](https://docs.oracle.com/javase/8/docs/api/java/io/FileInputStream.html) 和 [FileOutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/FileOutputStream.html) 上。其他种类的字节流用法类似,主要区别在于它们构造的方式,大家可以举一反三。 4 | 5 | By default, a scanner uses white space to separate tokens. (White space characters include blanks, tabs, and line terminators. For the full list, refer to the documentation for Character.isWhitespace.) To see how scanning works, let's look at ScanXan, a program that reads the individual words in xanadu.txt and prints them out, one per line. -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/annotation/AnnotationDemo.java: -------------------------------------------------------------------------------- 1 | package com.waylau.essentialjava.annotation; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.lang.reflect.Method; 6 | 7 | /** 8 | * 通过反射了解注解的例子. 9 | * 10 | * @since 1.0.0 2017年3月14日 11 | * @author Way Lau 12 | */ 13 | public class AnnotationDemo { 14 | 15 | /** 16 | * @param args 17 | * @throws Exception 18 | * @throws Throwable 19 | */ 20 | public static void main(String[] args) throws Exception, Throwable { 21 | AnnotationTest test = new AnnotationTest(); 22 | 23 | test.execute(); 24 | 25 | // 获取 AnnotationTest 的Class实例 26 | Class c = AnnotationTest.class; 27 | 28 | // 获取需要处理的方法Method实例 29 | Method method = c.getMethod("execute", new Class[]{}); 30 | 31 | // 判断该方法是否包含 MyAnnotation 注解 32 | if(method.isAnnotationPresent(MyAnnotation.class)){ 33 | 34 | // 获取该方法的 MyAnnotation 注解实例 35 | MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class); 36 | 37 | // 执行该方法 38 | method.invoke(test, new Object[]{}); 39 | 40 | // 获取 myAnnotation 的属性值 41 | String company = myAnnotation.company(); 42 | System.out.println(company); 43 | } 44 | 45 | // 获取方法上的所有注解 46 | Annotation[] annotations = method.getAnnotations(); 47 | for(Annotation annotation : annotations){ 48 | System.out.println(annotation); 49 | } 50 | } 51 | 52 | } 53 | 54 | class AnnotationTest { 55 | 56 | @MyAnnotation(company="https://waylau.com") 57 | public void execute(){ 58 | System.out.println("do something~"); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/annotation/MyAnnotation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.annotation; 5 | 6 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 7 | 8 | import java.lang.annotation.Documented; 9 | import java.lang.annotation.Retention; 10 | 11 | @Documented 12 | @Retention(RUNTIME) 13 | /** 14 | * 15 | * 16 | * @since 1.0.0 2017年3月14日 17 | * @author Way Lau 18 | */ 19 | public @interface MyAnnotation { 20 | String company() default "waylau.com"; 21 | } 22 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/annotation/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 注解相关的例子. 3 | * 4 | * @since 1.0.0 2017年3月14日 5 | * @author Way Lau 6 | */ 7 | package com.waylau.essentialjava.annotation; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/array/arraydemo/ArrayCopyDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.array.arraydemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月26日 9 | */ 10 | class ArrayCopyDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' }; 17 | char[] copyTo = new char[7]; 18 | 19 | System.arraycopy(copyFrom, 2, copyTo, 0, 7); 20 | System.out.println(new String(copyTo)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/array/arraydemo/ArrayCopyOfDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.array.arraydemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月26日 9 | */ 10 | class ArrayCopyOfDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' }; 17 | 18 | char[] copyTo = java.util.Arrays.copyOfRange(copyFrom, 2, 9); 19 | 20 | System.out.println(new String(copyTo)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/array/arraydemo/ArrayDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.array.arraydemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月26日 9 | */ 10 | class ArrayDemo { 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | // declares an array of integers 16 | int[] anArray; 17 | 18 | // allocates memory for 10 integers 19 | anArray = new int[10]; 20 | 21 | // initialize first element 22 | anArray[0] = 100; 23 | // initialize second element 24 | anArray[1] = 200; 25 | // and so forth 26 | anArray[2] = 300; 27 | anArray[3] = 400; 28 | anArray[4] = 500; 29 | anArray[5] = 600; 30 | anArray[6] = 700; 31 | anArray[7] = 800; 32 | anArray[8] = 900; 33 | anArray[9] = 1000; 34 | 35 | System.out.println("Element at index 0: " + anArray[0]); 36 | System.out.println("Element at index 1: " + anArray[1]); 37 | System.out.println("Element at index 2: " + anArray[2]); 38 | System.out.println("Element at index 3: " + anArray[3]); 39 | System.out.println("Element at index 4: " + anArray[4]); 40 | System.out.println("Element at index 5: " + anArray[5]); 41 | System.out.println("Element at index 6: " + anArray[6]); 42 | System.out.println("Element at index 7: " + anArray[7]); 43 | System.out.println("Element at index 8: " + anArray[8]); 44 | System.out.println("Element at index 9: " + anArray[9]); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/array/arraydemo/MultiDimArrayDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.array.arraydemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月26日 9 | */ 10 | class MultiDimArrayDemo { 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | String[][] names = { { "Mr. ", "Mrs. ", "Ms. " }, { "Smith", "Jones" } }; 16 | // Mr. Smith 17 | System.out.println(names[0][0] + names[1][0]); 18 | // Ms. Jones 19 | System.out.println(names[0][2] + names[1][1]); 20 | } 21 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/array/arraydemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月26日 7 | */ 8 | package com.waylau.essentialjava.array.arraydemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/Consumer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | import java.util.Random; 7 | 8 | /** 9 | * @author waylau.com 10 | * @date 2016年1月22日 11 | */ 12 | public class Consumer implements Runnable { 13 | private Drop drop; 14 | 15 | public Consumer(Drop drop) { 16 | this.drop = drop; 17 | } 18 | 19 | public void run() { 20 | Random random = new Random(); 21 | for (String message = drop.take(); !message.equals("DONE"); message = drop.take()) { 22 | System.out.format("MESSAGE RECEIVED: %s%n", message); 23 | try { 24 | Thread.sleep(random.nextInt(5000)); 25 | } catch (InterruptedException e) { 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/Counter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月21日 9 | */ 10 | public class Counter { 11 | private int c = 0; 12 | 13 | public void increment() { 14 | c++; 15 | } 16 | 17 | public void decrement() { 18 | c--; 19 | } 20 | 21 | public int value() { 22 | return c; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/Deadlock.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月21日 9 | */ 10 | public class Deadlock { 11 | static class Friend { 12 | private final String name; 13 | 14 | public Friend(String name) { 15 | this.name = name; 16 | } 17 | 18 | public String getName() { 19 | return this.name; 20 | } 21 | 22 | public synchronized void bow(Friend bower) { 23 | System.out.format("%s: %s" + " has bowed to me!%n", this.name, bower.getName()); 24 | bower.bowBack(this); 25 | } 26 | 27 | public synchronized void bowBack(Friend bower) { 28 | System.out.format("%s: %s" + " has bowed back to me!%n", this.name, bower.getName()); 29 | } 30 | } 31 | 32 | public static void main(String[] args) { 33 | final Friend alphonse = new Friend("Alphonse"); 34 | final Friend gaston = new Friend("Gaston"); 35 | new Thread(new Runnable() { 36 | public void run() { 37 | alphonse.bow(gaston); 38 | } 39 | }).start(); 40 | new Thread(new Runnable() { 41 | public void run() { 42 | gaston.bow(alphonse); 43 | } 44 | }).start(); 45 | } 46 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/Drop.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月22日 9 | */ 10 | public class Drop { 11 | // Message sent from producer 12 | // to consumer. 13 | private String message; 14 | // True if consumer should wait 15 | // for producer to send message, 16 | // false if producer should wait for 17 | // consumer to retrieve message. 18 | private boolean empty = true; 19 | 20 | public synchronized String take() { 21 | // Wait until message is 22 | // available. 23 | while (empty) { 24 | try { 25 | wait(); 26 | } catch (InterruptedException e) {} 27 | } 28 | // Toggle status. 29 | empty = true; 30 | // Notify producer that 31 | // status has changed. 32 | notifyAll(); 33 | return message; 34 | } 35 | 36 | public synchronized void put(String message) { 37 | // Wait until message has 38 | // been retrieved. 39 | while (!empty) { 40 | try { 41 | wait(); 42 | } catch (InterruptedException e) {} 43 | } 44 | // Toggle status. 45 | empty = false; 46 | // Store message. 47 | this.message = message; 48 | // Notify consumer that status 49 | // has changed. 50 | notifyAll(); 51 | } 52 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/ForkBlur.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | import java.awt.image.BufferedImage; 7 | import java.io.File; 8 | import java.util.concurrent.ForkJoinPool; 9 | import java.util.concurrent.RecursiveAction; 10 | import javax.imageio.ImageIO; 11 | 12 | /** 13 | * @author waylau.com 14 | * @date 2016年1月22日 15 | */ 16 | public class ForkBlur extends RecursiveAction { 17 | /** 18 | * 19 | */ 20 | private static final long serialVersionUID = 1L; 21 | private int[] mSource; 22 | private int mStart; 23 | private int mLength; 24 | private int[] mDestination; 25 | private int mBlurWidth = 15; // Processing window size, should be odd. 26 | 27 | public ForkBlur(int[] src, int start, int length, int[] dst) { 28 | mSource = src; 29 | mStart = start; 30 | mLength = length; 31 | mDestination = dst; 32 | } 33 | 34 | // Average pixels from source, write results into destination. 35 | protected void computeDirectly() { 36 | int sidePixels = (mBlurWidth - 1) / 2; 37 | for (int index = mStart; index < mStart + mLength; index++) { 38 | // Calculate average. 39 | float rt = 0, gt = 0, bt = 0; 40 | for (int mi = -sidePixels; mi <= sidePixels; mi++) { 41 | int mindex = Math.min(Math.max(mi + index, 0), mSource.length - 1); 42 | int pixel = mSource[mindex]; 43 | rt += (float) ((pixel & 0x00ff0000) >> 16) / mBlurWidth; 44 | gt += (float) ((pixel & 0x0000ff00) >> 8) / mBlurWidth; 45 | bt += (float) ((pixel & 0x000000ff) >> 0) / mBlurWidth; 46 | } 47 | 48 | // Re-assemble destination pixel. 49 | int dpixel = (0xff000000) | (((int) rt) << 16) | (((int) gt) << 8) | (((int) bt) << 0); 50 | mDestination[index] = dpixel; 51 | } 52 | } 53 | 54 | protected static int sThreshold = 10000; 55 | 56 | @Override 57 | protected void compute() { 58 | if (mLength < sThreshold) { 59 | computeDirectly(); 60 | return; 61 | } 62 | 63 | int split = mLength / 2; 64 | 65 | invokeAll(new ForkBlur(mSource, mStart, split, mDestination), 66 | new ForkBlur(mSource, mStart + split, mLength - split, mDestination)); 67 | } 68 | 69 | // Plumbing follows. 70 | public static void main(String[] args) throws Exception { 71 | String srcName = "red-tulips.jpg"; 72 | File srcFile = new File(srcName); 73 | BufferedImage image = ImageIO.read(srcFile); 74 | 75 | System.out.println("Source image: " + srcName); 76 | 77 | BufferedImage blurredImage = blur(image); 78 | 79 | String dstName = "blurred-tulips.jpg"; 80 | File dstFile = new File(dstName); 81 | ImageIO.write(blurredImage, "jpg", dstFile); 82 | 83 | System.out.println("Output image: " + dstName); 84 | 85 | } 86 | 87 | public static BufferedImage blur(BufferedImage srcImage) { 88 | int w = srcImage.getWidth(); 89 | int h = srcImage.getHeight(); 90 | 91 | int[] src = srcImage.getRGB(0, 0, w, h, null, 0, w); 92 | int[] dst = new int[src.length]; 93 | 94 | System.out.println("Array size is " + src.length); 95 | System.out.println("Threshold is " + sThreshold); 96 | 97 | int processors = Runtime.getRuntime().availableProcessors(); 98 | System.out.println( 99 | Integer.toString(processors) + " processor" + (processors != 1 ? "s are " : " is ") + "available"); 100 | 101 | ForkBlur fb = new ForkBlur(src, 0, src.length, dst); 102 | 103 | ForkJoinPool pool = new ForkJoinPool(); 104 | 105 | long startTime = System.currentTimeMillis(); 106 | pool.invoke(fb); 107 | long endTime = System.currentTimeMillis(); 108 | 109 | System.out.println("Image blur took " + (endTime - startTime) + " milliseconds."); 110 | 111 | BufferedImage dstImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 112 | dstImage.setRGB(0, 0, w, h, dst, 0, w); 113 | 114 | return dstImage; 115 | } 116 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/HelloRunnable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月21日 9 | */ 10 | public class HelloRunnable implements Runnable { 11 | /* (non-Javadoc) 12 | * @see java.lang.Runnable#run() 13 | */ 14 | @Override 15 | public void run() { 16 | System.out.println("Hello from a thread!"); 17 | } 18 | 19 | /** 20 | * @param args 21 | */ 22 | public static void main(String[] args) { 23 | (new Thread(new HelloRunnable())).start(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/HelloThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月21日 9 | */ 10 | public class HelloThread extends Thread { 11 | 12 | public void run() { 13 | System.out.println("Hello from a thread!"); 14 | } 15 | /** 16 | * @param args 17 | */ 18 | public static void main(String[] args) { 19 | (new HelloThread()).start(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/ImmutableRGB.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月22日 9 | */ 10 | public class ImmutableRGB { 11 | // Values must be between 0 and 255. 12 | final private int red; 13 | final private int green; 14 | final private int blue; 15 | final private String name; 16 | 17 | private void check(int red, 18 | int green, 19 | int blue) { 20 | if (red < 0 || red > 255 21 | || green < 0 || green > 255 22 | || blue < 0 || blue > 255) { 23 | throw new IllegalArgumentException(); 24 | } 25 | } 26 | 27 | public ImmutableRGB(int red, 28 | int green, 29 | int blue, 30 | String name) { 31 | check(red, green, blue); 32 | this.red = red; 33 | this.green = green; 34 | this.blue = blue; 35 | this.name = name; 36 | } 37 | 38 | 39 | public int getRGB() { 40 | return ((red << 16) | (green << 8) | blue); 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public ImmutableRGB invert() { 48 | return new ImmutableRGB(255 - red, 49 | 255 - green, 50 | 255 - blue, 51 | "Inverse of " + name); 52 | } 53 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/MsLunch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月21日 9 | */ 10 | public class MsLunch { 11 | @SuppressWarnings("unused") 12 | private long c1 = 0; 13 | @SuppressWarnings("unused") 14 | private long c2 = 0; 15 | private Object lock1 = new Object(); 16 | private Object lock2 = new Object(); 17 | 18 | public void inc1() { 19 | synchronized(lock1) { 20 | c1++; 21 | } 22 | } 23 | 24 | public void inc2() { 25 | synchronized(lock2) { 26 | c2++; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/Producer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | import java.util.Random; 7 | 8 | /** 9 | * @author waylau.com 10 | * @date 2016年1月22日 11 | */ 12 | public class Producer implements Runnable { 13 | private Drop drop; 14 | 15 | public Producer(Drop drop) { 16 | this.drop = drop; 17 | } 18 | 19 | public void run() { 20 | String importantInfo[] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", 21 | "A kid will eat ivy too" }; 22 | Random random = new Random(); 23 | 24 | for (int i = 0; i < importantInfo.length; i++) { 25 | drop.put(importantInfo[i]); 26 | try { 27 | Thread.sleep(random.nextInt(5000)); 28 | } catch (InterruptedException e) { 29 | } 30 | } 31 | drop.put("DONE"); 32 | } 33 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/ProducerConsumerExample.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月22日 9 | */ 10 | public class ProducerConsumerExample { 11 | public static void main(String[] args) { 12 | Drop drop = new Drop(); 13 | (new Thread(new Producer(drop))).start(); 14 | (new Thread(new Consumer(drop))).start(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/Safelock.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | import java.util.Random; 7 | import java.util.concurrent.locks.Lock; 8 | import java.util.concurrent.locks.ReentrantLock; 9 | 10 | /** 11 | * @author waylau.com 12 | * @date 2016年1月22日 13 | */ 14 | public class Safelock { 15 | static class Friend { 16 | private final String name; 17 | private final Lock lock = new ReentrantLock(); 18 | 19 | public Friend(String name) { 20 | this.name = name; 21 | } 22 | 23 | public String getName() { 24 | return this.name; 25 | } 26 | 27 | public boolean impendingBow(Friend bower) { 28 | Boolean myLock = false; 29 | Boolean yourLock = false; 30 | try { 31 | myLock = lock.tryLock(); 32 | yourLock = bower.lock.tryLock(); 33 | } finally { 34 | if (!(myLock && yourLock)) { 35 | if (myLock) { 36 | lock.unlock(); 37 | } 38 | if (yourLock) { 39 | bower.lock.unlock(); 40 | } 41 | } 42 | } 43 | return myLock && yourLock; 44 | } 45 | 46 | public void bow(Friend bower) { 47 | if (impendingBow(bower)) { 48 | try { 49 | System.out.format("%s: %s has" + " bowed to me!%n", this.name, bower.getName()); 50 | bower.bowBack(this); 51 | } finally { 52 | lock.unlock(); 53 | bower.lock.unlock(); 54 | } 55 | } else { 56 | System.out.format( 57 | "%s: %s started" + " to bow to me, but saw that" + " I was already bowing to" + " him.%n", 58 | this.name, bower.getName()); 59 | } 60 | } 61 | 62 | public void bowBack(Friend bower) { 63 | System.out.format("%s: %s has" + " bowed back to me!%n", this.name, bower.getName()); 64 | } 65 | } 66 | 67 | static class BowLoop implements Runnable { 68 | private Friend bower; 69 | private Friend bowee; 70 | 71 | public BowLoop(Friend bower, Friend bowee) { 72 | this.bower = bower; 73 | this.bowee = bowee; 74 | } 75 | 76 | public void run() { 77 | Random random = new Random(); 78 | for (;;) { 79 | try { 80 | Thread.sleep(random.nextInt(10)); 81 | } catch (InterruptedException e) { 82 | } 83 | bowee.bow(bower); 84 | } 85 | } 86 | } 87 | 88 | public static void main(String[] args) { 89 | final Friend alphonse = new Friend("Alphonse"); 90 | final Friend gaston = new Friend("Gaston"); 91 | new Thread(new BowLoop(alphonse, gaston)).start(); 92 | new Thread(new BowLoop(gaston, alphonse)).start(); 93 | } 94 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/SimpleThreads.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月21日 9 | */ 10 | public class SimpleThreads { 11 | // Display a message, preceded by 12 | // the name of the current thread 13 | static void threadMessage(String message) { 14 | String threadName = 15 | Thread.currentThread().getName(); 16 | System.out.format("%s: %s%n", 17 | threadName, 18 | message); 19 | } 20 | 21 | private static class MessageLoop 22 | implements Runnable { 23 | public void run() { 24 | String importantInfo[] = { 25 | "Mares eat oats", 26 | "Does eat oats", 27 | "Little lambs eat ivy", 28 | "A kid will eat ivy too" 29 | }; 30 | try { 31 | for (int i = 0; 32 | i < importantInfo.length; 33 | i++) { 34 | // Pause for 4 seconds 35 | Thread.sleep(4000); 36 | // Print a message 37 | threadMessage(importantInfo[i]); 38 | } 39 | } catch (InterruptedException e) { 40 | threadMessage("I wasn't done!"); 41 | } 42 | } 43 | } 44 | 45 | public static void main(String args[]) 46 | throws InterruptedException { 47 | 48 | // Delay, in milliseconds before 49 | // we interrupt MessageLoop 50 | // thread (default one hour). 51 | long patience = 1000 * 60 * 60; 52 | 53 | // If command line argument 54 | // present, gives patience 55 | // in seconds. 56 | if (args.length > 0) { 57 | try { 58 | patience = Long.parseLong(args[0]) * 1000; 59 | } catch (NumberFormatException e) { 60 | System.err.println("Argument must be an integer."); 61 | System.exit(1); 62 | } 63 | } 64 | 65 | threadMessage("Starting MessageLoop thread"); 66 | long startTime = System.currentTimeMillis(); 67 | Thread t = new Thread(new MessageLoop()); 68 | t.start(); 69 | 70 | threadMessage("Waiting for MessageLoop thread to finish"); 71 | // loop until MessageLoop 72 | // thread exits 73 | while (t.isAlive()) { 74 | threadMessage("Still waiting..."); 75 | // Wait maximum of 1 second 76 | // for MessageLoop thread 77 | // to finish. 78 | t.join(1000); 79 | if (((System.currentTimeMillis() - startTime) > patience) 80 | && t.isAlive()) { 81 | threadMessage("Tired of waiting!"); 82 | t.interrupt(); 83 | // Shouldn't be long now 84 | // -- wait indefinitely 85 | t.join(); 86 | } 87 | } 88 | threadMessage("Finally!"); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/SleepMessages.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月21日 9 | */ 10 | public class SleepMessages { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) throws InterruptedException { 16 | String importantInfo[] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", 17 | "A kid will eat ivy too" }; 18 | 19 | for (int i = 0; i < importantInfo.length; i++) { 20 | // Pause for 4 seconds 21 | Thread.sleep(4000); 22 | // Print a message 23 | System.out.println(importantInfo[i]); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/SynchronizedCounter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月21日 9 | */ 10 | public class SynchronizedCounter { 11 | private int c = 0; 12 | 13 | public synchronized void increment() { 14 | c++; 15 | } 16 | 17 | public synchronized void decrement() { 18 | c--; 19 | } 20 | 21 | public synchronized int value() { 22 | return c; 23 | } 24 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/SynchronizedRGB.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.concurrency; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月22日 9 | */ 10 | public class SynchronizedRGB { 11 | // Values must be between 0 and 255. 12 | private int red; 13 | private int green; 14 | private int blue; 15 | private String name; 16 | 17 | private void check(int red, 18 | int green, 19 | int blue) { 20 | if (red < 0 || red > 255 21 | || green < 0 || green > 255 22 | || blue < 0 || blue > 255) { 23 | throw new IllegalArgumentException(); 24 | } 25 | } 26 | 27 | public SynchronizedRGB(int red, 28 | int green, 29 | int blue, 30 | String name) { 31 | check(red, green, blue); 32 | this.red = red; 33 | this.green = green; 34 | this.blue = blue; 35 | this.name = name; 36 | } 37 | 38 | public void set(int red, 39 | int green, 40 | int blue, 41 | String name) { 42 | check(red, green, blue); 43 | synchronized (this) { 44 | this.red = red; 45 | this.green = green; 46 | this.blue = blue; 47 | this.name = name; 48 | } 49 | } 50 | 51 | public synchronized int getRGB() { 52 | return ((red << 16) | (green << 8) | blue); 53 | } 54 | 55 | public synchronized String getName() { 56 | return name; 57 | } 58 | 59 | public synchronized void invert() { 60 | red = 255 - red; 61 | green = 255 - green; 62 | blue = 255 - blue; 63 | name = "Inverse of " + name; 64 | } 65 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/concurrency/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月21日 7 | */ 8 | package com.waylau.essentialjava.concurrency; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/exception/ListOfNumbers.java: -------------------------------------------------------------------------------- 1 | package com.waylau.essentialjava.exception; 2 | import java.io.*; 3 | import java.util.List; 4 | import java.util.ArrayList; 5 | /** 6 | * 7 | * @author Way Lau 8 | * @date 2017年2月22日 9 | */ 10 | public class ListOfNumbers { 11 | private List list; 12 | private static final int SIZE = 10; 13 | 14 | public ListOfNumbers () { 15 | list = new ArrayList(SIZE); 16 | for (int i = 0; i < SIZE; i++) 17 | list.add(new Integer(i)); 18 | } 19 | public void writeList() { 20 | PrintWriter out = null; 21 | 22 | try { 23 | System.out.println("Entering try statement"); 24 | out = new PrintWriter(new FileWriter("OutFile.txt")); 25 | 26 | for (int i = 0; i < SIZE; i++) 27 | out.println("Value at: " + i + " = " + list.get(i)); 28 | } catch (IndexOutOfBoundsException e) { 29 | System.err.println("Caught IndexOutOfBoundsException: " + 30 | e.getMessage()); 31 | } catch (IOException e) { 32 | System.err.println("Caught IOException: " + e.getMessage()); 33 | } finally { 34 | if (out != null) { 35 | System.out.println("Closing PrintWriter"); 36 | out.close(); 37 | } else { 38 | System.out.println("PrintWriter not open"); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/exception/trywithresources/Demo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.exception.trywithresources; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年2月3日 9 | */ 10 | public class Demo { 11 | public static void main(String[] args) { 12 | try(Resource res = new Resource()) { 13 | res.doSome(); 14 | } catch(Exception ex) { 15 | ex.printStackTrace(); 16 | } 17 | } 18 | } 19 | 20 | class Resource implements AutoCloseable { 21 | void doSome() { 22 | System.out.println("do something"); 23 | } 24 | @Override 25 | public void close() throws Exception { 26 | System.out.println("resource is closed"); 27 | } 28 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/exception/trywithresources/Demo2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.exception.trywithresources; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年2月3日 9 | */ 10 | public class Demo2 { 11 | public static void main(String[] args) { 12 | try(ResourceSome some = new ResourceSome(); 13 | ResourceOther other = new ResourceOther()) { 14 | some.doSome(); 15 | other.doOther(); 16 | } catch(Exception ex) { 17 | ex.printStackTrace(); 18 | } 19 | } 20 | } 21 | 22 | class ResourceSome implements AutoCloseable { 23 | void doSome() { 24 | System.out.println("do something"); 25 | } 26 | @Override 27 | public void close() throws Exception { 28 | System.out.println("some resource is closed"); 29 | } 30 | } 31 | 32 | class ResourceOther implements AutoCloseable { 33 | void doOther() { 34 | System.out.println("do other things"); 35 | } 36 | @Override 37 | public void close() throws Exception { 38 | System.out.println("other resource is closed"); 39 | } 40 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/exception/trywithresources/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年2月3日 7 | */ 8 | package com.waylau.essentialjava.exception.trywithresources; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/expression/blockdemo/BlockDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.expression.blockdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class BlockDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | boolean condition = true; 17 | if (condition) { // begin block 1 18 | System.out.println("Condition is true."); 19 | } // end block one 20 | else { // begin block 2 21 | System.out.println("Condition is false."); 22 | } // end block 2 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/expression/blockdemo/ShareExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.expression.blockdemo; 5 | 6 | /** 7 | * 在一个异常处理程序中处理多个类型的异常. 8 | * 9 | * @author Way Lau 10 | * @date 2017年7月26日 11 | */ 12 | public class ShareExceptionHandler { 13 | /** 14 | * @param args 15 | */ 16 | public static void main(String[] args) { 17 | 18 | 19 | // not share exception handler 20 | int[] intArray = new int[3]; 21 | try { 22 | for (int i = 0; i <= intArray.length; i++) { 23 | intArray[i] = i; 24 | System.out.println("intArray[" + i + "] = " + intArray[i]); 25 | System.out.println("intArray[" + i + "]模 " + (i - 2) + "的值: " + intArray[i] % (i - 2)); 26 | } 27 | } catch (ArrayIndexOutOfBoundsException e) { 28 | System.out.println("异常信息:" + e); 29 | } catch (ArithmeticException e) { 30 | System.out.println("异常信息:" + e); 31 | } 32 | System.out.println("程序正常结束。"); 33 | 34 | // share exception handler 35 | intArray = new int[3]; 36 | try { 37 | for (int i = 0; i <= intArray.length; i++) { 38 | intArray[i] = i; 39 | System.out.println("intArray[" + i + "] = " + intArray[i]); 40 | System.out.println("intArray[" + i + "]模 " + (i - 2) + "的值: " + intArray[i] % (i - 2)); 41 | } 42 | } catch (ArrayIndexOutOfBoundsException | ArithmeticException e) { 43 | System.out.println("异常信息:" + e); 44 | } 45 | System.out.println("程序正常结束。"); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/expression/blockdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月27日 7 | */ 8 | package com.waylau.essentialjava.expression.blockdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/branchdemo/BreakDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.branchdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | class BreakDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 }; 17 | int searchfor = 12; 18 | 19 | int i; 20 | boolean foundIt = false; 21 | 22 | for (i = 0; i < arrayOfInts.length; i++) { 23 | if (arrayOfInts[i] == searchfor) { 24 | foundIt = true; 25 | break; 26 | } 27 | } 28 | 29 | if (foundIt) { 30 | System.out.println("Found " + searchfor + " at index " + i); 31 | } else { 32 | System.out.println(searchfor + " not in the array"); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/branchdemo/BreakWithLabelDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.branchdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | class BreakWithLabelDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int[][] arrayOfInts = { { 32, 87, 3, 589 }, { 12, 1076, 2000, 8 }, { 622, 127, 77, 955 } }; 17 | int searchfor = 12; 18 | 19 | int i; 20 | int j = 0; 21 | boolean foundIt = false; 22 | 23 | search: for (i = 0; i < arrayOfInts.length; i++) { 24 | for (j = 0; j < arrayOfInts[i].length; j++) { 25 | if (arrayOfInts[i][j] == searchfor) { 26 | foundIt = true; 27 | break search; 28 | } 29 | } 30 | } 31 | 32 | if (foundIt) { 33 | System.out.println("Found " + searchfor + " at " + i + ", " + j); 34 | } else { 35 | System.out.println(searchfor + " not in the array"); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/branchdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月28日 7 | */ 8 | package com.waylau.essentialjava.flow.branchdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/continuedemo/ContinueDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.continuedemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | class ContinueDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | String searchMe = "peter piper picked a " + "peck of pickled peppers"; 17 | int max = searchMe.length(); 18 | int numPs = 0; 19 | 20 | for (int i = 0; i < max; i++) { 21 | // interested only in p's 22 | if (searchMe.charAt(i) != 'p') 23 | continue; 24 | 25 | // process p's 26 | numPs++; 27 | } 28 | System.out.println("Found " + numPs + " p's in the string."); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/continuedemo/ContinueWithLabelDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.continuedemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | class ContinueWithLabelDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | String searchMe = "Look for a substring in me"; 17 | String substring = "sub"; 18 | boolean foundIt = false; 19 | 20 | int max = searchMe.length() - substring.length(); 21 | 22 | test: for (int i = 0; i <= max; i++) { 23 | int n = substring.length(); 24 | int j = i; 25 | int k = 0; 26 | while (n-- != 0) { 27 | if (searchMe.charAt(j++) != substring.charAt(k++)) { 28 | continue test; 29 | } 30 | } 31 | foundIt = true; 32 | break test; 33 | } 34 | System.out.println(foundIt ? "Found it" : "Didn't find it"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/continuedemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月28日 7 | */ 8 | package com.waylau.essentialjava.flow.continuedemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/fordemo/EnhancedForDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.fordemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | class EnhancedForDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int[] numbers = 17 | {1,2,3,4,5,6,7,8,9,10}; 18 | for (int item : numbers) { 19 | System.out.println("Count is: " + item); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/fordemo/ForDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.fordemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | class ForDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | for(int i=1; i<11; i++){ 17 | System.out.println("Count is: " + i); 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/fordemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月28日 7 | */ 8 | package com.waylau.essentialjava.flow.fordemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/ifelsedemo/IfElseDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.ifelsedemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class IfElseDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int testscore = 76; 17 | char grade; 18 | 19 | if (testscore >= 90) { 20 | grade = 'A'; 21 | } else if (testscore >= 80) { 22 | grade = 'B'; 23 | } else if (testscore >= 70) { 24 | grade = 'C'; 25 | } else if (testscore >= 60) { 26 | grade = 'D'; 27 | } else { 28 | grade = 'F'; 29 | } 30 | System.out.println("Grade = " + grade); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/ifelsedemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月27日 7 | */ 8 | package com.waylau.essentialjava.flow.ifelsedemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/switchdemo/StringSwitchDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.switchdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class StringSwitchDemo { 11 | 12 | public static int getMonthNumber(String month) { 13 | 14 | int monthNumber = 0; 15 | 16 | if (month == null) { 17 | return monthNumber; 18 | } 19 | 20 | switch (month.toLowerCase()) { 21 | case "january": 22 | monthNumber = 1; 23 | break; 24 | case "february": 25 | monthNumber = 2; 26 | break; 27 | case "march": 28 | monthNumber = 3; 29 | break; 30 | case "april": 31 | monthNumber = 4; 32 | break; 33 | case "may": 34 | monthNumber = 5; 35 | break; 36 | case "june": 37 | monthNumber = 6; 38 | break; 39 | case "july": 40 | monthNumber = 7; 41 | break; 42 | case "august": 43 | monthNumber = 8; 44 | break; 45 | case "september": 46 | monthNumber = 9; 47 | break; 48 | case "october": 49 | monthNumber = 10; 50 | break; 51 | case "november": 52 | monthNumber = 11; 53 | break; 54 | case "december": 55 | monthNumber = 12; 56 | break; 57 | default: 58 | monthNumber = 0; 59 | break; 60 | } 61 | 62 | return monthNumber; 63 | } 64 | 65 | public static void main(String[] args) { 66 | 67 | String month = "August"; 68 | 69 | int returnedMonthNumber = StringSwitchDemo.getMonthNumber(month); 70 | 71 | if (returnedMonthNumber == 0) { 72 | System.out.println("Invalid month"); 73 | } else { 74 | System.out.println(returnedMonthNumber); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/switchdemo/SwitchDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.switchdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class SwitchDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int month = 8; 17 | String monthString; 18 | switch (month) { 19 | case 1: 20 | monthString = "January"; 21 | break; 22 | case 2: 23 | monthString = "February"; 24 | break; 25 | case 3: 26 | monthString = "March"; 27 | break; 28 | case 4: 29 | monthString = "April"; 30 | break; 31 | case 5: 32 | monthString = "May"; 33 | break; 34 | case 6: 35 | monthString = "June"; 36 | break; 37 | case 7: 38 | monthString = "July"; 39 | break; 40 | case 8: 41 | monthString = "August"; 42 | break; 43 | case 9: 44 | monthString = "September"; 45 | break; 46 | case 10: 47 | monthString = "October"; 48 | break; 49 | case 11: 50 | monthString = "November"; 51 | break; 52 | case 12: 53 | monthString = "December"; 54 | break; 55 | default: 56 | monthString = "Invalid month"; 57 | break; 58 | } 59 | System.out.println(monthString); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/switchdemo/SwitchDemo2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.switchdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class SwitchDemo2 { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int month = 2; 17 | int year = 2000; 18 | int numDays = 0; 19 | 20 | switch (month) { 21 | case 1: 22 | case 3: 23 | case 5: 24 | case 7: 25 | case 8: 26 | case 10: 27 | case 12: 28 | numDays = 31; 29 | break; 30 | case 4: 31 | case 6: 32 | case 9: 33 | case 11: 34 | numDays = 30; 35 | break; 36 | case 2: 37 | if (((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0)) 38 | numDays = 29; 39 | else 40 | numDays = 28; 41 | break; 42 | default: 43 | System.out.println("Invalid month."); 44 | break; 45 | } 46 | System.out.println("Number of Days = " + numDays); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/switchdemo/SwitchDemoFallThrough.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.switchdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class SwitchDemoFallThrough { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | java.util.ArrayList futureMonths = new java.util.ArrayList(); 17 | 18 | int month = 8; 19 | 20 | switch (month) { 21 | case 1: 22 | futureMonths.add("January"); 23 | case 2: 24 | futureMonths.add("February"); 25 | case 3: 26 | futureMonths.add("March"); 27 | case 4: 28 | futureMonths.add("April"); 29 | case 5: 30 | futureMonths.add("May"); 31 | case 6: 32 | futureMonths.add("June"); 33 | case 7: 34 | futureMonths.add("July"); 35 | case 8: 36 | futureMonths.add("August"); 37 | case 9: 38 | futureMonths.add("September"); 39 | case 10: 40 | futureMonths.add("October"); 41 | case 11: 42 | futureMonths.add("November"); 43 | case 12: 44 | futureMonths.add("December"); 45 | break; 46 | default: 47 | break; 48 | } 49 | 50 | if (futureMonths.isEmpty()) { 51 | System.out.println("Invalid month number"); 52 | } else { 53 | for (String monthName : futureMonths) { 54 | System.out.println(monthName); 55 | } 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/switchdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月27日 7 | */ 8 | package com.waylau.essentialjava.flow.switchdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/whiledemo/DoWhileDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.whiledemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | class DoWhileDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int count = 1; 17 | do { 18 | System.out.println("Count is: " + count); 19 | count++; 20 | } while (count < 11); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/whiledemo/WhileDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.flow.whiledemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class WhileDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int count = 1; 17 | while (count < 11) { 18 | System.out.println("Count is: " + count); 19 | count++; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/flow/whiledemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月27日 7 | */ 8 | package com.waylau.essentialjava.flow.whiledemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/generic/boxdemo/Box.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.generic.boxdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月29日 9 | */ 10 | public class Box { 11 | private Object object; 12 | 13 | public void set(Object object) { 14 | this.object = object; 15 | } 16 | 17 | public Object get() { 18 | return object; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/generic/boxdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月29日 7 | */ 8 | package com.waylau.essentialjava.generic.boxdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/generic/generic/boxdemo/Box.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.generic.generic.boxdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月29日 9 | */ 10 | public class Box { 11 | // T stands for "Type" 12 | private T t; 13 | 14 | public void set(T t) { 15 | this.t = t; 16 | } 17 | 18 | public T get() { 19 | return t; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/generic/generic/boxdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月29日 7 | */ 8 | package com.waylau.essentialjava.generic.generic.boxdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/bytestream/CopyBytes.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.bytestream; 5 | 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author waylau.com 12 | * @date 2016年1月18日 13 | */ 14 | public class CopyBytes { 15 | /** 16 | * @param args 17 | * @throws IOException 18 | */ 19 | public static void main(String[] args) throws IOException { 20 | FileInputStream in = null; 21 | FileOutputStream out = null; 22 | 23 | try { 24 | in = new FileInputStream("resources/xanadu.txt"); 25 | out = new FileOutputStream("resources/outagain.txt"); 26 | int c; 27 | 28 | while ((c = in.read()) != -1) { 29 | out.write(c); 30 | } 31 | } finally { 32 | if (in != null) { 33 | in.close(); 34 | } 35 | if (out != null) { 36 | out.close(); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/bytestream/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月18日 7 | */ 8 | package com.waylau.essentialjava.io.bytestream; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/characterstream/CopyCharacters.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.characterstream; 5 | 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author waylau.com 12 | * @date 2016年1月18日 13 | */ 14 | public class CopyCharacters { 15 | /** 16 | * @param args 17 | * @throws IOException 18 | */ 19 | public static void main(String[] args) throws IOException { 20 | FileReader inputStream = null; 21 | FileWriter outputStream = null; 22 | 23 | try { 24 | inputStream = new FileReader("resources/xanadu.txt"); 25 | outputStream = new FileWriter("resources/characteroutput.txt"); 26 | 27 | int c; 28 | while ((c = inputStream.read()) != -1) { 29 | outputStream.write(c); 30 | } 31 | } finally { 32 | if (inputStream != null) { 33 | inputStream.close(); 34 | } 35 | if (outputStream != null) { 36 | outputStream.close(); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/characterstream/CopyLines.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.characterstream; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.FileReader; 8 | import java.io.FileWriter; 9 | import java.io.IOException; 10 | import java.io.PrintWriter; 11 | 12 | /** 13 | * @author waylau.com 14 | * @date 2016年1月18日 15 | */ 16 | public class CopyLines { 17 | /** 18 | * @param args 19 | * @throws IOException 20 | */ 21 | public static void main(String[] args) throws IOException { 22 | BufferedReader inputStream = null; 23 | PrintWriter outputStream = null; 24 | 25 | try { 26 | inputStream = new BufferedReader(new FileReader("resources/xanadu.txt")); 27 | outputStream = new PrintWriter(new FileWriter("resources/characteroutput.txt")); 28 | 29 | String l; 30 | while ((l = inputStream.readLine()) != null) { 31 | outputStream.println(l); 32 | } 33 | } finally { 34 | if (inputStream != null) { 35 | inputStream.close(); 36 | } 37 | if (outputStream != null) { 38 | outputStream.close(); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/characterstream/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月18日 7 | */ 8 | package com.waylau.essentialjava.io.characterstream; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/commandline/Password.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.commandline; 5 | 6 | import java.io.Console; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * @author waylau.com 11 | * @date 2016年1月18日 12 | */ 13 | public class Password { 14 | /** 15 | * @param args 16 | */ 17 | public static void main(String[] args) { 18 | Console c = System.console(); 19 | if (c == null) { 20 | System.err.println("No console."); 21 | System.exit(1); 22 | } 23 | 24 | String login = c.readLine("Enter your login: "); 25 | char [] oldPassword = c.readPassword("Enter your old password: "); 26 | 27 | if (verify(login, oldPassword)) { 28 | boolean noMatch; 29 | do { 30 | char [] newPassword1 = c.readPassword("Enter your new password: "); 31 | char [] newPassword2 = c.readPassword("Enter new password again: "); 32 | noMatch = ! Arrays.equals(newPassword1, newPassword2); 33 | if (noMatch) { 34 | c.format("Passwords don't match. Try again.%n"); 35 | } else { 36 | change(login, newPassword1); 37 | c.format("Password for %s changed.%n", login); 38 | } 39 | Arrays.fill(newPassword1, ' '); 40 | Arrays.fill(newPassword2, ' '); 41 | } while (noMatch); 42 | } 43 | 44 | Arrays.fill(oldPassword, ' '); 45 | } 46 | 47 | // Dummy change method. 48 | static boolean verify(String login, char[] password) { 49 | // This method always returns 50 | // true in this example. 51 | // Modify this method to verify 52 | // password according to your rules. 53 | return true; 54 | } 55 | 56 | // Dummy change method. 57 | static void change(String login, char[] password) { 58 | // Modify this method to change 59 | // password according to your rules. 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/commandline/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月18日 7 | */ 8 | package com.waylau.essentialjava.io.commandline; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/datastream/DataStreams.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.datastream; 5 | 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.DataInputStream; 9 | import java.io.DataOutputStream; 10 | import java.io.BufferedInputStream; 11 | import java.io.BufferedOutputStream; 12 | import java.io.IOException; 13 | import java.io.EOFException; 14 | 15 | /** 16 | * @author waylau.com 17 | * @date 2016年1月18日 18 | */ 19 | public class DataStreams { 20 | static final String dataFile = "resources/invoicedata.txt"; 21 | 22 | static final double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 }; 23 | static final int[] units = { 12, 8, 13, 29, 50 }; 24 | static final String[] descs = { "Java T-shirt", 25 | "Java Mug", 26 | "Duke Juggling Dolls", 27 | "Java Pin", 28 | "Java Key Chain" }; 29 | 30 | public static void main(String[] args) throws IOException { 31 | 32 | 33 | DataOutputStream out = null; 34 | 35 | try { 36 | out = new DataOutputStream(new 37 | BufferedOutputStream(new FileOutputStream(dataFile))); 38 | 39 | for (int i = 0; i < prices.length; i ++) { 40 | out.writeDouble(prices[i]); 41 | out.writeInt(units[i]); 42 | out.writeUTF(descs[i]); 43 | } 44 | } finally { 45 | out.close(); 46 | } 47 | 48 | DataInputStream in = null; 49 | double total = 0.0; 50 | try { 51 | in = new DataInputStream(new 52 | BufferedInputStream(new FileInputStream(dataFile))); 53 | 54 | double price; 55 | int unit; 56 | String desc; 57 | 58 | try { 59 | while (true) { 60 | price = in.readDouble(); 61 | unit = in.readInt(); 62 | desc = in.readUTF(); 63 | System.out.format("You ordered %d units of %s at $%.2f%n", 64 | unit, desc, price); 65 | total += unit * price; 66 | } 67 | } catch (EOFException e) { } 68 | System.out.format("For a TOTAL of: $%.2f%n", total); 69 | } 70 | finally { 71 | in.close(); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/datastream/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月18日 7 | */ 8 | package com.waylau.essentialjava.io.datastream; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/formatting/Format.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.formatting; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月18日 9 | */ 10 | public class Format { 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | System.out.format("%f, %1$+020.10f %n", Math.PI); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/formatting/Root.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.formatting; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月18日 9 | */ 10 | public class Root { 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | int i = 2; 16 | double r = Math.sqrt(i); 17 | 18 | System.out.print("The square root of "); 19 | System.out.print(i); 20 | System.out.print(" is "); 21 | System.out.print(r); 22 | System.out.println("."); 23 | 24 | i = 5; 25 | r = Math.sqrt(i); 26 | System.out.println("The square root of " + i + " is " + r + "."); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/formatting/Root2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.formatting; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2016年1月18日 9 | */ 10 | public class Root2 { 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | int i = 2; 16 | double r = Math.sqrt(i); 17 | 18 | System.out.format("The square root of %d is %f.%n", i, r); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/formatting/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月18日 7 | */ 8 | package com.waylau.essentialjava.io.formatting; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/objectstream/ObjectStreams.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.objectstream; 5 | 6 | import java.io.*; 7 | import java.math.BigDecimal; 8 | import java.util.Calendar; 9 | 10 | /** 11 | * @author waylau.com 12 | * @date 2016年1月19日 13 | */ 14 | public class ObjectStreams { 15 | static final String dataFile = "resources/invoicedata.txt"; 16 | 17 | static final BigDecimal[] prices = { 18 | new BigDecimal("19.99"), 19 | new BigDecimal("9.99"), 20 | new BigDecimal("15.99"), 21 | new BigDecimal("3.99"), 22 | new BigDecimal("4.99") }; 23 | static final int[] units = { 12, 8, 13, 29, 50 }; 24 | static final String[] descs = { "Java T-shirt", 25 | "Java Mug", 26 | "Duke Juggling Dolls", 27 | "Java Pin", 28 | "Java Key Chain" }; 29 | 30 | public static void main(String[] args) 31 | throws IOException, ClassNotFoundException { 32 | 33 | 34 | ObjectOutputStream out = null; 35 | try { 36 | out = new ObjectOutputStream(new 37 | BufferedOutputStream(new FileOutputStream(dataFile))); 38 | 39 | out.writeObject(Calendar.getInstance()); 40 | for (int i = 0; i < prices.length; i ++) { 41 | out.writeObject(prices[i]); 42 | out.writeInt(units[i]); 43 | out.writeUTF(descs[i]); 44 | } 45 | } finally { 46 | out.close(); 47 | } 48 | 49 | ObjectInputStream in = null; 50 | try { 51 | in = new ObjectInputStream(new 52 | BufferedInputStream(new FileInputStream(dataFile))); 53 | 54 | Calendar date = null; 55 | BigDecimal price; 56 | int unit; 57 | String desc; 58 | BigDecimal total = new BigDecimal(0); 59 | 60 | date = (Calendar) in.readObject(); 61 | 62 | System.out.format ("On %tA, %waylau.com 6 | * @date 2016年1月19日 7 | */ 8 | package com.waylau.essentialjava.io.objectstream; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月18日 7 | */ 8 | package com.waylau.essentialjava.io; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/path/Copy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.path; 5 | 6 | import java.nio.file.*; 7 | import static java.nio.file.StandardCopyOption.*; 8 | import java.nio.file.attribute.*; 9 | import static java.nio.file.FileVisitResult.*; 10 | import java.io.IOException; 11 | import java.util.*; 12 | 13 | /** 14 | * @author waylau.com 15 | * @date 2016年1月20日 16 | */ 17 | public class Copy { 18 | 19 | /** 20 | * Returns {@code true} if okay to overwrite a file ("cp -i") 21 | */ 22 | static boolean okayToOverwrite(Path file) { 23 | String answer = System.console().readLine("overwrite %s (yes/no)? ", file); 24 | return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes")); 25 | } 26 | 27 | /** 28 | * Copy source file to target location. If {@code prompt} is true then 29 | * prompt user to overwrite target if it exists. The {@code preserve} 30 | * parameter determines if file attributes should be copied/preserved. 31 | */ 32 | static void copyFile(Path source, Path target, boolean prompt, boolean preserve) { 33 | CopyOption[] options = (preserve) ? 34 | new CopyOption[] { COPY_ATTRIBUTES, REPLACE_EXISTING } : 35 | new CopyOption[] { REPLACE_EXISTING }; 36 | if (!prompt || Files.notExists(target) || okayToOverwrite(target)) { 37 | try { 38 | Files.copy(source, target, options); 39 | } catch (IOException x) { 40 | System.err.format("Unable to copy: %s: %s%n", source, x); 41 | } 42 | } 43 | } 44 | 45 | /** 46 | * A {@code FileVisitor} that copies a file-tree ("cp -r") 47 | */ 48 | static class TreeCopier implements FileVisitor { 49 | private final Path source; 50 | private final Path target; 51 | private final boolean prompt; 52 | private final boolean preserve; 53 | 54 | TreeCopier(Path source, Path target, boolean prompt, boolean preserve) { 55 | this.source = source; 56 | this.target = target; 57 | this.prompt = prompt; 58 | this.preserve = preserve; 59 | } 60 | 61 | @Override 62 | public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { 63 | // before visiting entries in a directory we copy the directory 64 | // (okay if directory already exists). 65 | CopyOption[] options = (preserve) ? 66 | new CopyOption[] { COPY_ATTRIBUTES } : new CopyOption[0]; 67 | 68 | Path newdir = target.resolve(source.relativize(dir)); 69 | try { 70 | Files.copy(dir, newdir, options); 71 | } catch (FileAlreadyExistsException x) { 72 | // ignore 73 | } catch (IOException x) { 74 | System.err.format("Unable to create: %s: %s%n", newdir, x); 75 | return SKIP_SUBTREE; 76 | } 77 | return CONTINUE; 78 | } 79 | 80 | @Override 81 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { 82 | copyFile(file, target.resolve(source.relativize(file)), 83 | prompt, preserve); 84 | return CONTINUE; 85 | } 86 | 87 | @Override 88 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) { 89 | // fix up modification time of directory when done 90 | if (exc == null && preserve) { 91 | Path newdir = target.resolve(source.relativize(dir)); 92 | try { 93 | FileTime time = Files.getLastModifiedTime(dir); 94 | Files.setLastModifiedTime(newdir, time); 95 | } catch (IOException x) { 96 | System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x); 97 | } 98 | } 99 | return CONTINUE; 100 | } 101 | 102 | @Override 103 | public FileVisitResult visitFileFailed(Path file, IOException exc) { 104 | if (exc instanceof FileSystemLoopException) { 105 | System.err.println("cycle detected: " + file); 106 | } else { 107 | System.err.format("Unable to copy: %s: %s%n", file, exc); 108 | } 109 | return CONTINUE; 110 | } 111 | } 112 | 113 | static void usage() { 114 | System.err.println("java Copy [-ip] source... target"); 115 | System.err.println("java Copy -r [-ip] source-dir... target"); 116 | System.exit(-1); 117 | } 118 | 119 | public static void main(String[] args) throws IOException { 120 | boolean recursive = false; 121 | boolean prompt = false; 122 | boolean preserve = false; 123 | 124 | // process options 125 | int argi = 0; 126 | while (argi < args.length) { 127 | String arg = args[argi]; 128 | if (!arg.startsWith("-")) 129 | break; 130 | if (arg.length() < 2) 131 | usage(); 132 | for (int i=1; i 1) { 151 | source[i++] = Paths.get(args[argi++]); 152 | remaining--; 153 | } 154 | Path target = Paths.get(args[argi]); 155 | 156 | // check if target is a directory 157 | boolean isDir = Files.isDirectory(target); 158 | 159 | // copy each source file/directory to target 160 | for (i=0; i opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); 166 | TreeCopier tc = new TreeCopier(source[i], dest, prompt, preserve); 167 | Files.walkFileTree(source[i], opts, Integer.MAX_VALUE, tc); 168 | } else { 169 | // not recursive so source must not be a directory 170 | if (Files.isDirectory(source[i])) { 171 | System.err.format("%s: is a directory%n", source[i]); 172 | continue; 173 | } 174 | copyFile(source[i], dest, prompt, preserve); 175 | } 176 | } 177 | } 178 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/path/FileTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.path; 5 | 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | 9 | /** 10 | * @author waylau.com 11 | * @date 2016年1月19日 12 | */ 13 | public class FileTest { 14 | /** 15 | * @param args 16 | */ 17 | @SuppressWarnings("unused") 18 | public static void main(String[] args) { 19 | 20 | if (args.length < 1) { 21 | System.out.println("usage: FileTest file"); 22 | System.exit(-1); 23 | } 24 | 25 | // Converts the input string to a Path object. 26 | Path inputPath = Paths.get(args[0]); 27 | 28 | // Converts the input Path 29 | // to an absolute path. 30 | // Generally, this means prepending 31 | // the current working 32 | // directory. If this example 33 | // were called like this: 34 | // java FileTest foo 35 | // the getRoot and getParent methods 36 | // would return null 37 | // on the original "inputPath" 38 | // instance. Invoking getRoot and 39 | // getParent on the "fullPath" 40 | // instance returns expected values. 41 | Path fullPath = inputPath.toAbsolutePath(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/path/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月19日 7 | */ 8 | package com.waylau.essentialjava.io.path; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/scanning/ScanSum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.scanning; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.FileReader; 8 | import java.io.IOException; 9 | import java.util.Locale; 10 | import java.util.Scanner; 11 | 12 | /** 13 | * @author waylau.com 14 | * @date 2016年1月18日 15 | */ 16 | public class ScanSum { 17 | /** 18 | * @param args 19 | * @throws IOException 20 | */ 21 | public static void main(String[] args) throws IOException { 22 | Scanner s = null; 23 | double sum = 0; 24 | 25 | try { 26 | s = new Scanner(new BufferedReader(new FileReader("resources/usnumbers.txt"))); 27 | s.useLocale(Locale.US); 28 | 29 | while (s.hasNext()) { 30 | if (s.hasNextDouble()) { 31 | sum += s.nextDouble(); 32 | } else { 33 | s.next(); 34 | } 35 | } 36 | } finally { 37 | s.close(); 38 | } 39 | 40 | System.out.println(sum); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/scanning/ScanXan.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.io.scanning; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.FileReader; 8 | import java.io.IOException; 9 | import java.util.Scanner; 10 | 11 | /** 12 | * @author waylau.com 13 | * @date 2016年1月18日 14 | */ 15 | public class ScanXan { 16 | /** 17 | * @param args 18 | * @throws IOException 19 | */ 20 | public static void main(String[] args) throws IOException { 21 | Scanner s = null; 22 | 23 | try { 24 | s = new Scanner(new BufferedReader(new FileReader("resources/xanadu.txt"))); 25 | 26 | //s.useDelimiter(",\\s*"); 27 | 28 | while (s.hasNext()) { 29 | System.out.println(s.next()); 30 | } 31 | } finally { 32 | if (s != null) { 33 | s.close(); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/io/scanning/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年1月18日 7 | */ 8 | package com.waylau.essentialjava.io.scanning; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/echo/AsyncEchoServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.essentialjava.net.echo; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.net.StandardSocketOptions; 6 | import java.nio.ByteBuffer; 7 | import java.nio.channels.AsynchronousServerSocketChannel; 8 | import java.nio.channels.AsynchronousSocketChannel; 9 | import java.util.concurrent.Callable; 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.concurrent.ExecutorService; 12 | import java.util.concurrent.Executors; 13 | import java.util.concurrent.Future; 14 | /** 15 | * Asynchronous Echo Server(Asynchronous IO Model) 16 | * @author waylau.com 17 | * @date 2016年3月1日 18 | */ 19 | public class AsyncEchoServer { 20 | 21 | public static int DEFAULT_PORT = 7; 22 | 23 | public static void main(String[] args) throws IOException { 24 | int port; 25 | 26 | try { 27 | port = Integer.parseInt(args[0]); 28 | } catch (RuntimeException ex) { 29 | port = DEFAULT_PORT; 30 | } 31 | 32 | ExecutorService taskExecutor = Executors.newCachedThreadPool(Executors.defaultThreadFactory()); 33 | // create asynchronous server socket channel bound to the default group 34 | try (AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open()) { 35 | if (asynchronousServerSocketChannel.isOpen()) { 36 | // set some options 37 | asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024); 38 | asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); 39 | // bind the server socket channel to local address 40 | asynchronousServerSocketChannel.bind(new InetSocketAddress(port)); 41 | // display a waiting message while ... waiting clients 42 | System.out.println("Waiting for connections ..."); 43 | while (true) { 44 | Future asynchronousSocketChannelFuture = asynchronousServerSocketChannel 45 | .accept(); 46 | try { 47 | final AsynchronousSocketChannel asynchronousSocketChannel = asynchronousSocketChannelFuture 48 | .get(); 49 | Callable worker = new Callable() { 50 | @Override 51 | public String call() throws Exception { 52 | String host = asynchronousSocketChannel.getRemoteAddress().toString(); 53 | System.out.println("Incoming connection from: " + host); 54 | final ByteBuffer buffer = ByteBuffer.allocateDirect(1024); 55 | // transmitting data 56 | while (asynchronousSocketChannel.read(buffer).get() != -1) { 57 | buffer.flip(); 58 | asynchronousSocketChannel.write(buffer).get(); 59 | if (buffer.hasRemaining()) { 60 | buffer.compact(); 61 | } else { 62 | buffer.clear(); 63 | } 64 | } 65 | asynchronousSocketChannel.close(); 66 | System.out.println(host + " was successfully served!"); 67 | return host; 68 | } 69 | }; 70 | taskExecutor.submit(worker); 71 | } catch (InterruptedException | ExecutionException ex) { 72 | System.err.println(ex); 73 | System.err.println("\n Server is shutting down ..."); 74 | // this will make the executor accept no new threads 75 | // and finish all existing threads in the queue 76 | taskExecutor.shutdown(); 77 | // wait until all threads are finished 78 | while (!taskExecutor.isTerminated()) { 79 | } 80 | break; 81 | } 82 | } 83 | } else { 84 | System.out.println("The asynchronous server-socket channel cannot be opened!"); 85 | } 86 | } catch (IOException ex) { 87 | System.err.println(ex); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/echo/EchoClient.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.net.echo; 5 | 6 | import java.io.*; 7 | import java.net.*; 8 | 9 | /** 10 | * @author waylau.com 11 | * @date 2016年2月2日 12 | */ 13 | public class EchoClient { 14 | public static void main(String[] args) throws IOException { 15 | 16 | if (args.length != 2) { 17 | System.err.println( 18 | "Usage: java EchoClient "); 19 | System.exit(1); 20 | } 21 | 22 | String hostName = args[0]; 23 | int portNumber = Integer.parseInt(args[1]); 24 | 25 | try ( 26 | Socket echoSocket = new Socket(hostName, portNumber); 27 | PrintWriter out = 28 | new PrintWriter(echoSocket.getOutputStream(), true); 29 | BufferedReader in = 30 | new BufferedReader( 31 | new InputStreamReader(echoSocket.getInputStream())); 32 | BufferedReader stdIn = 33 | new BufferedReader( 34 | new InputStreamReader(System.in)) 35 | ) { 36 | String userInput; 37 | while ((userInput = stdIn.readLine()) != null) { 38 | out.println(userInput); 39 | System.out.println("echo: " + in.readLine()); 40 | } 41 | } catch (UnknownHostException e) { 42 | System.err.println("Don't know about host " + hostName); 43 | System.exit(1); 44 | } catch (IOException e) { 45 | System.err.println("Couldn't get I/O for the connection to " + 46 | hostName); 47 | System.exit(1); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/echo/EchoServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.net.echo; 5 | 6 | import java.io.*; 7 | import java.net.*; 8 | /** 9 | * @author waylau.com 10 | * @date 2016年2月2日 11 | */ 12 | public class EchoServer { 13 | public static int DEFAULT_PORT = 7; 14 | 15 | public static void main(String[] args) throws IOException { 16 | 17 | int port; 18 | 19 | try { 20 | port = Integer.parseInt(args[0]); 21 | } catch (RuntimeException ex) { 22 | port = DEFAULT_PORT; 23 | } 24 | 25 | try ( 26 | ServerSocket serverSocket = 27 | new ServerSocket(port); 28 | Socket clientSocket = serverSocket.accept(); 29 | PrintWriter out = 30 | new PrintWriter(clientSocket.getOutputStream(), true); 31 | BufferedReader in = new BufferedReader( 32 | new InputStreamReader(clientSocket.getInputStream())); 33 | ) { 34 | String inputLine; 35 | while ((inputLine = in.readLine()) != null) { 36 | out.println(inputLine); 37 | } 38 | } catch (IOException e) { 39 | System.out.println("Exception caught when trying to listen on port " 40 | + port + " or listening for a connection"); 41 | System.out.println(e.getMessage()); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/echo/EchoServerHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.net.echo; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.io.PrintWriter; 10 | import java.net.Socket; 11 | 12 | /** 13 | * EchoServer Handler 14 | * @author waylau.com 15 | * @date 2016年3月1日 16 | */ 17 | public class EchoServerHandler implements Runnable { 18 | private Socket clientSocket; 19 | 20 | public EchoServerHandler(Socket clientSocket) { 21 | this.clientSocket = clientSocket; 22 | } 23 | 24 | /* 25 | * (non-Javadoc) 26 | * 27 | * @see java.lang.Runnable#run() 28 | */ 29 | @Override 30 | public void run() { 31 | try (PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); 32 | BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));) { 33 | 34 | String inputLine; 35 | while ((inputLine = in.readLine()) != null) { 36 | out.println(inputLine); 37 | } 38 | } catch (IOException e) { 39 | System.out.println(e.getMessage()); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/echo/MultiThreadEchoServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.net.echo; 5 | 6 | import java.io.IOException; 7 | import java.net.ServerSocket; 8 | import java.net.Socket; 9 | 10 | 11 | /** 12 | * EchoServer(MultiThread Model) 13 | * @author waylau.com 14 | * @date 2016年3月1日 15 | */ 16 | public class MultiThreadEchoServer { 17 | public static int DEFAULT_PORT = 7; 18 | 19 | public static void main(String[] args) throws IOException { 20 | 21 | int port; 22 | 23 | try { 24 | port = Integer.parseInt(args[0]); 25 | } catch (RuntimeException ex) { 26 | port = DEFAULT_PORT; 27 | } 28 | Socket clientSocket = null; 29 | try (ServerSocket serverSocket = new ServerSocket(port);) { 30 | while (true) { 31 | clientSocket = serverSocket.accept(); 32 | 33 | // MultiThread 34 | new Thread(new EchoServerHandler(clientSocket)).start(); 35 | } 36 | } catch (IOException e) { 37 | System.out.println( 38 | "Exception caught when trying to listen on port " + port + " or listening for a connection"); 39 | System.out.println(e.getMessage()); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/echo/NonBlokingEchoServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.net.echo; 5 | 6 | import java.io.IOException; 7 | import java.nio.channels.SocketChannel; 8 | import java.nio.ByteBuffer; 9 | import java.nio.channels.SelectionKey; 10 | import java.nio.channels.Selector; 11 | import java.nio.channels.ServerSocketChannel; 12 | import java.net.InetSocketAddress; 13 | import java.util.Iterator; 14 | import java.util.Set; 15 | 16 | /** 17 | * Non-Bloking EchoServer(Non-Bloking IO Model) 18 | * 19 | * @author waylau.com 20 | * @date 2016年3月1日 21 | */ 22 | public class NonBlokingEchoServer { 23 | public static int DEFAULT_PORT = 7; 24 | 25 | public static void main(String[] args) throws IOException { 26 | 27 | int port; 28 | 29 | try { 30 | port = Integer.parseInt(args[0]); 31 | } catch (RuntimeException ex) { 32 | port = DEFAULT_PORT; 33 | } 34 | System.out.println("Listening for connections on port " + port); 35 | 36 | ServerSocketChannel serverChannel; 37 | Selector selector; 38 | try { 39 | serverChannel = ServerSocketChannel.open(); 40 | InetSocketAddress address = new InetSocketAddress(port); 41 | serverChannel.bind(address); 42 | serverChannel.configureBlocking(false); 43 | selector = Selector.open(); 44 | serverChannel.register(selector, SelectionKey.OP_ACCEPT); 45 | } catch (IOException ex) { 46 | ex.printStackTrace(); 47 | return; 48 | } 49 | 50 | while (true) { 51 | try { 52 | selector.select(); 53 | } catch (IOException ex) { 54 | ex.printStackTrace(); 55 | break; 56 | } 57 | Set readyKeys = selector.selectedKeys(); 58 | Iterator iterator = readyKeys.iterator(); 59 | while (iterator.hasNext()) { 60 | SelectionKey key = iterator.next(); 61 | iterator.remove(); 62 | try { 63 | if (key.isAcceptable()) { 64 | ServerSocketChannel server = (ServerSocketChannel) key.channel(); 65 | SocketChannel client = server.accept(); 66 | System.out.println("Accepted connection from " + client); 67 | client.configureBlocking(false); 68 | SelectionKey clientKey = client.register(selector, 69 | SelectionKey.OP_WRITE | SelectionKey.OP_READ); 70 | ByteBuffer buffer = ByteBuffer.allocate(100); 71 | clientKey.attach(buffer); 72 | } 73 | if (key.isReadable()) { 74 | SocketChannel client = (SocketChannel) key.channel(); 75 | ByteBuffer output = (ByteBuffer) key.attachment(); 76 | client.read(output); 77 | } 78 | if (key.isWritable()) { 79 | SocketChannel client = (SocketChannel) key.channel(); 80 | ByteBuffer output = (ByteBuffer) key.attachment(); 81 | output.flip(); 82 | client.write(output); 83 | 84 | output.compact(); 85 | } 86 | } catch (IOException ex) { 87 | key.cancel(); 88 | try { 89 | key.channel().close(); 90 | } catch (IOException cex) { 91 | } 92 | } 93 | } 94 | } 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/echo/ThreadPoolEchoServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.net.echo; 5 | 6 | import java.io.IOException; 7 | import java.net.ServerSocket; 8 | import java.net.Socket; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | 12 | /** 13 | * EchoServer(ThreadPool Model) 14 | * @author waylau.com 15 | * @date 2016年3月1日 16 | */ 17 | public class ThreadPoolEchoServer { 18 | public static int DEFAULT_PORT = 7; 19 | 20 | public static void main(String[] args) throws IOException { 21 | 22 | int port; 23 | 24 | try { 25 | port = Integer.parseInt(args[0]); 26 | } catch (RuntimeException ex) { 27 | port = DEFAULT_PORT; 28 | } 29 | ExecutorService threadPool = Executors.newFixedThreadPool(5); 30 | Socket clientSocket = null; 31 | try (ServerSocket serverSocket = new ServerSocket(port);) { 32 | while (true) { 33 | clientSocket = serverSocket.accept(); 34 | 35 | // Thread Pool 36 | threadPool.submit(new Thread(new EchoServerHandler(clientSocket))); 37 | } 38 | } catch (IOException e) { 39 | System.out.println( 40 | "Exception caught when trying to listen on port " + port + " or listening for a connection"); 41 | System.out.println(e.getMessage()); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/echo/package-info.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 4 | */ 5 | /** 6 | * @author waylau.com 7 | * @date 2016年2月2日 8 | */ 9 | package com.waylau.essentialjava.net.echo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/net/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2016年2月2日 7 | */ 8 | package com.waylau.essentialjava.net; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/bicycledemo/Bicycle.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.object.bicycledemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月25日 9 | */ 10 | class Bicycle { 11 | 12 | int cadence = 0; 13 | int speed = 0; 14 | int gear = 1; 15 | 16 | void changeCadence(int newValue) { 17 | cadence = newValue; 18 | } 19 | 20 | void changeGear(int newValue) { 21 | gear = newValue; 22 | } 23 | 24 | void speedUp(int increment) { 25 | speed = speed + increment; 26 | } 27 | 28 | void applyBrakes(int decrement) { 29 | speed = speed - decrement; 30 | } 31 | 32 | void printStates() { 33 | System.out.println("cadence:" + 34 | cadence + " speed:" + 35 | speed + " gear:" + gear); 36 | } 37 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/bicycledemo/BicycleDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.object.bicycledemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月25日 9 | */ 10 | class BicycleDemo { 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | // Create two different 16 | // Bicycle objects 17 | Bicycle bike1 = new Bicycle(); 18 | Bicycle bike2 = new Bicycle(); 19 | 20 | // Invoke methods on 21 | // those objects 22 | bike1.changeCadence(50); 23 | bike1.speedUp(10); 24 | bike1.changeGear(2); 25 | bike1.printStates(); 26 | 27 | bike2.changeCadence(50); 28 | bike2.speedUp(10); 29 | bike2.changeGear(2); 30 | bike2.changeCadence(40); 31 | bike2.speedUp(10); 32 | bike2.changeGear(3); 33 | bike2.printStates(); 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/bicycledemo/MountainBike.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.object.bicycledemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月25日 9 | */ 10 | class MountainBike extends Bicycle { 11 | 12 | // new fields and methods defining 13 | // a mountain bike would go here 14 | } 15 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/bicycledemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月25日 7 | */ 8 | package com.waylau.essentialjava.object.bicycledemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/enumdemo/Day.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.object.enumdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | public enum Day { 11 | SUNDAY, MONDAY, TUESDAY, WEDNESDAY, 12 | THURSDAY, FRIDAY, SATURDAY 13 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/enumdemo/EnumTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.object.enumdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | class EnumTest { 11 | 12 | Day day; 13 | 14 | public EnumTest(Day day) { 15 | this.day = day; 16 | } 17 | 18 | public void tellItLikeItIs() { 19 | switch (day) { 20 | case MONDAY: 21 | System.out.println("Mondays are bad."); 22 | break; 23 | 24 | case FRIDAY: 25 | System.out.println("Fridays are better."); 26 | break; 27 | 28 | case SATURDAY: case SUNDAY: 29 | System.out.println("Weekends are best."); 30 | break; 31 | 32 | default: 33 | System.out.println("Midweek days are so-so."); 34 | break; 35 | } 36 | } 37 | 38 | public static void main(String[] args) { 39 | EnumTest firstDay = new EnumTest(Day.MONDAY); 40 | firstDay.tellItLikeItIs(); 41 | EnumTest thirdDay = new EnumTest(Day.WEDNESDAY); 42 | thirdDay.tellItLikeItIs(); 43 | EnumTest fifthDay = new EnumTest(Day.FRIDAY); 44 | fifthDay.tellItLikeItIs(); 45 | EnumTest sixthDay = new EnumTest(Day.SATURDAY); 46 | sixthDay.tellItLikeItIs(); 47 | EnumTest seventhDay = new EnumTest(Day.SUNDAY); 48 | seventhDay.tellItLikeItIs(); 49 | } 50 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/enumdemo/Planet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.object.enumdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月28日 9 | */ 10 | public enum Planet { 11 | MERCURY (3.303e+23, 2.4397e6), 12 | VENUS (4.869e+24, 6.0518e6), 13 | EARTH (5.976e+24, 6.37814e6), 14 | MARS (6.421e+23, 3.3972e6), 15 | JUPITER (1.9e+27, 7.1492e7), 16 | SATURN (5.688e+26, 6.0268e7), 17 | URANUS (8.686e+25, 2.5559e7), 18 | NEPTUNE (1.024e+26, 2.4746e7); 19 | 20 | private final double mass; // in kilograms 21 | private final double radius; // in meters 22 | Planet(double mass, double radius) { 23 | this.mass = mass; 24 | this.radius = radius; 25 | } 26 | // private double mass() { return mass; } 27 | // private double radius() { return radius; } 28 | 29 | // universal gravitational constant (m3 kg-1 s-2) 30 | public static final double G = 6.67300E-11; 31 | 32 | double surfaceGravity() { 33 | return G * mass / (radius * radius); 34 | } 35 | double surfaceWeight(double otherMass) { 36 | return otherMass * surfaceGravity(); 37 | } 38 | public static void main(String[] args) { 39 | if (args.length != 1) { 40 | System.err.println("Usage: java Planet "); 41 | System.exit(-1); 42 | } 43 | double earthWeight = Double.parseDouble(args[0]); 44 | double mass = earthWeight/EARTH.surfaceGravity(); 45 | for (Planet p : Planet.values()) 46 | System.out.printf("Your weight on %s is %f%n", 47 | p, p.surfaceWeight(mass)); 48 | } 49 | } -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/enumdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月28日 7 | */ 8 | package com.waylau.essentialjava.object.enumdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/interfacebiycledemo/ACMEBicycle.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.object.interfacebiycledemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月25日 9 | */ 10 | class ACMEBicycle implements Bicycle { 11 | 12 | int cadence = 0; 13 | int speed = 0; 14 | int gear = 1; 15 | 16 | // The compiler will now require that methods 17 | // changeCadence, changeGear, speedUp, and applyBrakes 18 | // all be implemented. Compilation will fail if those 19 | // methods are missing from this class. 20 | 21 | /* 22 | * (non-Javadoc) 23 | * 24 | * @see 25 | * com.waylau.essentialjava.interfaceBicycleDemo.Bicycle#changeCadence(int) 26 | */ 27 | @Override 28 | public void changeCadence(int newValue) { 29 | // TODO Auto-generated method stub 30 | 31 | } 32 | 33 | /* 34 | * (non-Javadoc) 35 | * 36 | * @see 37 | * com.waylau.essentialjava.interfaceBicycleDemo.Bicycle#changeGear(int) 38 | */ 39 | @Override 40 | public void changeGear(int newValue) { 41 | // TODO Auto-generated method stub 42 | 43 | } 44 | 45 | /* 46 | * (non-Javadoc) 47 | * 48 | * @see com.waylau.essentialjava.interfaceBicycleDemo.Bicycle#speedUp(int) 49 | */ 50 | @Override 51 | public void speedUp(int increment) { 52 | // TODO Auto-generated method stub 53 | 54 | } 55 | 56 | /* 57 | * (non-Javadoc) 58 | * 59 | * @see 60 | * com.waylau.essentialjava.interfaceBicycleDemo.Bicycle#applyBrakes(int) 61 | */ 62 | @Override 63 | public void applyBrakes(int decrement) { 64 | // TODO Auto-generated method stub 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/interfacebiycledemo/Bicycle.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.object.interfacebiycledemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月25日 9 | */ 10 | interface Bicycle { 11 | 12 | // wheel revolutions per minute 13 | void changeCadence(int newValue); 14 | 15 | void changeGear(int newValue); 16 | 17 | void speedUp(int increment); 18 | 19 | void applyBrakes(int decrement); 20 | } 21 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/object/interfacebiycledemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月26日 7 | */ 8 | package com.waylau.essentialjava.object.interfacebiycledemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/arithmeticdemo/ArithmeticDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.arithmeticdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月26日 9 | */ 10 | class ArithmeticDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int result = 1 + 2; 17 | // result is now 3 18 | System.out.println("1 + 2 = " + result); 19 | int original_result = result; 20 | 21 | result = result - 1; 22 | // result is now 2 23 | System.out.println(original_result + " - 1 = " + result); 24 | original_result = result; 25 | 26 | result = result * 2; 27 | // result is now 4 28 | System.out.println(original_result + " * 2 = " + result); 29 | original_result = result; 30 | 31 | result = result / 2; 32 | // result is now 2 33 | System.out.println(original_result + " / 2 = " + result); 34 | original_result = result; 35 | 36 | result = result + 8; 37 | // result is now 10 38 | System.out.println(original_result + " + 8 = " + result); 39 | original_result = result; 40 | 41 | result = result % 7; 42 | // result is now 3 43 | System.out.println(original_result + " % 7 = " + result); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/arithmeticdemo/ConcatDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.arithmeticdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月26日 9 | */ 10 | class ConcatDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | String firstString = "This is"; 17 | String secondString = " a concatenated string."; 18 | String thirdString = firstString+secondString; 19 | System.out.println(thirdString); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/arithmeticdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月26日 7 | */ 8 | package com.waylau.essentialjava.operator.arithmeticdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/bitdemo/BitDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.bitdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class BitDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int bitmask = 0x000F; 17 | int val = 0x2222; 18 | // prints "2" 19 | System.out.println(val & bitmask); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/bitdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月27日 7 | */ 8 | package com.waylau.essentialjava.operator.bitdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/conditionaldemo/ConditionalDemo1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.conditionaldemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class ConditionalDemo1 { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int value1 = 1; 17 | int value2 = 2; 18 | if ((value1 == 1) && (value2 == 2)) 19 | System.out.println("value1 is 1 AND value2 is 2"); 20 | if ((value1 == 1) || (value2 == 1)) 21 | System.out.println("value1 is 1 OR value2 is 1"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/conditionaldemo/ConditionalDemo2.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.conditionaldemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class ConditionalDemo2 { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int value1 = 1; 17 | int value2 = 2; 18 | int result; 19 | boolean someCondition = true; 20 | result = someCondition ? value1 : value2; 21 | 22 | System.out.println(result); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/conditionaldemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月27日 7 | */ 8 | package com.waylau.essentialjava.operator.conditionaldemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/instanceofdemo/InstanceofDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.instanceofdemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class InstanceofDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | 17 | // Must qualify the allocation with an enclosing instance of type InstanceofDemo 18 | Parent obj1 = new InstanceofDemo().new Parent(); 19 | Parent obj2 = new InstanceofDemo().new Child(); 20 | 21 | System.out.println("obj1 instanceof Parent: " 22 | + (obj1 instanceof Parent)); 23 | System.out.println("obj1 instanceof Child: " 24 | + (obj1 instanceof Child)); 25 | System.out.println("obj1 instanceof MyInterface: " 26 | + (obj1 instanceof MyInterface)); 27 | System.out.println("obj2 instanceof Parent: " 28 | + (obj2 instanceof Parent)); 29 | System.out.println("obj2 instanceof Child: " 30 | + (obj2 instanceof Child)); 31 | System.out.println("obj2 instanceof MyInterface: " 32 | + (obj2 instanceof MyInterface)); 33 | } 34 | 35 | class Parent {} 36 | class Child extends Parent implements MyInterface {} 37 | interface MyInterface {} 38 | } 39 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/instanceofdemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月27日 7 | */ 8 | package com.waylau.essentialjava.operator.instanceofdemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/relationaldemo/ComparisonDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.relationaldemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月27日 9 | */ 10 | class ComparisonDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int value1 = 1; 17 | int value2 = 2; 18 | if (value1 == value2) 19 | System.out.println("value1 == value2"); 20 | if (value1 != value2) 21 | System.out.println("value1 != value2"); 22 | if (value1 > value2) 23 | System.out.println("value1 > value2"); 24 | if (value1 < value2) 25 | System.out.println("value1 < value2"); 26 | if (value1 <= value2) 27 | System.out.println("value1 <= value2"); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/relationaldemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月27日 7 | */ 8 | package com.waylau.essentialjava.operator.relationaldemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/unarydemo/PrePostDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.unarydemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月26日 9 | */ 10 | class PrePostDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int i = 3; 17 | i++; 18 | // prints 4 19 | System.out.println(i); 20 | ++i; 21 | // prints 5 22 | System.out.println(i); 23 | // prints 6 24 | System.out.println(++i); 25 | // prints 6 26 | System.out.println(i++); 27 | // prints 7 28 | System.out.println(i); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/unarydemo/UnaryDemo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.essentialjava.operator.unarydemo; 5 | 6 | /** 7 | * @author waylau.com 8 | * @date 2015年12月26日 9 | */ 10 | class UnaryDemo { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | int result = +1; 17 | // result is now 1 18 | System.out.println(result); 19 | 20 | result--; 21 | // result is now 0 22 | System.out.println(result); 23 | 24 | result++; 25 | // result is now 1 26 | System.out.println(result); 27 | 28 | result = -result; 29 | // result is now -1 30 | System.out.println(result); 31 | 32 | boolean success = false; 33 | // false 34 | System.out.println(success); 35 | // true 36 | System.out.println(!success); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/operator/unarydemo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月26日 7 | */ 8 | package com.waylau.essentialjava.operator.unarydemo; -------------------------------------------------------------------------------- /samples/essential-java-demos/src/com/waylau/essentialjava/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * @author waylau.com 6 | * @date 2015年12月25日 7 | */ 8 | package com.waylau.essentialjava; --------------------------------------------------------------------------------