java的奇技淫巧--意外行为与特性(译文)

Java是一种非常成熟的编程语言 - 事实上,它已经走过21年了,如果它是一个人,它可以在美国随便混!随着年龄的增长,智慧也在增长,而至少有时候,有些东西会变得很怪异。在本文中,我将介Java语言的一些奇技淫巧的行为和特征。

在这里,没有特别的顺序去介绍一系列Java的奇技淫巧,仅供娱乐,或者你向朋友们推介它吧。

Java有goto和const关键字

虽然Java没有goto,但它确实作为保留关键字。const也是这样。这意味着您无法这两个名称定义变量:

int goto = 0;

int const = 0;

这样的定义是非法的,无法正常编译!

用“_”符号定义数字

Java允许您使用“_”符号定义数字。因此,您可以像这样编写数值:

int thousand = 1_000;

double bigValue = 1_000_000.456_555;

long thisIsSilly = 3______4__3;

Double.MIN_VALUE不是许多人所假设的

为了展示Double.MAX_VALUE结果比预期的效果要完美,提供以下这样的数值:1.7976931348623157E308。您认为Double.MIN_VALUE会为您带来什么?4.9E-324!好,执行开始 – 结果这个值大于0!

Double.MIN_VALUE是返回大于0的最小Double值(最小正数)。如果您想要最小的Double值,则需要使用:-Double.MAX_VALUE。他们实际上可以更好地命名这些东西,我想知道这样的做法引起了多少人为的错误!

有趣的整数相等问题

谈到这个错误......让我告诉你一些迷惑不解的事情:

Integer ten = Integer.parseInt("10");

System.out.println(ten == Integer.valueOf(10));

//this is true

Integer thousand = Integer.parseInt("1000");

System.out.println(thousand == Integer.valueOf(1000));

//this is false

Integer对象的缓存值的大小范围是在[-128 127]区间。这意味着当我们在此数值范围内操作时,“==”比较能正常返回结果。但当数值不在此范围,对象相等的比较是否正常返回结果就很难说了!

想象一下,你可以编写单元测试,且一切都正常运行,只要你没有使用足够大的数字,但这可能会导致严重的错误,所以为了安全 - 提醒:当你经常使用对象数值比较相等时,请使用“.equals()”,而不是依赖于“==”比较相等,除非你非常肯定这种做法没有错误。

反射可以(大多数情况)做任何事情

这不应该作为一个Java奇技淫巧的内容,但通过反射,你可以重写final值(大多数时间)并可访问私有字段......但不一定经常是这样。

在我写How to write horrible Java的文章时,当我重写final值得时候,我发现了无法与预期结果一致的问题。Java中的常量,当final被内联时(通指内联函数),即使你的代码看起来可以正常运行—没有数值情况也会改变,这太不可思议了(查看我的文章了解详情和Stack Overflow答案)。

如果你需要,这是重写final的数值代码例子:

public static void notSoFinal() throws NoSuchFieldException, IllegalAccessException, InterruptedException {

ExampleClass example = new ExampleClass(10);

System.out.println("Final value was: "+ example.finalValue);

Field f = example.getClass().getDeclaredField("finalValue");

Field modifiersField = Field.class.getDeclaredField("modifiers");

modifiersField.setAccessible(true);

modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

f.setInt(example, 77);

System.out.println("Final value was: "+ example.finalValue);

}

你知道Java标签是什么玩意吗?

好吧,我们离开上面调皮的话题,回到Java正规上来。你知不知道Java循环标签?看一下这个循环语句:

outerLoop:

while (true) {

System.out.println("I‘m the outer loop");

while(true){

System.out.println("I am the inner loop");

break outerLoop;

}

}

使用标签可以让你在处理嵌套循环的时候,继续或中断一个特定的循环……在不同语言环境下,这个有点类似goto,

现在让我们编写一个编译好了的,形迹可疑的代码:

int i = 3;

http://www.e4developer.com

while(i > 0){

System.out.println("http://www.e4developer.com");

i--;

}

可以正常编译并且正常运行,因为它只是一个附加注释的标记为http的循环。这会让那些不熟悉标签的人,使得它变得特别有趣!

