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/

最新文章

  1. Linux From Scratch(从零开始构建Linux系统,简称LFS)- Version 7.7(一)
  2. window的git extensions保存密码
  3. Linux流量监控工具-iftop教程
  4. BlueStacks 设置代理服务器 Proxifier指定任意程序的代理服务器
  5. Android中的Adapter总结
  6. HHVM 是如何提升 PHP 性能的?
  7. 【转】Adobe CC 的下载地址
  8. Oracle11g密码区分大小写导致database link无法连接
  9. CSS Hack代码与浏览兼容总结
  10. 设置角色遗留问题和为权限设置角色以及EasyUI Tabs的使用
  11. 如何面试 PHP 工程师?
  12. python的Collections 模块
  13. Java进阶(八)Java加密技术之对称加密 非对称加密 不可逆加密算法
  14. [JZOJ3588]【中山市选2014】J语言(表达式解析+栈)
  15. Logstash导入数据到ElasticSearch
  16. AngelToken钱包——值得投资与存币的钱包
  17. 2.ansible-playbook基本参数
  18. 剑指offer——python【第53题】表示数值的字符串
  19. iframe-父子-兄弟页面相互传值(jq和js两种方法)
  20. [MySQL优化1]centos中MySQL列出所有表

热门文章

  1. 分享几款流行的Java框架
  2. iOS小知识点记录
  3. REP-20147 Cannot implement column link for this detail SQL query. Converting to group link.
  4. RJ45接口定义
  5. 全栈工程师的武器——MEAN(转)
  6. 多线程-Executor,Executors,ExecutorService,ScheduledExecutorService,AbstractExecutorService
  7. spring junit 部署两套测试方案
  8. Missing artifact javax.transaction:jta:jar:1.0.1B解决办法
  9. 【iOS越狱开发】如何将应用打包成.ipa文件
  10. spring cloud 启动报错问题 Input length = 1