///<summary> /// 0123456789 ///</summary> privatestaticvoidLazyEvaluation3() { var answers = from number inAllNumbers() select number; var smallNumbers = answers.Take(10);
foreach (int num in smallNumbers) Console.Write(num); }
privatestatic IEnumerable<int> AllNumbers() { var number = 0;
while (number < int.MaxValue) yieldreturn number++; }
此示例不必生成整个序列,而是仅生成十个数 (虽然 AllNumbers() 可以生成至 int.MaxValue)。Take() 方法只需要其中的前 N 个对象。[8]
反之,如果把查询语句改成这样,程序将一直运行,直到 int.MaxValue才停下:
1 2 3 4
var answers = from number inAllNumbers() where number < 10 select number;
/** * no if statement in this method * use shift operators * if positive num : num >> 31 == 0 * if negative num : num >> 31 == -1 * ~0 = -1 (ffffffff) * ~-1 = 0 (0) */ publicstaticvoidsumAvoidBranchPrediction(int[] array, int arraySize) { longstart= System.nanoTime(); longsum=0;
for (inti=0; i < arraySize; ++i) { for (intj=0; j < arraySize; ++j) { sum += ~((array[j] - 128) >> 31) & array[j]; } } System.out.println(System.nanoTime() - start + " ns"); // _606_267_300 ns System.out.println("sum : " + sum); }
JLS SE 21, §15.17.3 Remainder Operator, defines Java % as remainder rather than mathematical modulo; Oracle Java SE 21 Random.nextInt(int bound) is the API to generate a bounded [0, bound) integer when that is the intended data range. ↩︎
Intel’s Optimization Reference Manual describes branch prediction as a processor optimization and treats mispredicted branches as a performance cost in hot code. ↩︎
Intel’s Optimization Reference Manual supports the general claim that predictable branch behavior is easier for the processor than irregular branch behavior; exact results depend on CPU, JVM, data shape, and benchmark method. ↩︎
JLS SE 21, §15.19 Shift Operators, defines signed right-shift behavior; branchless arithmetic or bit tricks should still be verified with JMH or equivalent benchmarking before being treated as an optimization. ↩︎
// Variant type parameters could be declared in interfaces or delegates only!
interfaceICovariant<outT> { }
classCovariant<T> : ICovariant<T> { }
interfaceIContravariant<inT> { }
classContravariant<T> : IContravariant<T> { }
interfaceIInvariant<T> { }
classInvariant<T> : IInvariant<T> { }
classProgram { privatestaticvoidCovariant(/* out */) { ICovariant<object> obj = new Covariant<object>(); ICovariant<string> str = new Covariant<string>();
// You can assign "Derived" to "Base" obj = str; str = obj; // error }
privatestaticvoidContravariant(/* in */) { IContravariant<object> obj = new Contravariant<object>(); IContravariant<string> str = new Contravariant<string>();
// You can assign "Base" to "Derived" str = obj; obj = str; // error }
privatestaticvoidInvariant(/* none */) { IInvariant<object> obj = new Invariant<object>(); IInvariant<string> str = new Invariant<string>();
// You can't do any assign obj = str; // error str = obj; // error } }
Microsoft Learn out generic modifier 说明 out 表示协变类型参数,允许把更派生的类型实参作为更宽泛的泛型接口或委托使用;这对应示例里 ICovariant<string> 可赋值给 ICovariant<object>。 ↩︎
Microsoft Learn in generic modifier 说明 in 表示逆变类型参数,允许把更宽泛的类型实参作为更具体的泛型接口或委托使用;这对应示例里 IContravariant<object> 可赋值给 IContravariant<string>。 ↩︎
Microsoft Learn Creating Variant Generic Interfaces 与 C# language specification 的 variance conversion 规则共同支撑:未标注 in / out 的类型参数是不变的,变体转换需要满足对应的协变、逆变或恒等转换条件。 ↩︎
The Garbage Collection Handbook uses reference counting and tracing as major families of automatic memory-management techniques; Oracle Java GC tuning describes HotSpot collectors in tracing/heap terms rather than as reference-counting collectors. ↩︎
Oracle Java SE 21 GC tuning docs define young, mixed, and full collection behavior in collector-specific terms; the article’s note that Major GC terminology is ambiguous is important because naming is not a Java-language specification contract. ↩︎
Oracle Java SE 21 GC tuning, Introduction to Garbage Collection Tuning, describes young-generation collection and promotion into older regions as core HotSpot GC concepts. ↩︎
Oracle Java SE 21, Garbage-First Garbage Collector, documents G1’s remembered sets as metadata that tracks references into a region to support regional collection. ↩︎
Oracle Java SE 21, Garbage-First Garbage Collector, distinguishes young-only, mixed, and full GC behavior for G1; exact event names vary by collector and logging era. ↩︎
Paul R. Wilson, Uniprocessor Garbage Collection Techniques, surveys mark-sweep among foundational tracing collection techniques and traces the historical lineage of classic GC algorithms. ↩︎
Oracle and HotSpot documentation support the generational premise that many young objects die quickly; the “98%” number is best treated as a historical heuristic, not a Java specification guarantee. ↩︎
The Garbage Collection Handbook describes the copying collector tradeoff: it compacts allocation space naturally but pays in target-space requirements and live-object copy cost. ↩︎
The Garbage Collection Handbook and Wilson’s survey cover mark-compact as the tracing-family strategy that moves live objects to reduce fragmentation. ↩︎
JEP 333 and JEP 189 describe ZGC and Shenandoah as low-pause collectors that perform much of the marking/relocation work concurrently with application threads. ↩︎
The Garbage Collection Handbook frames the moving versus non-moving choice as a tradeoff among fragmentation, allocation cost, reference update cost, pause time, and throughput. ↩︎
Oracle Java SE 21 GC tuning materials and classic GC literature describe fragmentation as the central cost of non-moving mark-sweep collection; CMS is the traditional HotSpot example of a mostly concurrent mark-sweep collector with fragmentation concerns. ↩︎
Oracle Java SE 21 GC tuning notes define an object as eligible for collection when there is no path from a GC root to it; The Garbage Collection Handbook provides the broader tracing-GC background. ↩︎
Oracle Java SE 21 GC tuning, Other Considerations, describes GC roots and the “no path from a GC root” reachability condition. ↩︎
Oracle Java SE 21 GC tuning, Other Considerations, identifies active-thread references and internal JVM references as GC roots; the concrete root set is implementation- and collector-dependent. ↩︎
The Garbage Collection Handbook covers the collector-design problem behind partial collection: a collector must account for references from outside the region being collected. ↩︎
The OpenJDK ZGC project page records ZGC’s JDK 11 limitations and later class-unloading support; Oracle GC documentation and OpenJDK collector notes should be used for collector-version specifics. ↩︎
Oracle Java SE 21 API, java.lang.ref, defines soft, weak, and phantom reference objects and their corresponding reachability levels. ↩︎
Oracle Java SE 21 API, Object.finalize(), documents the finalization hook and its deprecation status. ↩︎
Oracle Java SE 21 GC tuning, Other Considerations, discourages finalization because it can harm security, performance, and reliability, especially for timely resource release. ↩︎
JEP 421 deprecated finalization for removal in JDK 18 and lists unpredictable latency, object resurrection, always-on behavior, and unspecified threading as core flaws. ↩︎
JVMS SE 21, §2.5.4 Method Area, says the method area is logically part of the heap but the specification does not mandate garbage-collection or compaction policy; OpenJDK’s ZGC page records that JDK 11 ZGC did not support class unloading. ↩︎
Oracle Java SE 21 GC tuning, Class Metadata, states that class metadata is deallocated when the corresponding class is unloaded and that class unloading is a result of garbage collection. ↩︎
JEP 122 removed HotSpot’s permanent generation in JDK 8 and moved class metadata toward native-memory management; Oracle Java SE 21 GC tuning documents Metaspace/class-metadata deallocation behavior. ↩︎
Java 用起来如此舒适的一个因素在于,它是一门安全的语言 (safe language)。这意味着,它对于缓冲区溢出、数组越界、非法指针以及其他的内存破坏错误都自动免疫,而这些错误却困扰着诸如 C 和 C++ 这样的不安全语言。[1]在一门安全语言中,在设计类时,无论系统的其他部分发生什么问题,类的约束都可以保持为真。对于那些 “把所有内存当作一个巨大的数组来对待” 的语言来说,这是不可能的。
即使在安全的语言中,如果不采取一点措施,还是无法与其它的类隔离开来。建设类的客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性地设计程序。[2]实际上,只有当有人试图破坏系统的安全性时,才可能发生这种情况;更有可能的是,对你的 API 产生误解的程序员,所导致的各种不可预期的行为,只好由类来处理。无论是何种情况,编写面对客户端的不良行为仍保持健壮性的类,这是非常值得投入时间去做的事情。
// Broken "immutable" time period class publicclassPeriod { privatefinal Date start; privatefinal Date end;
publicPeriod(Date start, Date end) { if (start.compareTo(end) > 0) thrownewIllegalArgumentException(start + " after " + end); this.start = start; this.end = end; }
public Date start() { return start; }
public Date end() { return end; } }
乍看之下,此类似乎是不可变的,并且加了周期的起始时间 (start) 不能在结束时间 (end) 之后。然而,因为 Date 类本身是可变的,因此很容易违反这个约束条件:
1 2 3 4 5
// Attack the internals of a Period instance Datestart=newDate(); Dateend=newDate(); Periodp=newPeriod(start, end); end.setYear(78); // Modifies internals of p!
可以肯定地说,只要有可能,都应该使用不可变的对象作为对象内部的组件,这样就不必再为保护性拷贝(见第15条)操心。在前面的 Period 例子中,有经验的程序员通常使用 Date.getTime() 返回的 long 基本类型作为内部的时间表示法, 而不是使用 Date 对象引用。他们之所以这样做,主要因为 Date 是可变的。
Oracle, Secure Coding Guidelines for Java SE, treats Java’s type safety, automatic memory management, and array bounds checks as foundations that reduce memory corruption risks. ↩︎
Joshua Bloch, Effective Java, 3rd Edition, Item 50, frames defensive copying as a way to protect class invariants from hostile or mistaken clients. ↩︎
Oracle Java SE 21 API documents Date with mutator methods such as setTime(long); Instant is documented as a value-based java.time class. ↩︎
Effective Java Item 50 uses the Period example to recommend copying mutable constructor parameters before validating and storing them. ↩︎
MITRE, CWE-367, describes Time-of-check Time-of-use races where a checked state can change before use. ↩︎
Effective Java Item 50 warns against using clone for defensive copies when the parameter type can be subclassed by untrusted code. ↩︎
Effective Java Item 50 treats returning internal mutable fields from accessors as the mirror image of saving external mutable parameters: both share write access across the object boundary. ↩︎
The ownership boundary is also reflected in Oracle Java SE 21 List.copyOf, which returns an unmodifiable list whose contents do not reflect later changes to the input collection. ↩︎
Java arrays are mutable objects; for collections, Collections.unmodifiableList returns an unmodifiable view rather than an independent copy. ↩︎
Effective Java Item 50 allows ownership transfer or trusted-boundary shortcuts only when the API contract documents the caller’s responsibility not to mutate affected parameters or return values. ↩︎
This summary follows Effective Java Item 50 and the distinction between copies, unmodifiable views, and ownership transfer captured by List.copyOf and Collections.unmodifiableList. ↩︎
var output = $@"The First five items are: { src.Take( 5 ).Select( n => $@"Item: {n.ToString()}" ).Aggregate( (c, a) => $@"{Environment.NewLine}{a}" ) }";
上面的这种写法可能不太会出现在正式的产品代码中,但可以看出,内插字符串和 C# 之间结合的相当密切。ASP.NET MVC 框架中的 Razor View 引擎也支持内插字符串,使得开发者在编写 Web 应用程序时能够更便捷地以 HTML 的形式来输出信息。默认的 MVC 应用程序本身就演示了怎样在 Razor View 中使用内插字符串,以下示例节选自 controller 部分,它可以显示当前登入的用户名:
Joshua Bloch, Effective Java, 3rd Edition, Item 11, states the practice rule that classes overriding equals must also override hashCode; Oracle Java SE 21 API, Object.hashCode(), defines the formal contract. ↩︎
Oracle Java SE 21 API, Object.hashCode(), specifies that objects equal by equals(Object) must return the same integer hash code. ↩︎
Oracle Java SE 21 API, HashMap, documents hash-table-backed map behavior and notes that constant-time performance assumes the hash function disperses elements properly among buckets; OpenJDK HashMap source stores each node’s hash and checks hash equality before key equality in lookup paths, which is the implementation boundary behind this example. ↩︎
Oracle Java SE 21 API, HashMap, describes the performance assumption around proper dispersion; OpenJDK, JEP 180, adds tree bins as a collision-mitigation mechanism rather than a replacement for good hash functions. ↩︎
// Initialize unitCircle to contain all Points on the unit circle privatestaticfinal Set<Point> unitCircle = Set.of( newPoint(1, 0), newPoint(0, 1), newPoint(-1, 0), newPoint(0, -1) );
Joshua Bloch, Effective Java, 3rd Edition, Item 10, discusses value classes and logical equality; Oracle Java SE 21 API, Object.hashCode(), ties equal objects to equal hash codes for hash-based collections. ↩︎
Oracle Java SE 21 API, Object.equals(Object), defines equals as an equivalence relation with reflexive, symmetric, transitive, consistent, and non-null requirements. ↩︎
Joshua Bloch, Effective Java, 3rd Edition, Item 10, uses the Point / ColorPoint examples to show how adding value components in subclasses can break symmetry or transitivity. ↩︎
Barbara Liskov, Data Abstraction and Hierarchy, introduces the substitution framing behind the Liskov substitution principle; Effective Java Item 10 recommends composition rather than extending a value superclass when new value components affect equality. ↩︎
Oracle Java SE 21 API, Timestamp, documents the Timestamp / Date equality asymmetry caused by the nanoseconds component. ↩︎
Oracle Java SE 21 API, URL.equals(Object), documents host-name resolution as part of URL equality, which is why it is a poor model for stable value-object equality. ↩︎
Oracle Java SE 21 API, Float.compare(float, float) and Double.compare(double, double), document primitive comparison helpers for floating-point values; JLS §15.21.1 and Float.equals(Object) explain the NaN / signed-zero equality boundary. In Effective Java Item 10, the autoboxing warning applies to wrapper-object equality such as Float.equals / Double.equals, not to the primitive compare calls themselves. ↩︎
EqualsVerifier, Manual, documents automated checks for equals and hashCode contracts; Effective Java Item 10 recommends testing symmetry, transitivity, and consistency when implementing equals manually. ↩︎
Oracle Java SE 21 API, Object.hashCode(), requires equal objects to return the same integer hash code. ↩︎
Oracle Java SE 21 API, Object.equals(Object), defines the method signature that must be overridden; Oracle Java SE 21 API, @Override, documents compiler checking that a method overrides or implements a supertype method. ↩︎
Oracle Java SE 21 API, Object.equals(Object), provides the five-part contract that custom equals implementations must satisfy. ↩︎