考点总结

软件构造的多维度视图

  • By phases: build- and run-time views
  • By dynamics: moment and period views
  • By levels: code and component views

考点总结_第1张图片

考点总结_第2张图片


内部/外部的质量指标

External quality factors: qualities such as speed or ease of use, whose presence or absence in a software product may be detected by its users. Other qualities applicable to a software product, such as being modular, or readable, are internal factors. In the end, only external factors matter. But the key to achieving these external factors is in the internal ones.

External quality factors:

  1. Correctness: perform their exact tasks, as defined by their specification, the prime quality. Approaches of ensuring correctness: Conditional, Testing and debugging, Defensive programming such as typing and assertions, Formal approach.
  2. Robustness: react appropriately to abnormal conditions. the system does not cause catastrophic(灾难性的) events; it should produce appropriate error messages, terminate its execution cleanly, or enter a so-called “graceful degradation(毁坏)” mode.

考点总结_第3张图片

  1. Extendibility: the ease of adapting software products to changes of specification. Two principles are essential for improving extendibility: Design simplicity, Decentralization.
  2. Reusability: serve for the construction of many different applications.
  3. Compatibility: the ease of combining software elements with others. Approaches: Standardized.
  4. Efficiency: place as few demands as possible on hardware resources. Efficiency does not matter much if the software is not correct.
  5. Portability (可移植性 ): the ease of transferring software products to various hardware and software environments.
  6. Ease of use.
  7. Functionality: the extent of possibilities provided by a system.
  8. Timeliness: the ability of a software system to be released when or before its users want it.
  9. Verifiability. Integrity. Repairability. Economy


Internal quality factors:

Internal quality factors are usually used as partial measurement of external quality factors.

  1. Source code related factors such as Lines of Code (LOC), Cyclomatic Complexity, etc
  2. Architecture-related factors such as coupling, cohesion, etc
  3. Readability, understandability and clearness
  4. Complexity
  5. Size


Necessary as tradeoffs between quality factors may be, one factor stands out from the rest: correctness.


软件配置管理SCM与版本控制系统VCS

SCM is the task of tracking and controlling changes in the software. SCM practices include revision control and the establishment of baselines.

A baseline is an agreed description of the attributes of a product, at a point in time, which serves as a basis for defining change.

Local VCS; Centralized VCS; Distributed VCS


Git/GitHub

考点总结_第4张图片

A Git repository has three parts: – .git directory (a repository storing all version control data) – Working directory (local file system) – Staging area (in memory)

Each file belongs to one of the following three states: – Modified (the file in working directory is different from the one in git repository, but is not in staging area) – Staged (the file is modified and has been added into the staging area) – Committed (the file keeps same in working directory and git directory)

考点总结_第5张图片

考点总结_第6张图片

Git 教程


软件构造的阶段划分、各阶段的构造活动

考点总结_第7张图片




基本数据类型、对象数据类型

考点总结_第8张图片

基本数据类型的包装类:Boolean, Integer, Short, Long, Character, Float, Double (immutable)


静态类型检查、动态类型检查

精度损失为静态错误(类型无法隐式转化,需要cast)。

static checking

  1. Syntax errors
  2. Wrong names
  3. Wrong number of arguments
  4. Wrong argument types
  5. Wrong return types

dynamic checking

  1. Illegal argument values
  2. Unrepresentable return values
  3. Out-of-range indexes
  4. Calling a method on a null object reference

Static checking tends to be about types, errors that are independent of the specific value that a variable has. Dynamic checking, by contrast, tends to be about errors caused by specific values.


Mutable/Immutable


值的改变、引用的改变


防御式拷贝


Snapshot diagram

考点总结_第9张图片

Immutable objects (intended by their designer to always represent the same value) are denoted in a snapshot diagram by a double border.

In a snapshot diagram, an immutable reference (final) is denoted by a double arrow.

考点总结_第10张图片

考点总结_第11张图片

考点总结_第12张图片


Specification、前置/后置条件

If the effects do not explicitly say that an input can be mutated, then we assume mutation of the input is implicitly disallowed.

Exceptions that signal a special result are always documented with a Javadoc @throwsclause, specifying the conditions under which that special result occurs. Furthermore, if the exception is a checked exception, then Java requires the exception to be mentioned in a throws declaration in the method signature. For example, suppose NotPerfectSquareException were a checked exception. You would need to mention it in both @throws in the Javadoc and throws in the method signature

For unchecked exceptions that signal a special result, Java allows but doesn’t require the throws clause. But it is better to omit the exception from the throws clause in this case, to avoid misleading a human programmer into thinking that the exception is checked. For example, suppose you defined EmptyQueueException as an unchecked exception. Then you should document it with @throws, but not include it in the method signature


行为等价性


规约的强度

A specification S2 is stronger than or equal to a specification S1 if – S2’s precondition is weaker than or equal to S1’s – S2’s postcondition is stronger than or equal to S1’s, for the states that satisfy S1’s precondition.

If S3 is neither stronger nor weaker than S1, there specs. might overlap (such that there exist implementations that satisfy only S1, only S3, and both S1 and S3) or might be disjoint. In both cases, S1 and S3 are incomparable.


ADT操作的四种类型


表示独立性

This means that the use of an abstract type is independent of its representation (the actual data structure or data fields used to implement it), so that changes in representation have no effect on code outside the abstract type itself.


表示泄露


不变量、表示不变量RI


表示空间、抽象空间、AF

考点总结_第13张图片

Every abstract value is mapped to by some rep value (surjective, 满射). Some abstract values are mapped to by more than one rep value (not injective, 未必单射). Not all rep values are mapped (not bijective, 未必双射).


以注释的形式撰写AF、RI

checkrep:Although you don’t need to state it in a rep invariant comment, you still must implement the x != null check, and make sure that your checkRep() correctly fails when x is null.

考点总结_第14张图片


接口、抽象类、具体类

An interface can extend one or more others 一个接口可以扩展其他接口

A class can implement multiple interfaces 一个类可以实现多个接口

