On Java 8
OO
-
在“问题空间”(问题实际存在的地方)的元素与“方案空间”(对实际问题进行建模的地方,如计算机)的元素之间建立理想的“一对一”的映射关系。
-
Java不需要sizeof()方法获取数据项被分配的字节大小,因为所有类型的大小在不同平台上是相同的。 —— Java本身就是一种“与平台无关”的语言。
控制符
-
移位运算符
>>
有“正”、“负”值:若值为正,则在高位插入 0;若值为负,则在高位插入 1。 -
Java也添加了一种“不分正负”的移位运算符(>>>),它使用了“零扩展”(zero extension):无论正负,都在高位插入0。
流程控制
- case语句能够堆叠在一起,为一段代码形成多重匹配,即只要符合多种条件中的一种,就执行那段特别的代码,如下写法:
Random rand = new Random(47);
for(int i = 0; i < 100; i++) {
int c = rand.nextInt(26) + 'a';
System.out.print((char)c + ", " + c + ": ");
switch(c) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': System.out.println("vowel");
break;
case 'y':
case 'w': System.out.println("Sometimes vowel");
break;
default: System.out.println("consonant");
}
}
Class & Abstract Class & Interface
-
如果不需要内部类对象与其外部类对象之间有联系,那么可以将内部类声明为static,这通常称为嵌套类。想要理解static应用于内部类时的含义,就必须记住,普通的内部类对象隐式地保存了一个引用,指向创建它的外部类对象。然而,当内部类是static的时,就不是这样了。嵌套类意味着:
-
- 要创建嵌套类的对象,并不需要其外部类的对象。
-
- 不能从嵌套类的对象中访问非静态的外部类对象。
-
-
static方法中不会存在this。不能在静态方法中调用非静态方法(反之可以)。
-
可变参数列表会被转变为数组。
-
可变参数列表不依赖于自动装箱,而使用的是基本类型。
-
带参数的构造函数:对基类构造函数的调用必须是派生类构造函数中的第一个操作。如果你写错了,编译器会提醒你。
-
无参构造函数:默认从基类 “向外” 调用无参构造函数,如果没有无参构造函数,编译器也会为你合成一个无参数构造函数,调用基类构造函数。
-
有可能的话,尽量不要调用类中的任何方法。在基类的构造器中能安全调用的只有基类的final方法(这也适用于可被看作是final的private方法)。
-
接口的典型使用是代表一个类的类型或一个形容词,如Runnable或Serializable,而抽象类通常是类层次结构的一部分或一件事物的类型,如String或 ActionHero。
-
为什么接口中的字段是static final的?final确保了不变性,static确保了所有接口公用。
-
内部类只能通过外部类的具体对象创建。
Override
-
private方法默认带有final属性,无法被重写,如果加上@Override会在编译期报错。
-
属性与静态方法不存在多态和Override,只和运行时类型有关。
-
Java5中引入了协变返回类型,这表示派生类的被重写方法可以返回基类方法返回类型的派生类型。
Overload
- 为什么不能根据返回值重载:调用一个方法且忽略返回值,Java编译器就不知道你想调用哪个方法。
访问权限
-
protected也提供包访问权限
-
final
- 防止子类通过覆写改变方法的行为。
- 在早期的Java实现中,如果将一个方法指明为final,就是同意编译器把对该方法的调用转化为内嵌调用。
-
类的访问权限可以是package或者public,但是内部类可以是private或者protected的。
Functional & Lambda
-
OO(object oriented,面向对象)是抽象数据,FP(functional programming,函数式编程)是抽象行为。
-
“不可变对象和无副作用” 范式,函数式语言作为并行编程的解决方案。
-
Java 8让函数式编程更简单,不过我们要确保一切是final的,同时你的所有方法和函数没有副作用。
-
通过传入所有方法都适用的 Consumer 来避免重复代码。
static void test(String testName, Consumer<Optional<String>> cos) { System.out.println(" === " + testName + " === "); cos.accept(...); }
-
我们不能通过传递null到of()来创建Optional对象。最安全的方法是,使用ofNullable()来优雅地处理null。
集合
异常
-
只是在当前的环境中还没有足够的信息来解决这个问题,所以就把这个问题提交到一个更高级别的环境中,在那里将作出正确的决定。
-
把异常情形与普通问题相区分很重要,所谓的普通问题是指,在当前环境下能得到足够的信息,总能处理这个错误。
普通问题不需要定义和抛出异常
-
如果只是把当前异常对象重新抛出,那么printStackTrace()方法显示的将是原来异常抛出点的调用栈信息,而并非重新抛出点的信息。要想更新这个信息,可以调用fillInStackTrace()方法,这将返回一个Throwable对象,它是通过把当前调用栈信息填入原来那个异常对象而建立的。
如果不通过fillInStackTrace,直接通过printStackTrace不方便定位是在哪里调用的发生异常的代码。
-
当涉及break和continue语句的时候,finally子句也会得到执行。请注意,如果把finally子句和带标签的break及continue配合使用,在Java里就没必要使用goto语句了。
不管什么情况,finally语句都可以执行。
-
如果StormyInning类在扩展Inning类的同时又实现了Storm接口,那么Storm里的event()方法就不能改变在Inning中的event()方法的异常接口。否则的话,在使用基类的时候就不能判断是否捕获了正确的异常,所以这也很合理。
-
异常范围的收缩
- 必须抛出和接口/抽象类中的一样的异常。
- 可以不必抛出和父类一样的异常。
所有调用了父类/接口的地方,换成任意实现类都不会影响原逻辑。
-
try-with-resource以创建顺序相反的顺序关闭它们。
-
“报告”功能是异常的精髓所在。