赞
踩
初代版本,伟大的一个里程碑,但是是纯解释运行,使用外挂JIT,性能比较差,运行速度慢。
主要特性有:
反射参考博文:一文读懂反射那些事
主要特性有:
集合使用与原理参考博文:集合与数据结构
主要特性有:
主要特性有:
正则表达式详解参考博文:正则表达式基础语法与Java、JS使用实例
主要有:
泛型是JDK1.5中一个最“酷”的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出 ClassCastExceptions的可能。在JDK1.5中,你可以声明一个集合将要接收/返回的对象的类型。在JDK1.4中,创建雇员名字的清单 (List)需要一个集合对象,像下面的语句:
List listOfEmployeeName = new ArrayList();
在JDK1.5中,你将使用下面语句
List<String> listOfEmployeeName = new ArrayList<String>();
如果你试图插入非string类型的值,你将在编译时发现并且修正这类问题。没有泛型,很可能你所编写的程序抛出ClassCastException异常而崩溃。
JDK1.5中Collection类库的大部分类都被改进为Generic类。需要注意的是类型值信息只为Java编译器在编译时所用,确保代码无类型安全问题;验证通过之后,即被去除(泛型擦除)。对于JVM而言,只有如JDK1.5之前版本一样的 List,并无List和List之分。这也就是Java Generics实现中关键技术Erasure的基本思想。以下代码在控制台输出的就是“true”。
List<String> strList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();
System.out.println(strList.getClass() == intList.getClass());
可以将Generic理解为:为提高Java代码类型安全性(在编译时确保,而非等到运行时才暴露),Java代码与Java编译器之间新增的一种约定规 范。Java编译器在编译结果*.class文件中供JVM读取的部分里没有保留Generic的任何信息,JVM看不到Generic的存在。
对于Generic类(设为GenericClass)的类型参数(设为T):
class GenericClass<T> { T t1; public void method1(T t){ t1 = new T(); //编译错误,T不能与new联用 if (t1 instanceof T) {}; //编译错误,T不能与instanceof联用 }; static T t2; //编译错误,静态字段不能使用T public static void method2(T t){};//编译错误,静态方法不能使用T }
Generic类可以有多个类型参数,且类型参数命名一般为大写单字符。例如Collection类库中的Map声明为:
public interface Map<K,V> {
//...
}
Generic类和原(Raw)类
对每一个Generic类,用户在使用时可以不指定类型参数。例如,对于List,用户可以以“List list;”方式使用,也可以以“List list;”方式使用。“List”被称为参数化的Generic类(类型参数被赋值),而“List”称为原类。原类 List的使用方式和效果与JDK1.5之前版本List的一样,使用原类也就失去了Generic带来的可读性和健壮性的增强。
允许原类使用方式的存在显然是为了代码的向前兼容:即JDK1.5之前的代码在JDK1.5下仍然编译通过且正常运行。
当你在JDK1.5中使用原类并向原类实例中添加对象时,编译器会产生警告,因为它无法保证待添加对象类型的正确性。编译通过是为了保证代码向前兼容,产生警告是提醒潜在的风险。
泛型的使用参考博文:泛型系列讲解
在JDK1.5之前版本下的For循环语法如下:
void printAll(Collection c) {
//这里采用迭代器形式
for (Iterator i = c.iterator(); i.hasNext(); ) {
Employee emp = (Employee)i.next();
System.out.println(emp.getName());
}
}
现在,用增强的For语句实现相同方法:
void printAll(Collection c) {
for (Object o : c)
System.out.println((TimerTask)o).getName());
}
Java有基本数据类型,在这些基本数据类型周围又有包装类。通常,编程人员需要将一种类型转换成另一种。
jdk1.5以前:
public class Employee {
private static final Integer CHILD = new Integer(0);
public static void main(String args[]) {
//code for adding n to an Integer
int n = 10;
Integer age = new Integer(30);
Integer ageAfterTenYear = new Integer(age.intValue +10);
}
}
jdk1.5后使用自动拆装箱:
public class Employee {
public static void main(String args[]) {
int n =10;
Integer age = new Integer(30);
Integer ageAfterTenYear = age +10;
}
}
类型安全枚举提供下列特性:
实例一:
enum Season { winter, spring, summer, fall }
实例二:
public enum Coin {
penny(1), nickel(5), dime(10), quarter(25);
Coin(int value) { this.value = value; }
//设置属性
private final int value;
//设置方法
public int value() { return value; }
}
参考博文:枚举类的详解与实例
静态导入使代码更易读。通常,你要使用定义在另一个类中的常量(constants),像这样:
import org.yyy.pkg.Increment;
class Employee {
public Double calculateSalary(Double salary{
return salary + Increment.INCREMENT * salary;
}
}
当时使用静态导入,我们无需为常量名前缀类名就能使用这些常量,像这样:
import static org.yyy.pkg.Increment;
class Employee {
public Double calculateSalary(Double salary{
return salary + INCREMENT * salary;
}
}
注意,我们可以调用INCREMENT这一常量而不要使用类名Increment.。
元数据特征志于使开发者们借助厂商提供的工具可以进行更简易的开发。实例如下(Remote是用于远程服务调用的接口):
import org.yyy.hr;
public interface EmployeeI extends Java.rmi.Remote {
public String getName() throws Java.rmi.RemoteException;
public String getLocation () throws Java.rmi.RemoteException;
}
public class EmployeeImpl implements EmployeeI {
public String getName() {
}
public String getLocation () {
}
}
通过元数据的支持,你可以改写实例代码为:
import org.yyy.hr;
public class Employee {
@Remote public String getName() {
...
}
@Remote public public String getLocation() {
...
}
}
Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利。为了编写高效稳定可靠的多线程程序,线程部分的新增内容显得尤为重要。
线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。
多线程和线程池的系列博文参考:多线程并发和线程池
主要特性有:
在JDK1.6中,AWT新增加了两个类:Desktop和SystemTray。
前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档。
Desktop内部有一个静态枚举类,其实例对象代表不同动作:
public static enum Action {
OPEN,
EDIT,
PRINT,
MAIL,
BROWSE
};
后者可以用来在系统托盘区创建一个托盘程序。
JAXB是Java Architecture for XML Binding的缩写,可以将一个Java对象转变成为XML格式,反之亦然。
我们把对象与关系数据库之间的映射称为ORM,其实也可以把对象与XML之间的映射称为OXM(Object XML Mapping)。原来JAXB是Java EE的一部分,在JDK1.6中,SUN将其放到了Java SE中,这也是SUN的一贯做法。JDK1.6中自带的这个JAXB版本是2.0,比起1.0(JSR 31)来,JAXB2(JSR 222)用JDK5的新特性Annotation来标识要作绑定的类和属性等,这就极大简化了开发的工作量。
实际上,在Java EE 5.0中,EJB和Web Services也通过Annotation来简化开发工作。另外,JAXB2在底层是用StAX(JSR 173)来处理XML文档。除了JAXB之外,我们还可以通过XMLBeans和Castor等来实现同样的功能。
StAX(JSR 173)是JDK1.6.0中除了DOM和SAX之外的又一种处理XML文档的API。
StAX 的来历:在JAXP1.3(JSR 206)有两种处理XML文档的方法—DOM(Document Object Model)和SAX(Simple API for XML)。
JDK1.6.0中的JAXB2(JSR 222)和JAX-WS 2.0(JSR 224)都会用到StAX。Sun决定把StAX加入到JAXP家族当中来,并将JAXP的版本升级到1.4(JAXP1.4是JAXP1.3的维护版 本)。JDK1.6里面JAXP的版本就是1.4。
StAX是The Streaming API for XML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API。StAX通过提供一种基于事件迭代器(Iterator)的API让 程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每一个解析事件,解析事件可以看做是程序拉出来的,也就是程序促使解析器产生一个解析事件 然后处理该事件,之后又促使解析器产生下一个解析事件,如此循环直到碰到文档结束符。
SAX也是基于事件处理xml文档,但却是用推模式解析,解析器解析完整个xml文档后,才产生解析事件,然后推给程序去处理这些事件。
DOM采 用的方式是将整个xml文档映射到一颗内存树,这样就可以很容易地得到父节点和子结点以及兄弟节点的数据,但如果文档很大,将会严重影响性能.
现在我们可以用JDK1.6 的Compiler API(JSR 199)去动态编译Java源文件,Compiler API结合反射功能就可以实现动态的产生Java代码并编译执行这些代码,有点动态语言的特征。
这个特性对于某些需要用到动态编译的应用程序相当有用,比如JSP Web Server,当我们手动修改JSP后,是不希望需要重启Web Server才可以看到效果的,这时候我们就可以用Compiler API来实现动态编译JSP文件,当然,现在的JSP Web Server也是支持JSP热部署的,现在的JSP Web Server通过在运行期间通过Runtime.exec或ProcessBuilder来调用javac来编译代码,这种方式需要我们产生另一个进程去 做编译工作,不够优雅容易使代码依赖与特定的操作系统。
Compiler API通过一套易用的标准的API提供了更加丰富的方式去做动态编译,是跨平台的。
JDK1.6 提供了一个简单的Http Server API,据此我们可以构建自己的嵌入式Http Server,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的Http Server API来实现,程序员自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这 里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给 HttpHandler实现类的回调方法.
插入式注解处理API(JSR 269)提供一套标准API来处理Annotations(JSR 175)。
实际上JSR 269不仅仅用来处理Annotation,我觉得更强大的功能是它建立了Java 语言本身的一个模型,它把method,package,constructor,type,variable, enum,annotation等Java语言元素映射为Types和Elements(两者有什么区别?),从而将Java语言的语义映射成为对象,我 们可以在javax.lang.model包下面可以看到这些类. 我们可以利用JSR 269提供的API来构建一个功能丰富的元编程(metaprogramming)环境。
JSR 269用Annotation Processor在编译期间而不是运行期间处理Annotation,Annotation Processor相当于编译器的一个插件,称为插入式注解处理。如果Annotation Processor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次Annotation Processor,如果第二次处理还有新代码产生,就会接着调用Annotation Processor,直到没有新代码产生为止.每执行一次process()方法被称为一个"round",这样整个Annotation processing过程可以看作是一个round的序列。
JSR 269主要被设计成为针对Tools或者容器的API. 举个例子,我们想建立一套基于Annotation的单元测试框架(如TestNG),在测试类里面用Annotation来标识测试期间需要执行的测试方法.
JDK1.6中提供了java.io.Console 类专用来访问基于字符的控制台设备。你的程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳。 但我们不总是能得到可用的Console,一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用。如果JVM是在交互式命令行(比如 Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例。
如: ruby,groovy,javascript
Common annotations原本是Java EE 5.0(JSR 244)规范的一部分,现在SUN把它的一部分放到了Java SE 6.0中。
随着Annotation元数据功能(JSR 175)加入到Java SE 5.0里面,很多Java 技术(比如EJB,Web Services)都会用Annotation部分代替XML文件来配置运行参数(或者说是支持声明式编程,如EJB的声明式事务),如果这些技术为通用 目的都单独定义了自己的Annotations,显然有点重复建设。为其他相关的Java技术定义一套公共的Annotation是有价值的,可以避免 重复建设的同时,也保证Java SE和Java EE 各种技术的一致性。
主要特性有:
首先说明一点,网上所说的所谓jdk1.7新特性中对“集合类语言的支持”是错的,实践证明并不可以,官网也并没有说该特性,不少博客以讹传讹。
Java中某些资源是需要手动关闭的,如InputStream,Writes,Sockets,Sql classes等。这个新的语言特性允许try语句本身申请更多的资源, 这些资源作用于try代码块,并自动关闭。
实例如下:
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
修改为如下:
try (BufferedReader br = new BufferedReader(new FileReader(path)) {
return br.readLine();
}
可以定义关闭多个资源:
try (
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest))
{
// code
}
为了支持这个行为,所有可关闭的类将被修改为实现一个Closable(可关闭的)接口。
类型推断是一个特殊的烦恼,下面的代码:
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
通过类型推断后变成:
Map<String, List<String>> anagrams = new HashMap<>();
这个<>被叫做diamond(钻石)运算符,这个运算符从引用的声明中推断类型。
很长的数字可读性不好,在Java 7中可以使用下划线分隔长int以及long了,如:
int one_million = 1_000_000;
运算时先去除下划线,如:1_1 * 10 = 110,120 – 1_0 = 110
以前你在switch中只能使用number或enum。现在可以使用string了:
String s = ...
switch(s) {
case "quux":
processQuux(s);
case "foo":
case "bar":
processFooOrBar(s);
break;
case "baz":
processBaz(s);
default:
processDefault(s);
break;
}
由于继承C语言,Java代码在传统上迫使程序员只能使用十进制,八进制或十六进制来表示数(numbers)。
由于很少的域是以bit导向的,这种限制可能导致错误。现在,你可以使用二进制字面量这种表示方式,并且使用非常简短的代码,可将二进制字符转换为数据类型,如在byte或short。
byte aByte = (byte)0b001;
short aShort = (short)0b010;
int binary = 0b1001_1001;
当程序员试图使用一个不可具体化的可变参数并调用一个varargs(可变)方法时,编辑器会生成一个“非安全操作”的警告。
JDK 7将警告从call转移到了方法声明(methord declaration)的过程中。这样API设计者就可以使用vararg,因为警告的数量大大减少了。
NIO即非阻塞IO,Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。随着JDK 7 的发布,Java对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,以至于我们称他们为NIO.2。因为NIO 提供的一些功能,NIO已经成为文件处理中越来越重要的部分。
关于NIO和NIO2.0特性参考博文:IO/NIO那些事
Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Java 8 是oracle公司于2014年3月发布,可以看成是自Java 5 以来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。
主要特性有:
在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
可以直接在lambda表达式中访问外层的局部变量。
代码如下:
final int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
但是和匿名对象不同的是,这里的变量num可以不用声明为final,该代码同样正确。
代码如下:
int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
不过这里的num必须不可被后面的代码修改(即隐性的具有final的语义),例如下面的就无法编译:
int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
num = 3;
在lambda表达式中试图修改num同样是不允许的。
和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的:
class Lambda4 { static int outerStaticNum; int outerNum; void testScopes() { Converter<Integer, String> stringConverter1 = (from) -> { outerNum = 23; return String.valueOf(from); }; Converter<Integer, String> stringConverter2 = (from) -> { outerStaticNum = 72; return String.valueOf(from); }; } }
Lambda表达式中是无法访问到默认方法的,以下代码将无法编译:
Formula formula = (a) -> sqrt( a * 100);
//Built-in Functional Interfaces
Map类型不支持stream,不过Map提供了一些新的有用的方法来处理一些日常任务。
实例如下:
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
map.putIfAbsent(i, "val" + i);
}
map.forEach((id, val) -> System.out.println(val));
以上代码很容易理解, putIfAbsent 不需要我们做额外的存在性检查,而forEach则接收一个Consumer接口来对map里的每一个键值对进行操作。
下面的例子展示了map上的其他有用的函数:
map.computeIfPresent(3, (num, val) -> val + num);
map.get(3); // val33
map.computeIfPresent(9, (num, val) -> null);
map.containsKey(9); // false
map.computeIfAbsent(23, num -> "val" + num);
map.containsKey(23); // true
map.computeIfAbsent(3, num -> "bam");
map.get(3); // val33
map.getOrDefault(42, "not found"); // not found
接下来展示如何在Map里删除一个键值全都匹配的项:
map.remove(3, "val3");
map.get(3); // val33
map.remove(3, "val33");
map.get(3); // null
对Map的元素做合并也变得很容易了:
map.merge(9, "val9", (value, newValue) -> value.concat(newValue));
map.get(9); // val9
map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
map.get(9); // val9concat
Merge做的事情是如果键名不存在则插入,否则则对原键对应的值做合并操作并重新插入到map中。
jdk1.8的其他特性详解讲解参考博客:JDK1.8新特性一二三
经过4次跳票,历经曲折的java 9 终于终于在2017年9月21日发布。java 9 提供了超过150项新功能特性,包括备受期待的模块化系统、可交互的 REPL 工具:jshell,JDK 编译工具,Java 公共 API 和私有代码,以及安全增强、扩展提升、性能管理改善等。可以说Java 9是一个庞大的系统工程,完全做了一个整体改变。
主要特性具体来讲:
根据官网的公开资料,共有12个重要特性,如下:
\$FEATURE.\$INTERIM.\$UPDATE.\$PATCH
,分别是大版本,中间版本,升级包和补丁版本。翻译后的新特性有:
不定期整理分享。。
根据下面文章进行的整理:
https://blog.csdn.net/J080624/article/details/85092655
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。