From Java 8,interfaces are allowed to contain static methods, so we can implement the creator operation valueOf as a static factory method in the interface MyString. Hiding the implementation completely is a tradeoff, because sometimes the client wants a choice of implementations with different characteristics.


继承、override

In Java methods are rewriteable by default, i.e. there is no special keyword.

The subclass can only add new methods to the superclass, it cannot overwrite them – If a method cannot be overwritten in a Java program, it must be prefixed with the keyword final.

Cannot reduce the visibility of the inherited method from super-type.

考点总结_第15张图片

考点总结_第16张图片

A final field: prevents reassignment to the field after initialization

A final method: prevents overriding the method

A final class: prevents extending the class


多态、overload

Three Types of Polymorphism:

  1. Ad hoc polymorphism(function overloading )
  2. Parametric polymorphism(generic programming )
  3. Subtyping (when a name denotes instances of many different classes related by some common superclass )

Overloaded methods let you reuse the same method name in a class, but with different arguments(返回类型不属于签名)

Rules in function overloading: the overloaded function must differ either by the arity(参数数量) or data types


泛型

Generic programming is a style of programming in which data types and functions are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters.

generic class declarations, generic interface declarations, generic method declarations, and by generic constructor declarations. (范型的四种使用方式)

Suppose we want to implement the generic Set interface. – Way 1: Generic interface, non-generic implementation: to implement Set for a particular type E . Way 2: Generic interface, generic implementation. – We can also implement the generic Set interface without picking a type for E . – In that case, we write our code blind to the actual type that clients will choose for E . – Java’s HashSet does that for Set

考点总结_第17张图片


等价性equals()和==


equals()的自反、传递、对称性

If you redefine the equals method, you will also need to redefine the hashcode method for objects that users might insert into a hash table.

考点总结_第18张图片


hashCode()

Equal objects must have equal hash codes – If you override equals you must override hashCode  Unequal objects should have different hash codes – Take all value fields into account when constructing it .

考点总结_第19张图片
Hash code must not change unless object mutated


可变对象的观察等价性、行为等价性

observational equality means that two references cannot be distinguished by code that doesn’t change the state of either object, i.e., by calling only observer, producer, and creator methods. This tests whether the two references “look” the same in the current state of the program.

behavioral equality means that two references cannot be distinguished by any code, even if a mutator is called on one but not the other. This tests whether the two references will “behave” the same, in this and all future states.

Java uses observational equality for most of its mutable data types (such as Collections), but other mutable classes (like StringBuilder ) use behavioral equality.  If two distinct List objects contain the same sequence of elements, then equals() reports that they are equal.  But using observational equality leads to subtle bugs, and in fact allows us to easily break the rep invariants of other collection data structures.

equals() should implement behavioral equality .

In general, that means that two references should be equals() if and only if they are aliases for the same object.

So mutable objects should just inherit equals() and hashCode() from Object .

For clients that need a notion of observational equality (whether two mutable objects “look” the same in the current state), it’s better to define a new method, e.g., similar().

For immutable types : – equals() should compare abstract values. This is the same as saying equals() should provide behavioral equality. – hashCode() should map the abstract value to an integer. – So immutable types must override both equals() and hashCode() .

For mutable types : – equals() should compare references, just like == . Again, this is the same as saying equals() should provide behavioral equality. – hashCode() should map the reference into an integer. – So mutable types should not override equals() and hashCode() at all, and should simply use the default implementations provided by Object . Java doesn’t follow this rule for its collections, unfortunately, leading to the pitfalls that we saw above.

/* -128-127在autobox 和valueof(不是new)的时候会是一个对象 */




代码可理解性/可读性

Length of names

Name Uniqueness Ratio

Comment density (MCOMM%) MCOMM / LOC

– Specifications: pre-condition and post-condition (section 3.2) – Rep Invariants (RI) (section 3.3) – Abstract Function (AF) (section 3.3) – Safety from Rep Exposure (section 3.3) – Testing Strategy (to be discussed in Chapter 7) – How to ensure thread-safe (to be discussed in Chapter 10)


编码规范

Use Intention-Revealing Names

Packages should be lower case

Classes and Interfaces should be nouns and first upper case

Constant naming: all upper case with underscores between words


Programing for/with reuse

Levels and morphology of reusable components – Source code level reuse – Module-level reuse: class/interface – Library-level: API/package – System-level reuse: framework

External observations of reusability – Type Variation – Routine Grouping – Implementation Variation – Representation Independence – Factoring Out Common Behaviors


LSP

Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T. 派生类(子类)对象能够替换其基类(超类)对象被使用


数组的子类型化

泛型的子类型化

泛型中的通配符 ?

协变与逆变的讨论题

Delegation

Delegation is simply when one object relies on another object for some subset of its functionality (one entity passing something to another entity)

Explicit delegation: passing the sending object to the receiving object; Implicit delegation: by the member lookup rules of the language

Five types of relations between objects:泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

Inheritance

Delegation: – Association – Dependency – Composition – Aggregation


Comparator和Comparable

Java中Comparable和Comparator区别小结


接口的组合

一个类可以实现多个接口,因此在设计的时候,不要设计过于“胖”的接口,应该设计功能单一的小接口,然后通过让类实现不同接口的组合来完成功能。


CRP原则

Common Reuse Principle (CRP) lays down a good foundation to determine which classes should be packaged together:

The classes in a package are reused together. If you reuse one of the classes in the package, you reuse them all.

白盒框架的原理与实现

Extension via subclassing and overriding methods

Common design pattern(s): Template Method

Subclass has main method but gives control to framework

Allows extension of every nonprivate method – Need to understand implementation of superclass – Only one extension at a time – Compiled together – Often so-called developer frameworks


黑盒框架的原理与实现

Extension via implementing a plugin interface

Common design pattern(s): Strategy, Observer

Plugin-loading mechanism loads plugins and gives control to the framework

Allows extension of functionality exposed in interface – Only need to understand the interface – Multiple plugins – Often provides more modularity – Separate deployment possible (.jar, .dll, …) – Often so-called end-user frameworks, platforms


