java 编程思想 5th 总结
java 编程思想 5th 总结
原文书籍
书中的代码
阅读时的记录
-
java 中, 动态绑定是默认行为,不需要额外的关键字来实现多态性。
-
这种把子类当成其基类来处理的过程叫做“向上转型”(upcasting)。在面向对象的编程里,经常利用这种方法来给程序解耦。
-
Java 允许在类中定义一个名为 finalize() 的方法 来释放不是 new 出来的对象空间。当垃圾回收器准备回收对象的内存时,首先会调用其 finalize() 方法,并在下一轮的垃圾回收动作发生时,才会真正回收对象占用的内存。
-
包内包含一组类,它们被组织在一个单独的命名空间(namespace)下。
-
每个编译单元中只能有一个 public 类,否则编译器不接受, 默认是 private 类。
-
在 Java 中,可运行程序是一组 .class 文件,它们可以打包压缩成一个 Java 文档文件(JAR,使用 jar 文档生成器)。Java 解释器负责查找、加载和解释这些文件。
-
类库是一组类文件。每个源文件通常都含有一个 public 类和任意数量的非 public 类,因此每个文件都有一个 public 组件。如果把这些组件集中在一起,就需要使用关键字 package。
-
默认访问权限没有关键字,通常被称为包访问权限(package access)(有时也称为 friendly)。
-
@Override 注释防止你意外地重载。
-
空白 final 指的是没有初始化值的 final 属性。编译器确保空白 final 在使用前必须被初始化。这样既能使一个类的每个对象的 final 属性值不同,也能保持它的不变性。
-
接口只允许 public 方法,如果不加访问修饰符的话,接口的方法不是 friendly 而是 public。
-
Java 8 允许接口包含默认方法和静态方法。
-
private 方法可以当作是 final 的,对于派生类来说是隐蔽的, 派生类可声明一个全新的 方法。
-
如果一个方法是静态(static)的,它的行为就不具有多态性。
- 静态的方法只与类关联,与单个的对象无关。
-
普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象。
-
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
-
内部类允许继承多个非接口类型.
-
闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。
- 内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括 private 成员。
- 通过内部类提供闭包的功能是优良的解决方案,它比指针更灵活、更安全。
-
函数式编程语言操纵代码片段就像操作数据一样容易。 虽然 Java 不是函数式语言,但 Java 8 Lambda 表达式和方法引用 (Method References) 允许你以函数式编程。
- OO(object oriented,面向对象)是抽象数据,FP(functional programming,函数式编程)是抽象行为。
- “不可变对象和无副作用”范式解决了并发编程中最基本和最棘手的问题之一。
- 函数组合(Function Composition)意为“多个函数组合成新函数”。它通常是函数式编程的基本组成部分。
-
java Lambda 表达式语法:
- 当只用一个参数,可以不需要括号 ()。 然而,这是一个特例。
- 正常情况使用括号 () 包裹参数。 为了保持一致性,也可以使用括号 () 包裹单个参数,虽然这种情况并不常见。
- 如果没有参数,则必须使用括号 () 表示空参数列表。
- 对于多个参数,将参数列表放在括号 () 中。
- 单行 Lambda 表达式不能使用 return 关键字,多行需要使用 return。
- 递归的 Lambda 表达式中的递归方法必须是实例变量或静态变量。
-
未绑定的方法引用: 未绑定的方法引用是指没有关联对象的普通(非静态)方法。在使用未绑定的引用之前,必须先提供对象。
- 使用未绑定的引用时,函数方法的签名(接口中的单个方法)不再与方法引用的签名完全匹配。 理由是:你需要一个对象来调用方法。
-
构造函数只有一个相同名称: ::new, 但在每种情况下都赋值给不同的接口,编译器可以检测并知道从那个构造函数引用(编译器能识别并调用构造函数)。
-
Lambda 表达式包含类型推导(编译器会自动推导出类型信息,避免了程序员显式地声明)。
-
高阶函数(Higher-order Function)只是一个消费或产生函数的函数。
-
流式编程: 集合优化了对象的存储,而流和对象的处理有关。
- 流是一系列与特定存储机制无关的元素。
- 当 Lambda 表达式和方法引用(method references)和流一起使用的时候会让人感觉自成一体。流使得 Java 8 更具吸引力。
- 流可以在不使用赋值或可变数据的情况下对有状态的系统建模。
- 流是懒加载的。
- 在接口中添加被 default(默认)修饰的方法。
-
e.printStackTrace() 信息就会被输出到标准错误流。
-
应该在下列情况下使用异常:
- 尽可能使用 try-with-resource。
- 在恰当的级别处理问题。(在知道该如何处理的情况下才捕获异常。)
- 解决问题并且重新调用产生异常的方法。
- 进行少许修补,然后绕过异常发生的地方继续执行。
- 用别的数据进行计算,以代替方法预计会返回的值。
- 把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层。
- 把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层。
- 终止程序。
- 进行简化。(如果你的异常模式使问题变得太复杂,那用起来会非常痛苦也很烦人。)
- 让类库和程序更安全。(这既是在为调试做短期投资,也是在为程序的健壮性做长期投资。
-
异常处理的优点之一就是它使得你可以在某处集中精力处理你要解决的问题,而在另一处处理你编写的这段代码中产生的错误。尽管异常通常被认为是一种工具,使得你可以在运行时报告错误并从错误中恢复。
-
Java是一个静态类型的语言,程序员经常对一种编程语言明显的安全性感到过于舒适,“能通过编译器,那就是没问题的”。但静态类型检查是一种非常局限性的测试,只是说明编译器接受你代码中的语法和基本类型规则,并不意味着你的代码达到程序的目标。随着你代码经验的丰富,你逐渐了解到你的代码从来没有满足过这些目标。迈向代码校验的第一步就是创建测试,针对你的目标检查代码的行为。
-
JDB 对于学习调试和执行简单的调试任务来说是有用的,而且知道只要安装了 JDK 就可以使用 JDB 是有帮助的。
-
优雅与清晰很重要,正是它们区别了成功的解决方案与失败的解决方案。
-
注解在一定程度上是把元数据和源代码文件结合在一起的趋势所激发的,而不是保存在外部文档。
-
注解使得我们可以以编译器验证的格式存储程序的额外信息。注解可以生成描述符文件,甚至是新的类定义,并且有助于减轻编写“样板”代码的负担。
- @Override:表示当前的方法定义将覆盖基类的方法。如果你不小心拼写错误,或者方法签名被错误拼写的时候,编译器就会发出错误提示.
- @Deprecated:如果使用该注解的元素被调用,编译器就会发出警告信息。
- @SuppressWarnings:关闭不当的编译器警告信息。
- @SafeVarargs:在 Java 7 中加入用于禁止对具有泛型varargs参数的方法或构造函数的调用方发出警告。
- @FunctionalInterface:Java 8 中加入用于表示类型声明为函数式接口
-
@Target 定义你的注解可以应用在哪里(例如是方法还是字段). @Retention 定义了注解在哪里可用.
-
适配器允许代码接受已有的接口产生需要的接口。
-
虚线箭头表示实现关系,实线箭头表示继承关系。
-
不要在新代码中使用遗留类 Vector ,Hashtable 和 Stack.
-
可以通过 Stream.of() 很容易地将一组元素转化成为流.
-
每个集合都可以通过调用 stream() 方法来产生一个流。
-
boxed() 流操作将会自动地把基本类型包装成为对应的装箱类型。
-
e.printStackTrace(System.out); 打印异常链, 可以在异常处理程序后面加上 finally 子句 进行清理。
-
Try-With-Resources 用法:
- 需要资源清理。
- 需要在特定的时刻进行资源清理,比如你离开作用域的时候(在通常情况下意味着通过异常进行清理)。
- Java 7 引入了 try-with-resources 语法.
- 可以跟一个带括号的定义, 括号内的部分称为资源规范头(resource specification header)。
- 在 try-with-resources 定义子句中创建的对象(在括号内)必须实现 java.lang.AutoCloseable 接口,这个接口有一个方法:close()。
- try-with-resources 里面的 try 语句块可以不包含 catch 或者 finally 语句而独立存在.
-
String 对象是不可变的。查看 JDK 文档你就会发现,String 类中每一个看起来会修改 String 值的方法,实际上都是创建了一个全新的 String 对象,以包含修改后的字符串内容。而最初的 String 对象则丝毫未动。
-
Java 还提供了另一种方法来生成类对象的引用:类字面常量。对上述程序来说,就像这样:FancyToy.class;
-
一个动态 instanceof 函数
-
必须在编译时知道类型,才能使用 RTTI 检测它,并对信息做一些有用的事情。换句话说,编译器必须知道你使用的所有类。
-
类 Class 支持反射的概念, java.lang.reflect 库中包含类 Field、Method 和 Constructor(每一个都实现了 Member 接口)。
-
可以使用 Constructor 创建新对象,get() 和 set() 方法读取和修改与 Field 对象关联的字段,invoke() 方法调用与 Method 对象关联的方法。
-
匿名对象的类信息可以在运行时完全确定,编译时不需要知道任何信息。
-
RTTI 和反射的真正区别在于,使用 RTTI 时,编译器在编译时会打开并检查 .class 文件。
- 通过反射,.class 文件在编译时不可用;它由运行时环境打开并检查。
- 反射提供了一种方法,可以简单地编写一个工具类自动地向你展示所有的接口.
-
invokeAll()才会返回一个Future列表,每个任务一个Future。Future是Java 5中引入的机制,允许你提交任务而无需等待它完成。
-
支持Java 8的CompletableFuture。
-
添加AtomicBoolean标志,告诉任务清理自己并退出。
-
并行流和 CompletableFutures 是 Java 并发工具箱中最先进发达的技术。
- 很容易把数据分解成相同的、易于处理的各个部分时,使用并行流方法处理最为合适。
- 比起面向数据,CompletableFutures 更像是面向任务的。