枚举类

好吧,你可能知道这一点,但我还是想重复提一下。枚举是具有有限数量实例的特殊类。这意味着枚举可以:

实现接口

具有构造函数

实现不同方法

对于Scott Logic博客,我写了一篇名为 Java Enums – how to use them smarter 的文章,我展示了一些其他的使用方法。

For循环的灵活性

循环的标准,我相信你使用它们的次数,比你记忆中的还要多:

for(int i = 0; i < 100; i++){

//...

}

您知不知道里面所有条件是可选的吗?你不需要初始化一个变量,你也不需要一个条件停止,你也不需要增加任何东西......如果省略所有内容,你最终会得到一个有趣的无限循环语法:

for(;;){

//Infinite loop!

}

 

Java有初始化程序......以防万一...

这是一个非常通用的特性,但是我还是依然会遇到一些具有经验的Java开发人员,他们并不会真正意识到它的存在。在Java中,您可以写类加载(静态初始化程序)或构造函数(标准初始化程序)之前运行的代码块。它是这样的。

标准初始化程序:

int sum = 0;

{

for(int i = 0; i < 1; i++){

sum += 1;

}

}

静态初始化程序:

static double value = 0;

static {

for(int i = 0; i < 1; i++){

value += 1;

}

}

只需要将这些代码块放在类中,不要放在任何方法或构造函数中。

双括号初始化集合

关于初始化的话题,我会向你展示Java初始化集合的奇技淫巧:

Map<String, String> map = new HashMap<String, String>() {{

put("it", "really");

put("works", "!");

}};

Set<String> set = new HashSet<String>() {{

add("It");

add("works");

add("with");

add("other");

add("collections");

add("too");

}};

它在Java中被称为双括号初始化,我从未见过这样的写法,被任何人使用过……难道是因为没有人知道使用它吗?

在发表这篇文章之后,很多读者很快告诉我,这是我们应该避免的一个危险行为!比如应当使用辅助方法List.of()代替。(注意,双括号初始化会派生匿名类。派生的类this可以指向外部的类。通常这不是什么大问题,但在某些情况下使用不当会引起悲剧的问题,例如在序列化或垃圾回收时,应当注意这个问题)

Final值的可以放在后面初始化

这是一个小事情,但有些人认为,你在定义它们时时候,必须初始化常量值。实际情况不是这样,您只需要初始化它们一次就够了,你可以使用以下有效代码核对一下:

final int a;

if(someCondition){

a = 1;

} else {

a = 2;

}

System.out.println(a);

当我们混合初始化代码块和其他构造函数时,这么做会变得棘手。

泛型扩展的桥接

尽管存在可疑的实现(类型擦除),但泛型在Java中还是非常强大。我吃惊的是,我们可以允许定义我们需要的泛型类型。看看这个例子:

public class SomeClass<T extends ClassA & InterfaceB & InterfaceC>

{}

你特别需要注意你定义的T,这特性会对你非常有用!

你还有更多吗?

我希望你喜欢我分享的Java奇技淫巧。如果你还知道其他的Java特性和行为,并值得分享,请务必在评论或Twitter上告诉我!

原文:https://www.e4developer.com/2018/10/28/java-surprises-unexpected-behaviours-and-features/

原文地址:https://www.cnblogs.com/david1989/p/9897562.html

时间: 2024-11-05 23:22:09

java的奇技淫巧--意外行为与特性(译文)的相关文章

用Java来比较JavaScript的一些特性