设计模式adapter、decorator、 façade、strategy、template、 iterator/iterable

设计模式:creational、structural、behavioral

Structural patterns:

Adapter allows classes with incompatible interfaces to work together by wrapping its own interface around that of an already existing class.

考点总结_第20张图片

继承:

Decorator dynamically adds/overrides behavior in an existing method of an object.

Problem: You need arbitrary or dynamically composable extensions to individual objects.  Solution: Implement a common interface as the object you are extending, add functionality, but delegate primary responsibility to an underlying object.  It works in a recursive way. Decorators use both subtyping and delegation

考点总结_第21张图片

考点总结_第22张图片

考点总结_第23张图片

考点总结_第24张图片

Decorator vs. Inheritance  Decorator composes features at run time – Inheritance composes features at compile time  Decorator consists of multiple collaborating objects – Inheritance produces a single, clearly-typed object  Can mix and match multiple decorations – Multiple inheritance is conceptually difficult

Facade provides a simplified interface to a large body of code.

考点总结_第25张图片


Behavioral patterns:

Strategy allows one of a family of algorithms to be selected on-the-fly at runtime.

考点总结_第26张图片

Template method defines the skeleton of an algorithm as an abstract class, allowing its subclasses to provide concrete behavior.

不同的客户端具有相同的算法步骤 ,但是每个步骤的具体实现不同。

考点总结_第27张图片

Template method pattern uses inheritance + overridable methods to vary part of an algorithm – While strategy pattern uses delegation to vary the entire algorithm (interface and ad-hoc polymorphism).  Template Method is widely used in frameworks – The framework implements the invariants of the algorithm – The client customizations provide specialized steps for the algorithm – Principle: “Don’t call us, we’ll call you”.

Iterator accesses the elements of an object sequentially without exposing its underlying representation.

考点总结_第28张图片




可维护性的常见度量指标

Cyclomatic Complexity - Measures the structural complexity of the code. – It is created by calculating the number of different code paths in the flow of the program. – A program that has complex control flow will require more tests to achieve good code coverage and will be less maintainable. – CC = E-N+2, CC=P+1, CC=number of areas

Lines of Code - Indicates the approximate number of lines in the code.

Halstead Volume: a composite metric based on the number of (distinct) operators and operands in source code. 运算符和操作数的数目

Depth of Inheritance - Indicates the number of class definitions that extend to the root of the class hierarchy.

Class Coupling

Unit test coverage


聚合度与耦合度

The degree of coupling between modules is determined by: – The number of interfaces between modules (quantity), and – Complexity of each interface (determined by the type of communication) (quality)

A module has high cohesion if all of its elements are working towards the same goal.

Good software design dictates that types and methods should have high cohesion and low coupling.

When Coupling is high, cohesion tends to be low and vise versa.


SOLID

(SRP) The Single Responsibility Principle 单一责任原则

“There should never be more than one reason for a class to change”, i.e., a class should concentrate on doing one thing and one thing only.

(OCP) The Open-Closed Principle 开放封闭原则

"Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification“, i.e., change a class' behavior using inheritance and composition

Whenever a software system must support a set of alternatives, one and only one module in the system should know their exhaustive list.

(LSP) The Liskov Substitution Principle Liskov替换原则

Subtypes must be substitutable for their base types.

考点总结_第29张图片

(ISP) The Interface Segregation Principle 接口隔离原则

"Clients should not be forced to depend upon interfaces that they do not use“, i.e., keep interfaces small. “客户不应该被迫依赖他们 不使用的接口”,即保持接口小。

(DIP) The Dependency Inversion Principle 依赖转置原则

"A. High level modules should not depend upon low level modules. Both should depend upon abstractions.高层模块不应该依 赖于低层模块,二者都应该依赖于抽象。  B. Abstractions should not depend upon details. Details should depend upon abstractions“, i.e., use lots of interfaces and abstractions. 抽象不应该依赖于实现细节,实现细节应该依赖于抽象。

考点总结_第30张图片


设计模式:factory method、 abstract factory、builder、 bridge、proxy、composite、 observer/observable、visitor、 state、memento

Creational patterns:

Factory method pattern creates objects without specifying the exact class to create.

Abstract factory pattern groups object factories that have a common theme.

Builder pattern constructs complex objects by separating construction and representation.

Structural patterns:

Bridge

decouples an abstraction from its implementation so that the two can vary independently. Implementation may be switched at run-time. Implementation changes should not affect clients . Hide a class’s interface from clients

– Logical one for clients – Physical one for different implementations

将类的功能层次结构(abstract)与实现层次结构分离(implementation)

考点总结_第31张图片

考点总结_第32张图片

Proxy provides a placeholder for another object to control access, reduce cost, and reduce complexity.

