本文目录一览:
java8的特性有哪些
Lambda表达式(也称为闭包)它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理
Java 8使用两个新概念扩展了接口的含义:默认方法和静态方法。
方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。
重复注解,Java 8中使用@Repeatable注解定义重复注解
Java 8编译器在类型推断方面有很大的提升,在很多场景下编译器可以推导出某个参数的数据类型,从而使得代码更为简洁。
Java 8拓宽了注解的应用场景。
Java 8增加了很多新的工具类(date/time类),并扩展了现存的工具类,以支持现代的并发编程、函数式编程等。
java8中的字符串的用法
1.
首先String不属于8种基本数据类型,String是一个对象。
因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。
2.
new String()和new String(“”)都是申明一个新的空字符串,是空串不是null;
3.
String str=”kvill”;
String
str=new String (“kvill”);的区别:
在这里,我们不谈堆,也不谈栈,只先简单引入常量池这个简单的概念。
常量池(constant
pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。
看例1:
String
s0=”kvill”;
String
s1=”kvill”;
String
s2=”kv” + “ill”;
System.out.println(
s0==s1 );
System.out.println(
s0==s2 );
结果为:
true
true
首先,我们要知道Java会确保一个字符串常量只有一个拷贝。
因为例子中的s0和s1中的”kvill”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而”kv”和”ill”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中
”kvill”的一个引用。
所以我们得出s0==s1==s2;
用new
String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。
看例2:
String
s0=”kvill”;
String
s1=new String(”kvill”);
String
s2=”kv” + new String(“ill”);
System.out.println(
s0==s1 );
System.out.println(
s0==s2 );
System.out.println(
s1==s2 );
结果为:
false
false
false
例2中s0还是常量池中”kvill”的应用,s1因为无法在编译期确定,所以是运行时创建的新对象”kvill”的引用,s2因为有后半部分new
String(“ill”)所以也无法在编译期确定,所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。
4.
String.intern():
再补充介绍一点:存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;看例3就清楚了
例3:
String
s0= “kvill”;
String
s1=new String(”kvill”);
String
s2=new String(“kvill”);
System.out.println(
s0==s1 );
System.out.println(
“**********” );
s1.intern();
s2=s2.intern();
//把常量池中“kvill”的引用赋给s2
System.out.println(
s0==s1);
System.out.println(
s0==s1.intern() );
System.out.println(
s0==s2 );
结果为:
false
**********
false
//虽然执行了s1.intern(),但它的返回值没有赋给s1
true
//说明s1.intern()返回的是常量池中”kvill”的引用
true
最后我再破除一个错误的理解:
有人说,“使用String.intern()方法则可以将一个String类的保存到一个全局String表中,如果具有相同值的Unicode字符串已经在这个表中,那么该方法返回表中已有字符串的地址,如果在表中没有相同值的字符串,则将自己的地址注册到表中“如果我把他说的这个全局的
String表理解为常量池的话,他的最后一句话,“如果在表中没有相同值的字符串,则将自己的地址注册到表中”是错的:
看例4:
String
s1=new String("kvill");
String
s2=s1.intern();
System.out.println(
s1==s1.intern() );
System.out.println(
s1+" "+s2 );
System.out.println(
s2==s1.intern() );
结果:
false
kvill
kvill
true
在这个类中我们没有声名一个”kvill”常量,所以常量池中一开始是没有”kvill”的,当我们调用s1.intern()后就在常量池中新添加了一个”kvill”常量,原来的不在常量池中的”kvill”仍然存在,也就不是“将自己的地址注册到常量池中”了。
s1==s1.intern()为false说明原来的“kvill”仍然存在;
s2现在为常量池中“kvill”的地址,所以有s2==s1.intern()为true。
5.
关于equals()和==:
这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。
6.
关于String是不可变的
这一说又要说很多,大家只要知道String的实例一旦生成就不会再改变了,比如说:String
str=”kv”+”ill”+” “+”ans”;
就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和”
“ 生成 ”kvill “存在内存中,最后又和生成了”kvill
ans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量,这也就是为什么建议用StringBuffer的原因了,因为StringBuffer是可改变的。
Java8有哪些新特性
jdk1.8的新特性包括如下:
一、接口的默认方法与静态方法,也就是接口中可以有实现方法
二、Lambda 表达式
三、函数式接口与静态导入
四、Lambda 作用域
在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
五、访问局部变量,等等其他新特性。
Java8的特性有哪些
1、函数式接口
Java 8 引入的一个核心概念是函数式接口(Functional Interfaces)。通过在接口里面添加一个抽象方法,这些方法可以直接从接口中运行。如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。同时,引入了一个新的注解:@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口。这个注解是非必须的,只要接口只包含一个方法的接口,虚拟机会自动判断,不过最好在接口上使用注解 @FunctionalInterface 进行声明。在接口中添加了 @FunctionalInterface 的接口,只允许有一个抽象方法,否则编译器也会报错。
java.lang.Runnable 就是一个函数式接口。
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
2、Lambda 表达式
函数式接口的重要属性是:我们能够使用 Lambda 实例化它们,Lambda 表达式让你能够将函数作为方法参数,或者将代码作为数据对待。Lambda 表达式的引入给开发者带来了不少优点:在 Java 8 之前,匿名内部类,监听器和事件处理器的使用都显得很冗长,代码可读性很差,Lambda 表达式的应用则使代码变得更加紧凑,可读性增强;Lambda 表达式使并行操作大集合变得很方便,可以充分发挥多核 CPU 的优势,更易于为多核处理器编写代码;
Lambda 表达式由三个部分组成:第一部分为一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数;第二部分为一个箭头符号:-;第三部分为方法体,可以是表达式和代码块。语法如下:
1. 方法体为表达式,该表达式的值作为返回值返回。
(parameters) - expression
2. 方法体为代码块,必须用 {} 来包裹起来,且需要一个 return 返回值,但若函数式接口里面方法返回值是 void,则无需返回值。
(parameters) - { statements; }
例如,下面是使用匿名内部类和 Lambda 表达式的代码比较。
下面是用匿名内部类的代码:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.print("Helllo Lambda in actionPerformed");
}
});
下面是使用 Lambda 表达式后:
button.addActionListener(
\\actionPerformed 有一个参数 e 传入,所以用 (ActionEvent e)
(ActionEvent e)-
System.out.print("Helllo Lambda in actionPerformed")
);
上面是方法体包含了参数传入 (ActionEvent e),如果没有参数则只需 ( ),例如 Thread 中的 run 方法就没有参数传入,当它使用 Lambda 表达式后:
Thread t = new Thread(
\\run 没有参数传入,所以用 (), 后面用 {} 包起方法体
() - {
System.out.println("Hello from a thread in run");
}
);
通过上面两个代码的比较可以发现使用 Lambda 表达式可以简化代码,并提高代码的可读性。
为了进一步简化 Lambda 表达式,可以使用方法引用。例如,下面三种分别是使用内部类,使用 Lambda 表示式和使用方法引用方式的比较:
//1. 使用内部类
FunctionInteger, String f = new FunctionInteger,String(){
@Override
public String apply(Integer t) {
return null;
}
};
//2. 使用 Lambda 表达式
FunctionInteger, String f2 = (t)-String.valueOf(t);
//3. 使用方法引用的方式
FunctionInteger, String f1 = String::valueOf;
要使用 Lambda 表达式,需要定义一个函数式接口,这样往往会让程序充斥着过量的仅为 Lambda 表达式服务的函数式接口。为了减少这样过量的函数式接口,Java 8 在 java.util.function 中增加了不少新的函数式通用接口。例如:
FunctionT, R:将 T 作为输入,返回 R 作为输出,他还包含了和其他函数组合的默认方法。
PredicateT :将 T 作为输入,返回一个布尔值作为输出,该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(与、或、非)。
ConsumerT :将 T 作为输入,不返回任何内容,表示在单个参数上的操作。
例如,People 类中有一个方法 getMaleList 需要获取男性的列表,这里需要定义一个函数式接口 PersonInterface:
interface PersonInterface {
public boolean test(Person person);
}
public class People {
private ListPerson persons= new ArrayListPerson();
public ListPerson getMaleList(PersonInterface filter) {
ListPerson res = new ArrayListPerson();
persons.forEach(
(Person person) -
{
if (filter.test(person)) {//调用 PersonInterface 的方法
res.add(person);
}
}
);
return res;
}
}
为了去除 PersonInterface 这个函数式接口,可以用通用函数式接口 Predicate 替代如下:
class People{
private ListPerson persons= new ArrayListPerson();
public ListPerson getMaleList(PredicatePerson predicate) {
ListPerson res = new ArrayListPerson();
persons.forEach(
person - {
if (predicate.test(person)) {//调用 Predicate 的抽象方法 test
res.add(person);
}
});
return res;
}
}
3、接口的增强
Java 8 对接口做了进一步的增强。在接口中可以添加使用 default 关键字修饰的非抽象方法。还可以在接口中定义静态方法。如今,接口看上去与抽象类的功能越来越类似了。
默认方法
Java 8 还允许我们给接口添加一个非抽象的方法实现,只需要使用 default 关键字即可,这个特征又叫做扩展方法。在实现该接口时,该默认扩展方法在子类上可以直接使用,它的使用方式类似于抽象类中非抽象成员方法。但扩展方法不能够重载 Object 中的方法。例如:toString、equals、 hashCode 不能在接口中被重载。
例如,下面接口中定义了一个默认方法 count(),该方法可以在子类中直接使用。
public interface DefaultFunInterface {
//定义默认方法 countdefault int count(){
return 1;
}
}
public class SubDefaultFunClass implements DefaultFunInterface {
public static void main(String[] args){
//实例化一个子类对象,改子类对象可以直接调用父接口中的默认方法 count
SubDefaultFunClass sub = new SubDefaultFunClass();
sub.count();
}
}
静态方法
在接口中,还允许定义静态的方法。接口中的静态方法可以直接用接口来调用。
例如,下面接口中定义了一个静态方法 find,该方法可以直接用 StaticFunInterface .find() 来调用。
public interface StaticFunInterface {public static int find(){
return 1;
}
}
public class TestStaticFun {
public static void main(String[] args){
//接口中定义了静态方法 find 直接被调用
StaticFunInterface.fine();
}
}
java8是java18吗
是。Java8于2014年3月18日发布,截止到2022年12月16日,当前最新发行版本是Java18,所以是,Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。