Java Exceptions

Exception-handling 假如调用了一个不是自己写的方法, 该方法执行某些有风险的任务(当然,自己写的也可能会有风险),可能会在运行期间出状况,那么就必须认识到该方法是有风险的, 要写出可以在发生状况时做出应对的代码. 当程序出现错误时,假如继续运行下去已经没有意义(或者根本不可能继续),那么我们就想要中断正常的控制流程 - throws an exception。 Throwing Exceptions 比如当想从某ArrayMap中提取某个不存在的键值时, java自动抛出一个implicit exception $ java ExceptionDemo Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1 at ArrayMap.get(ArrayMap.java:38) at ExceptionDemo.main(ExceptionDemo.java:6) 如果想让自己的程序抛出更详细的信息, 可以在程序中加入explicit exception public V get(K key) { intlocation = findKey(key); if(location < 0) { throw newIllegalArgumentException("Key " + key + " does not exist in map."\); } return values[findKey(key)]; } $java ExceptionDemo Exception in thread "main" java.lang.IllegalArgumentException: Key yolp does not exist in map....

2017-05-29 · 3 min · Cong Chan

Java Immutability

An immutable data type is a data type whose instances cannot change in any observable way after instantiation. 比如String是immutable, Array是mutable. Immutable 的类型: String, Integer, Double, Color, Vector, Transaction, Point2D. Mutable: StringBuilder, Stack, Counter, Java array. public final class Vector { private final int N; private final double[] data; public Vector(double[] data) { this.N = data.length; this.data = new double[N]; for (int i = 0; i < N; i++) { // defensive copy of mutable instance variables this....

2017-05-29 · 1 min · Cong Chan

Java 堆栈

认识栈和堆的概念, 有助于了解变量的有效范围(scope),对象的建立,内存管理,线程(thread)和异常处理。 对象生存在可垃圾回收的堆(heap)上面,方法调用(方法的参数,局部变量的引用)的生存空间(stack)。 当JVM启动时,从底层操作系统取得一块内存, 以此区段来执行Java程序。 实例变量和局部变量 实例变量声明在类方法之外:实例变量保存在所属的对象中,位于堆上。如果实例变量是个对对象的引用,则引用和对象都在堆上。 public class Duck { int size; Mouth mouth; } 当新建一个Duck()时, Java必须在堆上帮它找位置, 保证空间足够存放该对象所有实例变量. 对于primitive数据类型的实例变量, Java会根据类型的大小为它们留下堆空间, int 32, long 64 .... 如果实例变量是个对象, 也就是Duck对象带有引用变量mouth, Java会在堆上留给Duck的专属空间只包含该引用变量, 不包含引用的那个对象. 被引用的对象, 只有实际实例化后, 才会在堆上占有一席之地mouth = new Mouth(), 该空间并不属于Duck. 局部变量声明在方法或方法的参数上:它们是暂时的,且生命周期只限于被放在栈上的这段时间(也就是方法调用至执行完毕位止)。所有局部变量存在栈上相对应的堆栈块中,故又称为栈变量。引用对象的局部变量(只是对对象的引用)和primitive数据类型变量也都放在栈上。 public void foo(int x) { int i = x + 3; } 不管是实例变量还是局部变量, 它们指向的对象本身在堆上。 栈 程序对方法的调用,以带有方法的状态的堆栈块的形式,不断堆在栈上面,当前被执行的方法处于栈顶。执行完毕的方法会出栈。递归调用太深层,会导致栈空间耗尽。 如果方法中有局部变量引用对象,那么该局部变量也是存在于栈中. 但被引用的对象还是运行在堆上面. 堆 变量的生命周期 局部变量只会存活在声明该变量的方法中, 其余方法无法接触到 实例变量的寿命与所属对象相同. 如果所属对象还活着, 则实例变量也会活着. public class Life { int size; // size 在类中一直可以用 public void setSize(int s) { size = s; } // 但 s 仅限于setSize中, 且在方法结束后消失 } 所以这里存在生命周期life和范围scope的概念差别...

2017-05-29 · 1 min · Cong Chan

Java 封装, 包, JAR, 权限控制

Encapsulation 封装是面向对象编程的基本原则之一,也是程序员处理复杂性一个方法。管理复杂性是编写大型程序时必须面对的主要挑战之一。 对抗复杂性的一些工具包括: Hierarchical abstraction: 创建一个个具有明确的 abstraction barriers 的抽象层 Abstraction Barriers:使用private, 保证对象内部不能被查看, 确保底层的复杂性不会暴露给外部世界。 “Design for change” (D. Parnas) Organize program around objects. Let objects decide how things are done. Hide information others don’t need. 大概的想法都是 - 程序应该被构建成模块化,可互换的片段,可以在不破坏系统的情况下进行交换。 封装就是构建在这种对外部隐藏信息的概念上。以细胞为类比:细胞内部可能非常复杂,由染色体,线粒体,核糖体等组成,但它完全被封装在一个单一模块中 - 抽象了内部的复杂性。 Module: A set of methods that work together as a whole to perform some task or set of related tasks. Encapsulated: A module is said to be encapsulated if its implementation is completely hidden, and it can be accessed only through a documented interface....

2017-05-29 · 2 min · Cong Chan

Java 抽象数据类型

Abstract Data Types (ADTS) ADTS 是由其行为属性定义的抽象类型, 跟如何实现无关. 堆栈 Stacks 和队列 Queues 是两种类似的线性集合。堆栈是后进先出的ADT:元素总是从数据结构的一端添加或删除。队列是先进先出的ADT. 二者都支持以下操作: push(): 加入 peek(): 返回下一个 poll(): 返回下一个并删除 Java的Deque(double ended queue, “deck”) 接口融合了堆栈和队列, 支持两端的元素插入和移除. ArrayDeque和LinkedListDeque都是实现deque这个接口,deque只是罗列了一些 methods,也即是一种合约,保证会实现的行为。而这些方法的具体实现则是由ArrayDeque和LinkedListDeque完成。从概念上讲,deque就是一种抽象的数据类型,只说会有什么行为,但不体现这些行为的具体实现方式,所以是抽象的。 优先级队列 priority queue 的每个元素都有一个与之关联的优先级,以决定从队列中元素操作的顺序。 三种方式实现Stack的push(Item x): 继承模式:extends LinkedList<Item>以使用其方法: public class ExtensionStack<Item> extends LinkedList<Item> { public void push(Item x) { add(x); } } 委托模式Delegation, 生成Linked List并调用其方法来达到目的 public class DelegationStack<Item> { private LinkedList<Item> L = new LinkedList<Item>(); public void push(Item x) { L.add(x); } } 类似委托模式, 只是这里可以利用任何实现了List接口的类, 如Linked List, ArrayList, 等等 public class StackAdapter<Item> { private List L; public StackAdapter(List<Item> worker) { L = worker; } public void push(Item x) { L....

2017-05-29 · 2 min · Cong Chan

Java 格式

Java格式化指令" 跟在%后面的都是格式化指令. % [argument number] [flags] [width] [.precision] type []内都是选择性的参数, 且必须按照顺序. argument number 当要格式化的参数超过一个, 这里指定是哪一个 flags 特定类型的特定选项, 如数字是否要加逗号或正负号 width 最小的字符数. 但不是总数, 输出可以超过此宽度, 若不足则会主动补零 .precision 精确度 type 类型标识 d decimal, 十进制整数 f 浮点数 x hexadecimal, 16进制 c character 如format("%, 6.1f", 33.000); 如果有多个待输出的参数, 可以把新的参数加到后面, 并对应两个不同的格式化设定, 也就是两个%格式指令 String s = String.format("%,.2f out of %,d", 999, 1000) 可变参数列表 可以看到格式化的参数似乎可以不断添加,如果用重载来实现会显得不现实。为了应对格式化的API,Java支持可变参数列表 varable argument list (vararg). 日期 日期格式化的类型是用t开头的两个字符表示 %tc 完整的日期与时间 Sun Nov 03 14:52:41 2018 %tr 只有时间 03:01:47 PM 周月日 Sunday, November 03, 通过组合而来...

2017-05-29 · 1 min · Cong Chan

Java 比较对象大小

对物品排序首先需要比较各个物品的大小, 这个大小的定义既可以是按照"自然顺序", 也可以是其他指定的特殊规则. Comparable Java的对象不能直接使用>, <, =进行比较. 在Python或C++中,当应用于不同对象类型时,比较运算符可以重新定义,但Java不支持。但可以借用接口继承,Java提供了一个Comparable接口,包含一个compareTo方法, 以保证任何实现该接口的类可以和其他同类做比较: /** Return negative if this < o. Return 0 if this equals o. Return positive if this > o. */ public interface Comparable<T> { public int compareTo(T obj); } 当有class需要与其他class比较时, 就实现这个接口: public class Dog implements Comparable<Dog> { ... public int compareTo(Dog uddaDog) { return this.size - uddaDog.size; } } Comparable定义了类用于比较的自然顺序(Natural order), 返回的是三种结果负整数, 0, 正整数, 分别对应小于, 等于和大于. Insertion.sort()不需要知道要排序的数组类型, 因为它直接调用数组成员自带的compareTo方法. Java的Integer, Double, String, Date, File数据类型都扩展了Comparable接口。...

2017-05-29 · 2 min · Cong Chan

Java 泛型

泛型 泛型意味着更好的类型安全性。主要目的是支持类型安全性的集合,让问题尽可能在编译阶段就能捉到。 泛型定义在类声明中 public class ArrayLiat<E> extends AbstractLìst<E> implements List<E> { public boolean add (E o); } E代表用来创建赋予初始ArrayList的类型 ArrayList<String> list = new ArrayList<String>; 编译器会自动把E看做String. 泛型方法 使用未定义在类声明的类型参数: 在返回类型之前指定泛型 maxKey: 返回给定ArrayMap中所有keys的最大值(仅在key可以比较的情况下)。假如这样写public static K maxKey(Map61B<K, V> map) { ... }会报错. 要将方法声明为泛型,必须在返回类型前面指定正式的类型参数 public static <K extends Comparable<K>, V> K maxKey(Map61B<K, V> map) { List<K> keylist = map.keys(); K largest = map.get(0); for (K k: keylist) { if (k.compareTo(largest)) { largest = k; } } return largest; } K extends Comparable<K> 保证了keys必须实现Comparable接口(也是一个generic接口), 并可以与其他K进行比较。...

2017-05-29 · 2 min · Cong Chan

Java 迭代 Iteration

Java提供了 foreach (enhanced for) 的循环简写语法: ArrayMap<String, Integer> am = new ArrayMap<String, Integer>(); for (String s : am) { System.out.println(s); } 实现的关键原理是使用Iterable接口使一个类变成可迭代的: 该接口包含一个iterator()方法用于返回一个Iterator对象。Iterator接口定义Iterator对象和hasNext(), next()方法来进行实际的迭代操作。 public class ArrayMap<K, V> implements Map61B<K, V>, Iterable<K> { private K[] keys; private V[] values; int size; public ArrayMap() { keys = (K[]) new Object[100]; values = (V[]) new Object[100]; size = 0; } @Override public Iterator<T> iterator() { return new KeyIterator(); } public class KeyIterator implements Iterator<K> { private int ptr; public KeyIterator() { ptr = 0; } public boolean hasNext() { return (ptr !...

2017-05-29 · 1 min · Cong Chan

Java 高阶函数和回调

Higher Order Functions A higher order function is a function that treats other functions as data. 在 Java 7 及之前的版本, memory boxes (variables) 不能包含指向 functions 的 pointers, 也就是无法给 functions 指定 types. 所以不能像Python一样直接把 function 作为参数传递到另一个 function 中。只能借用 interface: public interface IntUnaryFunction { int apply(int x); } // 定义一个方法 public class TenX implements IntUnaryFunction { /* Returns ten times the argument. */ public int apply(int x) { return 10 * x; } } // 高阶方法 public static int do_twice(IntUnaryFunction f, int x) { return f....

2017-05-29 · 1 min · Cong Chan