Goal: – Prevent an object from being accessed directly by its clients(  Solution: – Use an additional object, called a proxy – Clients access to protected object only through proxy – Proxy keeps track of status and/or location of protected object

3 Types:

  1. Caching of information (“Remote Proxy”) (提供一个对象在不同地址空间的局部代表,”缓存”) Good if information does not change too often
  2. Standin (“Virtual Proxy”) (根据需要 创建开销较大的对象,实现延迟加载) – Good if the real object is not accessed too often
  3. Access control (“Protection Proxy”) 保护实际的对象 Good when different actors should have different access and viewing rights for the same object

example:

考点总结_第33张图片

Composite composes zero-or-more similar objects so that they can be manipulated as one object. 将对象组合成树形结构以表示“部分-整体”的层次结构。使得用 户对单个对象和组合对象的使用具有一致性 – Recursive composition

– "Directories contain entries, each of which could be a directory."

 In a company we have supervisors and workers. The supervisors can manage other supervisors or workers under them.  The supervisors will be the composites.  The workers does not manage anyone and they will be the leaves.  All the supervisors and workers are employees, and as an employee you can always show your happiness level in the company (this is the common operation of the elements) :

考点总结_第34张图片

Behavioral patterns

Observer is a publish/subscribe pattern which allows a number of observer objects to see an event.

The subscribers are registered to the publisher so that when a change occurs in the publisher all of the subscribers are notified. – The publishers and the subscribers are decoupled through the use of interfaces so that the development of each can vary independently.

Three variants for maintaining the consistency:

  1. Push Notification: Every time the state of the subject changes, all the observers are notified of the change
  2. Push-Update Notification: The subject also sends the state that has been changed to the observers
  3. Pull Notification: An observer inquires about the state the of the subject

考点总结_第35张图片

In mediator pattern, there is the notion of the participants and they communicate with each other using the mediator as a central hub. – In observer pattern, there is a clear distinction between the sender and the receiver, and the receiver merely listens to the changes in the sender.

Visitor separates an algorithm from an object structure by moving the hierarchy of methods into one object.If the logic of operation changes, then we need to make change only in the visitor implementation rather than doing it in all the item classes. 将数据结构与其上的处理分离,允许在运行时对一组具有不同数据结构的对 象执行统一操作

考点总结_第36张图片

考点总结_第37张图片

考点总结_第38张图片

考点总结_第39张图片

Text: “manufacturer independent”, “device independent”, “must support a family of products” => Abstract Factory Pattern

Text: “must interface with an existing object” => Adapter Pattern

Text: “must interface to several systems, some of them to be developed in the future”, “an early prototype must be demonstrated” =>Bridge Pattern

Text: “must interface to existing set of objects” => Façade Pattern

Text: “complex structure”, “must have variable depth and width” => Composite Pattern

Text: “must be location transparent” => Proxy Pattern

Text: “must be extensible”, “must be scalable” => Observer Pattern

Text: “must provide a policy independent from the mechanism” => Strategy Pattern

Composite, Adapter, Bridge, Façade, Proxy (Structural Patterns) - Focus: Composing objects to form larger structures. Realize new functionality from old functionality, • Provide flexibility and extensibility

Command, Observer, Strategy, Template (Behavioral Patterns) - Focus: Algorithms and assignment of responsibilities to objects • Avoid tight coupling to a particular solution .

Abstract Factory, Builder (Creational Patterns) - Focus: Creation of complex objects • Hide how complex objects are created and put together

State

Suppose an object is always in one of several known states  The state an object is in determines the behavior of several methods  Could use if/case statements in each method

The State Design Pattern allows you to alter the behavior, or the state, of the object at runtime. Each behavior is represented by a state class, and the behavior can change from one state to another.

Have a reference to a state object – Normally, state object doesn’t contain any fields – Change state: change state object – Methods delegate to state object

考点总结_第40张图片

memento

– Without violating encapsulation, capture and externalize an object's internal state so that the object can be returned to this state later. – Promote undo or rollback to full object status.

– Originator原发器 - the object that knows how to save itself. • creates a memento containing a snapshot of its current internal state. • uses the memento to restore its internal state.

Memento 备忘录- the lock box that is written and read by the Originator, and shepherded by the Caretaker. • stores internal state of the Originator object. • protects against access by objects other than the originator

Caretaker 负责人- the object that knows why and when the Originator needs to save and restore itself. • is responsible for the memento's safekeeping. • never operates on or examines the contents of a memento.

考点总结_第41张图片

考点总结_第42张图片


语法、正则表达式

A regular grammar正则语法 has a special property: by substituting every nonterminal (except the root one) with its righthand side, you can reduce it down to a single production for the root, with only terminals and operators on the right-hand side.

html ::= ( [^<>]* | '' html '' )*
Not regular!

The reduced expression of terminals and operators can be written in an even more compact form, called a regular expression. A regular expression does away with the quotes around the terminals, and the spaces between terminals and operators, so that it consists just of terminal characters, parentheses for grouping, and operator characters.

Pattern regex = Pattern.compile("");
Matcher m = regex.matcher(string);
if (m.matches()) {
String url = m.group(1);
// Matcher.group(n) returns the nth parenthesized part of
// the regex
}


健壮性和正确性

Robustness(鲁棒性/健壮性): “the degree to which a system or component can function correctly in the presence of invalid inputs or stressful environmental conditions“ (IEEE Std 610.12-1990)系统 或组件在存在无效输入或压力环境条件时可以正确运行的程度

对自己做的事情保守(服务specification),对接收的信息自由(能够处理 各类情况)

Robustness adds built-in tolerance for common and non-critical mistakes, while correctness throws an error when it encounters anything less than perfect input.

Internally, seek correctness; Externally, seek robustness.

Safety critical applications tend to favor correctness to robustness. Consumer applications tend to favor robustness to correctness.

Reliability. The ability of a system to perform its required functions under stated conditions whenever required—having a long mean time between failures. 系统在任何需要的情况下在规定的条件下执行 其所需功能的能力  Reliability=Robustness + Correctness

Error -> defect/fault/bug -> failure A programmer makes an error (mistake), which results in a defect (fault, bug) in the software source code.  If this defect is executed, in certain situations the system will produce wrong results, causing a failure

Mean time between failures (MTBF) is the predicted elapsed time between inherent failures of a system during operation. 平均故障间 隔时间,是指相邻两次故障之间的平均工作时间。

Mean time between failures (MTBF) describes the expected time between two failures for a repairable system, while mean time to failure (MTTF) denotes the expected time to failure for a nonrepairable system. (MTTF,平均失效前时间)。


Throwable

考点总结_第43张图片


Runtime异常、其他异常

Checked异常、Unchecked异常

Declare more than one Checked Exceptions: throws FileNotFoundException, EOFException

Do not need to advertise internal Java errors—that is, exceptions inheriting from Error. Similarly, you should not advertise unchecked exceptions inheriting from RuntimeException.

How to Throw an Exception : String gripe = "Content-length: " + len + ", Received: " + n; throw new EOFException(gripe);


Checked异常的处理机制: – 抛出、捕获、处理、清理现场、 释放资源等

准则:处理知道如何处理的异常,传播不知道如何处理的异 常。

InputStream in = new FileInputStream(. . .);
try {
// 1
code that might throw exceptions
// 2
}
catch (IOException e) {
// 3
show error message
// 4
}
Finally {
// 5
in.close();
}
// 6

Case 1: The code throws no exceptions. 没有抛出异常 1, 2, 5, and 6.

Case 2: The code throws an exception that is caught in a catch clause and the catch clause does not throw an exception. 抛出一个 被捕获的异常,catch没有继续抛出异常 :1, 3, 4, 5, and 6.

Case 3: The code throws an exception that is caught in a catch clause and the catch clause throws an exception. 抛出一个被捕获 的异常,catch继续抛出异常 : 1, 3, and 5

Case4: The code throws an exception that is not caught in any catch clause. 抛出一个未被捕获的异常 :1 and 5

异常处 理不能代替简单的测试 :if (!s.empty()) s.pop(); Use exceptions for exceptional circumstances only

Do not micromanage exceptions. 不要过分地细化异常


自定义异常类

Creating Exception Classes : Just derive it from Exception, or from a child class of Exception such as IOException.


断言的作用、应用场合

The java language gives you three mechanisms to deal with system failures:

  1. throwing an exception
  2. logging
  3. using assertions

when should you choose assertions? keep these points in mind:

  1. assertion failures are intended to be fatal, unrecoverable errors.
  2. assertion checks are turned on only during development and testing. (This is sometimes jokingly described as "wearing a life jacket when you are close to shore, and throwing it overboard once you are in the middle of the ocean.")

Therefore, you world not use assertions for signaling recoverable conditions to another part of the program or for communicating problems to the program user. Assertions should only be used to locate internal program errors during testing.

  1. The checking of method parameters/ return value requirements (specification required and not throws exception)
  2. Using assertions for documenting assumptions
  3. Covering all

assert condition : expression;

Runtime assertions are not free. They can clutter the code, so they must be used judiciously.

不要用断言来测试外部的条件

The assert statements don’t run without -ea, but the JUnit assertXXX() methods always run.

Assertions generally cover correctness issues of program.  Exceptions generally cover robustness issues of program

Avoid putting executable code ( side-effects ) in assertions

pre-/post- conditions :if the variables latitude, longitude, and elevation were coming from an external source, invalid values should be checked and handled by error handling code rather than assertions.  If the variables are coming from a trusted, internal source, however, and the routine’s design is based on the assumption that these values will be within their valid ranges, then assertions are appropriate.


调试的基本过程和方法

Process for debugging: Reproduce the bug – Diagnosing the bug – Fix the bug – Reflection

– Stabilize the error. (Reproduce)

– Locate the source of the error (Diagnose, bug localization). :

• Gather the data that produces the defect.

• Analyze the data that has been gathered and form a hypothesis about the defect.

• Determine how to prove or disprove the hypothesis, either by testing the program or by examining the code.

• Prove or disprove the hypothesis using the procedure identified in 2(c).

– Fix the defect. (Fix) – Test the fix. – Look for similar errors.


Diagnosis stratagem :

  1. Instrumentation(插桩)
  2. Divide and Conquer 分治
  3. Leveraging VCS 利用版本控制系统
  4. Focus on the differences
  5. Learn from others
  6. Debugger


Debugging techniques and tools: Print debugging / stack tracing / memory dump – Logging – Compiler Warning Messages – Debugger: watch points, break points, etc

debugging occurs as a consequence of successful testing. 测试发现现象,调试发现本质。

Like testing, debugging isn’t a way to improve the quality of your software, but it’s a way to diagnose defects.


黑盒测试用例的设计 – 等价类划分、边界值分析

Unit-test considerations :

Don't forget error-handling paths.

Test cases for black-box testing are built around specifications and requirements, i.e., what the application is supposed to do.

Equivalence partitioning is a testing method that divides the input domain of a program into classes of data from which test cases can be derived. (相似的输入会产生 相似的结果的输入分为一个集合,可以用集合中的一个输入的测试结 果代表整个集合)

例子:BigInteger × BigInteger → BigInteger

– a and b are both positive – a and b are both negative – a is positive, b is negative – a is negative, b is positive

There are also some special cases for multiplication that we should check: 0, 1, and -1.

So we should definitely also try integers that are very big, bigger than the biggest long. (测试java支持的最大值)

考点总结_第44张图片

  1. Full Cartesian product (完全的笛卡尔乘积) (– In practice not all of these combinations are possible )
  2. Cover each part(覆盖每一个分区)

be careful about Boundary Value Analysis:

  1. If an input condition specifies a range bounded by values a and b, test cases should be designed with values a and b and just above and just below a and b.
  2. If an input condition specifies a number of values, test cases should be developed that exercise the minimum and maximum numbers. Values just above and below minimum and maximum are also tested.
  3. Apply guidelines 1 and 2 to output conditions. For example, assume that a temperature versus pressure table is required as output from an engineering analysis program. Test cases should be designed to create an output report that produces the maximum (and minimum) allowable number of table entries.
  4. If internal program data structures have prescribed boundaries (e.g., a table has a defined limit of 100 entries), be certain to design a test case to exercise the data structure at its boundary. (白盒)


以注释的形式撰写测试策略

考点总结_第45张图片


JUnit测试用例写法

assertEquals, assertTrue, and assertFalse.

考点总结_第46张图片


测试覆盖度

White-box

Branch coverage is stronger (requires more tests to achieve) than statement coverage, and path coverage is stronger than branch coverage.

100% statement coverage is a common goal, but even that is rarely achieved due to unreachable defensive code (like “should never get here” assertions).

EclEmma




内存管理模型:堆、栈

Dynamic allocation, contrast to Static allocation.

stack-based

heap-based(free)

New objects created and placed in the heap. – Once your application have no reference anymore to an object the Java garbage collector is allowed to delete this object and remove the memory so that your application can use this memory again.

考点总结_第47张图片

基本类型保存在线程栈中,对象保存在堆中.局部变量保存在线程栈中,局部变量引用了对象,引用保存在栈中 ,对象存储在堆中.对象包含 的方法和方法包含的局部变量存储在栈中.对象的成员变量存储在堆中.静态类变量保存在堆中

Objects on the heap can be accessed by all threads that have a reference to the object.  If two threads call a method on the same object at the same time, they will both have access to the object's member variables, but each thread will have its own copy of the local variables.


GC,root、reachable、 unreachable、live、dead

Any dependent, direct or indirect, of these origins/roots is reachable, and any other object is unreachable

The live objects of the graph are those reachable from a root.

Identifying garbage and deallocating the memory it occupies is called Garbage Collection(GC).

 In common language implementations roots include – Words in the static area – Registers – Words on the execution stack that point into the heap.

持有Integer对象的对象,需要回收2个对象;持有int的 对象,只需要回收1个对象


GC的四种基本算法

Reference counting: 引用计数 – Keep a note on each object, indicating the number of live references to the object. If an object’s reference count goes to zero, throw the object out (it’s dead).A pitfall of reference counting: reference cycles

Mark-Sweep: 标记-清除 – Put a note on objects you need (roots). – Then recursively put a note on anything needed by a live object. – Afterwards, check all objects and throw out objects without notes

考点总结_第48张图片

Mark-Compact: 标记-压缩 – Put notes on objects you need. – Move anything with a note on it to the back of the garage. – Burn everything at the front of the garage (it’s all dead).

考点总结_第49张图片

Copying: 复制 – Move objects you need to a new garage. – Then recursively move anything needed by an object in the new garage. – Afterwards, burn down the old garage (any objects in it are dead)!

  1. Divide heap into 2 halves called semi-spaces and named Fromspace and Tospace
  2. Allocate objects in Tospace
  3. When Tospace is full – Flip(翻转) the roles of the semi-spaces – Pick out all live data in Fromspace and copy them to Tospace – Preserve sharing by leaving a forwarding address in the Fromspace replica – Use Tospace objects as a work queue


Java/JVM的内存管理模型:各区域、各区域的GC方法

young generation, old generation, and permanent generation.

新对象分配到young generation中

垃圾回收后仍然存活的对象,提升到old generation中

Perm保存class 元数据

In the young generation 每次GC会发现大量死亡对象,少量存活对象 复制算法适合,代价低

In the old generation the Mark-Sweep or Mark-Compact

考点总结_第50张图片

三个空间任何一个已满且存在 对额外空间需求时,会发生GC

When the young generation space does not have enough room available to satisfy a Java object allocation, the HotSpot VM performs a minor garbage collection to free up space. Minor garbage collections tend to be short in duration relative to full garbage collections. Minor GC针对年轻代

 When the old generation space no longer has available space for promoted objects, the HotSpot VM performs a full garbage collection. 当没有空间提供给minor GC将对象提升到老年代中,或者永久代中无空间保存class元数据时,Full GC针对老年代和永久代


JVM GC性能调优:参数配置、 GC模式选择

考点总结_第51张图片

-XX:+UseSerialGC

-XX:+UseParallelGC

-XX:+UseConcMarkSweepGC

-XX:+UseTrainGC


Java性能调优工具:jstat, jmap, jhat, Visual VM, MAT

jstat: 获取JVM的heap使用和GC的性能统计数据

jmap: 输出内存中的 对象分布情况

jhat: 导出heap dump,浏览/查询其中的对象分布情况

jstack: 获取java线程的stack trace


Memory dump

Stack trace

Java代码调优的设计模式: singleton, prototype/cloneable, flyweight, pool

考点总结_第52张图片

Singleton Pattern 单例模式 :

Some classes have conceptually one instance 某些类在概念上只有一个 实例 只创建一个对象,然后复用 确保类只有一个实例,并提供一个全局访问点

优势:对唯一实例的受控访问 缩小命名空间(对全局变量的一种改进) 类通过封装确保对象的复用,不用让客户端考虑 节省创建时间 降低内存消耗 对于 系统的核心组件和经常使用的对象,使用单例模式可以有效地提高系统性能。

Make constructor private 使构造器private – Provide static method/field to allow access to the only instance of the class 提供static方法和字段允许对唯一实例的调用

考点总结_第53张图片

考点总结_第54张图片

Pay attention to the usage in multi-thread program

Flyweight Pattern 享元模式 :

Intrinsic states(内在状态) are things that are constant and are stored in the memory, can be shared. 内在状态:不变的状态,可以共享

Extrinsic states( 外在状态) are things that are not constant and need to be calculated on the fly, and are therefore not stored in the memory, can not be shared.外在状态:状态是不固定的,使用时需要计算,不可共享

考点总结_第55张图片

Prototype Pattern 原型模式 :

通过复制已有原型对象新 创建对象 目标:创建或初 始化对象代价高时,可通过此模式创建相似对象,降低开销 类似于文档模板,创建一次, 多次被复制使用,作为撰写文档的起点。 原型模式在初始化创建第一个对象时开销大,然后将 这些值作为原型存储在存储库中。 需要再次创建相同或类似对象时,只需从存储库中获取所有值预填充的 原型副本。

考点总结_第56张图片

类中要声明clone()方法 . 实现clone()时,要调用super.clone()(in Object) 类需要实现java.lang.Cloneable接 口

Shallow copy(浅拷贝) is a method of copying an object(field-by-field copy, field-for-field copy, or field copy). In that case a new object B is created, and the fields values of A are copied over to B. 复制对象A的 所有字段到对象B中. 基本数据类型采用复制值的形式 对对象的引用,则复制引 用,此时A和B共享对同一对象的引用。

prototype pattern vs. flyweight pattern :原型模式用于创建本质上相似的新对 象(因此它是创建模式), flyweight模式用于允许应用程序指向对象的同一个实例以节省内 存(因此它是一种结构模式)。

Object Pool Pattern:

已经有了一个对象,并不再使用时,可让其他对象继续使用 回收再利用 E.g., database connection pool, printer pool 使用时从pool中取出,用完后归还,类似工具箱

Object Pool Pattern vs Flyweight Pattern :原理不同: – object pool的原理是复用,pool中object被取出后,只能由一个client使用; – flyweight的原理是共享,一个object可被多个client同时使用。 对象性质不同: – object pool中的对象是同质的,对于client来说,可以用pool中的任何一个 object。如:需要connection时可以从connection pool中任意的拿一个出来 使用; – Flyweight的每一个实例的内部属性相同,但是外部属性不同,是异质的。 flyweight使用时,是去FlyweightFactory中找一个特定的对象出来(如果没 有的话,就创建一个)。 应用场合不同 – object pool对应的场景是对象被频繁创建、使用,然后销毁。每个对象的生 命期都很短。同一时刻内,系统中存在的对象数也比较小。 – Flyweight对应的情况是在同一时刻内,系统中存在大量对象。


常见的Java I/O方法

考点总结_第57张图片


进程和线程

进程是正在运行程序的一个实例,拥有自己私有 专用的内存空间 进程可抽象为虚拟计算机, 拥有独立的执行环境和完整的资源 为了实现进程间通信,大多数操作系统都 支持”进程间通信(IPC)资源”,例如管道和socket。 Java虚拟机本身的大多数实现都是作为单个进程运行的

线程是正在运行程序的一个执行路径(一个进程可对应 多个线程),线程有自己的堆栈和局部变量,但是多个线程共享内存空间 线程可抽象为一个虚拟处理器,线程有时也称为 轻量级进程 线程采用内存共享机制通信 每个应用程序至少有一个线程 从main线程开始,创建其他的线程

考点总结_第58张图片


线程的创建和启动,runnable

所有的线程都需要实现Runnable接 口,在run()中写具体实现

public interface Runnable {
    void run();
}

(Seldom used) Subclassing Thread. 创建Thread类的子类 The Thread class itself implements Runnable, though its run method does nothing. An application can subclass Thread, providing its own implementation of run().

public class HelloThread extends Thread {
    public void run() {
        System.out.println("Hello from a thread!");
    }
    public static void main(String args[]) {
        (new HelloThread()).start();
        (new HelloThread()).start();
        (new HelloThread()).start();
    }
}

(More generally used) Implement the Runnable interface and use the new Thread(..) constructor. 实现Runnable接口,作为参数传递给 new Thread(..)构造函数

public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }
    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}