由于是从java做到JavaScript,所以对强弱语言类型,还是比较敏感的.JavaScript是弱语言,只严格区分数据和指令.简单描述下自己对两者之间的一些区别吧. 1.JavaScript变量的类型取决于右侧的对象. JavaScript: var variable_name = new Object(); Java: Object variable_name = new Object(); 2.JavaScript没有块级作用域, Java: if(true) { Object a =

Java 8的八个新特性

Java 8的八个新特性 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs 1.接口的默认方法和静态方法 Java 8在接口方面引入了新特性. Java 8版之前,接口只有抽象方法,而在Java 8,为接口新增了两种类型的方法. 第一种是默认方法.此方法使用了default关键字修饰方法名.实际上接口不包含任何实现的方法,而在Java 8中,可以通过使用default关键字来添加默认的方法实现. 接口的实现类可以直接使

你可能没听过的 Java 8 中的 10 个特性

你以前听到的谈论关于Java8的所有都是围绕lambda表达式. 但它仅仅是Java8的一部分. Java 8 有许多新特性---一些强大的新类和语法, 还有其他的从一开始就应该具有的东西. 我将要介绍我认为值得了解的10个精华特性. 它们中最少也会有一个或两个你想要试一试, 所以我们开始吧! 1. 默认方法 Java语言一个新添加的特性是你可以为接口(interface)的方法添加方法体(称为默认方法). 这些方法会被隐式地添加到实现这个接口的类中. 这能使你在不破坏代码的情况下为已存在的库添

Cause: org.apache.ibatis.executor.ExecutorException: Error getting generated key or setting result to parameter object. Cause: java.sql.SQLException: 不支持的特性

mybatis插入数据时报错: Cause: org.apache.ibatis.executor.ExecutorException: Error getting generated key or setting result to parameter object. Cause: java.sql.SQLException: 不支持的特性 at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFacto

java中的三(四)大特性

java中的三(四)大特性 :继承 . 封装 .多态.(抽象) 类与类之间的关系: is-a                   继承 .实现 继承的表现:使用extends继承父类 实现的表现:使用importance实现接口 has-a                组合 .聚合.关联 关联的表现:关联关系一般使用成员变量来实现. use-a (need-a)  依赖 依赖的表现,一个类的方法操作另一个类的对象 例如:人(Person) 开 车(Car) 继承 使用extends关键词  子

JAVA核心技术 卷II:高级特性(原书第8版)下载 &#363916;

下载地址: http://www.gqylpy.com/di/12 <JAVA核心技术 卷II:高级特性>PDF高清完整版-下载 前言致读者本书是按照Java?SE?8完全更新后的<Java核心技术??卷Ⅱ??高级特性(原书第10版)>.卷Ⅰ主要介绍了Java语言的一些关键特性:而本卷主要介绍编程人员进行专业软件开发时需要了解的高级主题.因此,与本书卷Ⅰ和之前的版本一样,我们仍将本书定位于用Java技术进行实际项目开发的编程人员.????编写任何一本书籍都难免会有一些错误或不准确的

Java面向基础概述和三大特性

Java 是面向对象的高级编程语言,类和对象是 Java 程序的构成核心.围绕着 Java 类和 Java 对象,有三大基本特性:封装是 Java 类的编写规范.继承是类与类之间联系的一种形式.而多态为系统组件或模块之间解耦提供了解决方案. 本文主要围绕这三大特性介绍一下 Java 面向对象.组件解耦的核心思想. 1.面向对象思想 面向对象编程是当今主流的程序设计思想,已经取代了过程化程序开发技术,Java 是完全面向对象编程语言,所以必须熟悉面向对象才能够编写 Java 程序. 面向对象的程序

java语言的11个关键特性

(1)easy:java的语法比c++的相对简单,另一个方面就是java能使软件在很小的机器上运行,基础解释其和类库的支持的大小约为40kb,增加基本的标准库和线程支持的内存需要增加125kb. (2)分布式:java带有很强大的tcp/ip协议族的例程库,java应用程序能够通过url来穿过网络来访问远程对象,由于servlet机制的出现,使java编程非常的高效,现在许多的大的webserver都支持servlet. (3)oo:面向对象设计是把重点放在对象及对象的接口上的一个编程技术.其面

java 1.7 1.8新特性

在JDK1.7的新特性方面主要有下面几方面的增强:1.jdk7语法上1.1二进制变量的表示,支持将整数类型用二进制来表示,用0b开头.1.2 Switch语句支持string类型1.3 Try-with-resource语句 注意:实现java.lang.AutoCloseable接口的资源都可以放到try中,跟final里面的关闭资源类似: 按照声明逆序关闭资源 ;Try块抛出的异常通过Throwable.getSuppressed获取1.4 Catch多个异常 说明:Catch异常类型为fi