惯用法:用一个匿名 的Runnable启动一个线程,它避免了创建命名的类

new Thread(new Runnable() {
    public void run() {
        System.out.println("Hello from a thread!");
    }
}).start(); 


时间分片、交错执行、竞争条件

在某时刻,一个 运行核心上只有一个线程可以运行 进程/线程等采用OS提供的时间 片特征来共享处理时间 当线程数多于处理器数量时,并发性通过时间片来模拟,处理器切换处理 不同的线程。 .时间片的使用是不可预知和非确定性的,这意味 着线程可能随时暂停或恢复。

竞争条件:程序的正确性(后置条件和不变量的满足)取决于并发计算A和B中事件 的相对时间 When correctness of result (postconditions and invariants) depends on the relative timing of events – Multiple threads sharing the same mutable variable without coordinating what they’re doing. –


线程的休眠、中断

Pausing Execution with Thread.sleep(time): causes the current thread to suspend execution for a specified period.让当前线程暂停指定 时间的执行

The join() method is used to hold the execution of currently running thread until the specified thread is dead (finished execution). Join()方法用于保持当前正在运行的线程的执行,直到该 线程死亡(执行完毕),才能继续执行后续线程

防护块:在语句块开始放 一个轮询条件(一直检测),当条件为真才能执行后续的语句。 始终循环, 浪费处理器时间

--> o.wait(): release lock on o, enter o‘s wait queue and wait 释放对象o的锁 ,使线程进入等待状态 o.notify(): wake up one thread in o‘s wait queue 唤醒对象o监视器上( 锁对象)等待的单个线程 o.notifyAll(): wake up all threads in o‘s wait queue唤醒对象o监视器上 等待的所有线程 Using wait() in Guarded Blocks 执行wait()后,当前线程会等待,直到其他线程调用 此对象的notify( ) 方法或 notifyAll( ) 方法 必须预先锁定o

. 每个线程 都有一个与之相关联的 Boolean 属性,用于表示线程的中断状态,中断状 态初始时为 false。 当另一个线程通过调用 Thread.interrupt() 中断一个线程时,会出现以下两种情况之一。 如果被中断线程在执行一个低级可中断阻塞方法,例如 Thread.sleep()、 Thread.join() 或Object.wait(),那么它将取消阻塞并抛出 InterruptedException。 否则, interrupt() 只是设置线程的中断状态。 在被中断线 程中运行的代码以后可以轮询中断状态,看看它是否被请求停止正在做的 事情。 中断状态可以通过 Thread.isInterrupted() 来读取,并且可以通过一个名为 Thread.interrupted() 的操作读取和清除 中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一 定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿 意并且方便的时候停止它正在做的事情。有些方法,例 如 Thread.sleep(),很认真地对待这样的请求,但每个方法不是一定要对 中断作出响应。对于中断请求,不阻塞但是仍然要花较长时间执行的方法 可以轮询中断状态,并在被中断的时候提前返回。 您可以随意忽略中断 请求,但是这样做的话会影响响应。 中断的协作特性所带来的一个好处是,它为安全地构造可取消活动提供更 大的灵活性。 我们很少希望一个活动立即停止; 如果活动在正在进行更新的时候被取消,那么程序数据结构可能处于不一 致状态。中断允许一个可取消活动来清理正在进行的工作,恢复不变量, 通知其他活动它要被取消,然后才终止。


线程安全的四种策略

数据类型或静态方法在多线程中执行时,无论如何执行, 不需调用者做额外的协作,仍然能够行为正确,则称为线程安全的

行为正确意味着满足规格说明和保持不变性 不能在前置条件中对调用者增加时间性要求 Iterator不是线程安全的,因为需要满足特殊约定

Confinement. Don’t share the mutable variable between threads. 限制可变变量的共享

Immutability. Make the shared data immutable. There are some additional constraints for concurrent programming. 用不可变的共享变量

In order to be confident that an immutable data type is threadsafe without locks, we need a stronger definition of immutability: – No mutator methods 没有改变数据的操作 – All fields are private and final 所有的字段均为private 和 final – No representation exposure 没有表示泄露 – No mutation whatsoever of mutable objects in the rep – not even beneficent mutation 表示中的任何可变对象都不能变化

Threadsafe data type. Encapsulate the shared data in an existing threadsafe data type that does the coordination for you. 将共 享数据封装在线程安全的数据类型中 确保方法是原子的

Iterators are still not threadsafe. – Even though method calls on the collection itself ( get() , put() , add() , etc.) are now threadsafe, iterators created from the collection are still not threadsafe.

– So you can’t use iterator() , or the for loop syntax:

for (String s: lst) { ... }
// not threadsafe, even if lst is a synchronized list wrapper

解决方案将是在需要迭代collection时 获取集合的锁

原子 操作不足以完全防止竞争 例如检查列表是否至少有一个元 素,然后获取该元素

if ( ! lst.isEmpty()) { String s = lst.get(0); ... }

because another thread may remove the element between the isEmpty()call and the get()call.

Synchronization. Use synchronization to keep the threads from accessing the variable at the same time. Synchronization is what you need to build your own threadsafe data type.使用同步来防止线程同时访问变量

锁定是一种实现同步的技术 某时刻最多只允许一个线程拥有锁

– acquire 获取锁的所有权,如过锁被其他线程拥有,将进入阻塞状态,等待锁释放后, 再同其他线程竞争获取锁的所有权。 阻塞一般意味着线程等待(不再 继续工作),直到一个事件发生。

– release 释放锁的所有权

可以确保锁的所有者始终查看最新 的数据。

错误:拥有对象的锁会自动阻止其他线程访问该对象 锁只能确保与其他请求获取相同对象锁的线程互斥访问,如 果其他线程没有使用synchronized (obj)或者利用了不同object的锁 ,则同步会失效。

//lock is an object of a class
synchronized (lock) { // thread blocks here until lock is free
    // now this thread has the lock
    balance = balance + 1;
    // exiting the block releases the lock
}
public synchronized void increment() { c++; }

Synchronized block语句可用于实现 具有细粒度同步的并发性

当线程调用同步方法时,它会 自动获取该方法对象的内部锁,并在方法返回时释放它。 即使返回是 由未捕获的异常引起的,也会释放锁 .同一对象上的同步方法的两次调用不会 有交错现象。 当一个线程正在执行一个对象的同步方法时,所有其他线程 如果调用同一对象的同步方法块,则会挂起执行,直到第一个线程针 对此对象的操作完成 .当一个同步方法退出时,它会自动建立一个与之后调用同 一个对象的同步方法的happens-before关系。这保证对象状态的更改 对所有线程都是可见的。

happened-before保证了语句A内存的写入对语句B是可见的, 也就是在B开始读数据之前,A已经完成了数据的写入。 确保内存一致性

static synchronized method :由于静态方法与类关联,而不是对象。 在 这种情况下,线程获取与该类关联的Class对象的内部锁。 Thus access to class's static fields is controlled by a lock that's distinct from the lock for any instance of the class.

The monitor pattern guards the rep of a datatype with a single lock that is acquired by every method.

Giving clients access to a lock :让数据类型的锁对客户端可用,以实 现更高级的原子操作

考点总结_第59张图片


Message passing

模块间通过消 息传递进行交互

消息接收方将收到的消 息形成队列逐一处理(先进先出) ,消息发送者并不停下来等待结果而是继 续执行(异步方式)

消息传递的方式并不能消除竞争条件的可能性

需要仔细选择消息传递模型的 操作, withdraw-if-sufficient-funds 比单纯的withdraw更加适合

通过通信通道显式交互,而不是共享可变数据 消息传递共 享的信息为不可变的,降低了产生bugs的可能在同一进程的线程间传递消息,比通过锁定机制共 享内存更受欢迎

Use a synchronized queue for message passing between threads. The queue serves the same function as the buffered network communication channel in client/server message passing.使用同步 队列在线程之间传递消息 ArrayBlockingQueue LinkedBlockingQueue It must be an immutable type.

BlockingQueue

– put(e) blocks until it can add element e to the end of the queue (if the queue does not have a size bound, put will not block).

– take() blocks until it can remove and return the element at the head of the queue, waiting until the queue is non-empty.

message-passing deadlock E.g., instead of using LinkedBlockingQueues that can grow arbitrarily (limited only by the size of memory), we will use the ArrayBlockingQueue implementation that has a fixed capacity

One solution to deadlock is to design the system so that there is no possibility of a cycle — so that if A is waiting for B, it cannot be that B was already (or will start) waiting for A.

Another approach to deadlock is timeouts. If a module has been blocked for too long (maybe 100 milliseconds? or 10 seconds? how to decide?), then you stop blocking and throw an exception. Now the problem becomes: what do you do when that exception is thrown?


死锁

死锁描述了两个或更多线程 永远被阻塞的情况,都在等待对方。 线程间的依赖关系环是出现死锁的信号

Deadlock solution 1: lock ordering

防止死锁的一种方法是对需要同时获 取的锁进行排序,并确保所有代码按照该顺序获取锁定。

考点总结_第60张图片

Deadlock solution 2: coarse-grained locking

粗粒度的锁,用单个锁来监控多个 对象实例 :对整个社交网络设置一个锁,并且对 其任何组成部分的所有操作都在该锁上进行 同步。 例如:所有的Wizards都属于一个 Castle, 可使用castle实例的锁。

性能损失大 如果用一个锁 保护大量的可变数据,那么就放弃了同时访问这些数据的能力。在最糟糕的情况下,程序可能基 本上是顺序执行的,丧失了并发性。


以注释的形式撰写线程安全策略

考点总结_第61张图片

阐述使用了哪种技术 使用threadsafe data types, or synchronization时,还需要论证所有对数据的访问都是具有 原子性的。
考点总结_第62张图片

Just using immutable and threadsafe-mutable data types is not sufficient when the rep invariant depends on relationships between objects in the rep. (竞争(非原子操作)导致rep不满足)

你可能感兴趣的:(考点总结)