包含java8接口的变化的词条
本篇文章给大家谈谈java8接口的变化,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
- 1、Java8有哪些新特性
- 2、java8接口为什么可以
- 3、jdk1.8新特性
- 4、Java8这10个特性你知道多少
- 5、如何强迫自己使用java8新特性
- 6、Java8里面的java.util.Spliterator接口有什么用
Java8有哪些新特性
jdk1.8的新特性包括如下:
一、接口的默认方法与静态方法,也就是接口中可以有实现方法
二、Lambda 表达式
三、函数式接口与静态导入
四、Lambda 作用域
在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
五、访问局部变量,等等其他新特性。
java8接口为什么可以
接口可以继承接口,并且可以继承不只一个接口,但是不能实现接口。因为接口的成员方法都具有抽象属性,不具有方法体,无法实现继承的接口。
jdk1.8新特性
Java8(又称为jdk1.8)是Java语言开发迄今为止的一个最主要和用户最多的一个版本。
Java8是Oracle公司于2014年3月18日发布,它不仅支持函数式编程,而且还拥有新的日期API,StreamAPI等操作,下面胖虎带领大家一探究竟Java8的一些新特性。
ava8API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等操作。
java8添加了接口的默认方法,简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现的方法。
Java8这10个特性你知道多少
下面给你列举Java8的10个特性:
1、default方法
这是Java语言的一个新特性,现在接口类里可以包含方法体(这就是default方法)了。这些方法会隐式的添加到实现这个接口的每个子类中。
2、终止进程
一旦启动外部进程的话,当这个进程崩溃,挂起,或者CPU到达100%的时候,你就得回来擦屁股了。Process类现在增加了两个新的方法,可以来教训下那些不听话的进程了。第一个是isAlive()方法,有了它你可以判断进程是否还活着。第二个方法则更加强大,它叫destroyForcibly(),你可以用它来强制的杀掉一个已经超时或者不再需要的进程。
3、StampedLock
Java 8引入了一个新的读写锁,叫做StampedLock。它不仅更快,同时还提供了一系列强大的API来实现乐观锁,这样如果没有写操作在访问临界区域的话,你只需很低的开销就能获取到一个读锁。访问结束后你可以查询锁来判断这期间是否发生了写操作,如果有的话再选择进行重试,升级锁,或者放弃这个操作。
4、并发计数器
这是多线程程序会用到的另一个小工具。它提供了简单高效的新接口来实现多线程的并发读写计数器的功能,和AtomicInteger比起来,它要更快一些。相当赞的工具。
5、Optional
Java 8借鉴了Scala和Haskell,提供了一个新的Optional模板,可以用它来封装可能为空的引用。这绝不是终结空指针的银弹,更多只是使API的设计者可以在代码层面声明一个方法可能会返回空值,调用方应该注意这种情况。正因为这个,这只对新的API有效,前提是调用方不要让引用逃逸出封装类,否则的话引用可能会在外面被不安全的废弃掉。
6、万物皆可注解
还有一个小的改进就是现在Java注解可以支持任意类型了。之前只有像类和方法声明之类的才能使用注解。在Java 8里面,当类型转化甚至分配新对象的时候,都可以在声明变量或者参数的时候使用注解。这是Java为了更好地支持静态分析及检测工具(比如FireBug)而做的工作中的一部分。这是个很不错的特性,但是和Java 7的invokeDynamic一样,它的真正价值取决于社区以后如何去使用它。
7、数值溢出
这些方法早就该出现在Java的核心类库里了。我有个癖好就是去测试整型超出2^32时溢出的情况,搞出一些恶心的随机BUG来(怎么会得到这么奇怪的一个值?)。
同样的,这也不是什么银弹,只不过是提供了一组函数,这样你在使用+/*操作符进行数值操作的时候,如果出现了溢出,会抛一个异常。如果我可以决定的话,我会把它作为JVM的默认模式,显式的标明函数会出现数值溢出。
8、目录遍历
遍历目录树这种事通常都得上Google搜下怎么实现(你很可能用的是Apache.FileUtils)。Java 8给Files类做了一次整容手术,增加了十个新的方法。我最喜欢的一个是walk()方法,它遍历目录后会创建出一个惰性的流(文件系统很大的情况下非常有用)。
9、增强的随机数生成
现在经常都在讨论密码或者密钥容易遭受攻击的事。程序的安全性是项很复杂的工程,并且很容易出错。这就是我为什么喜欢这个新的SecureRandom.getinstanceStrong()方法的原因,它能自动选择出当前JVM可用的最佳的随机数生成器。这样减少了获取失败的机率,同时也避免了默认的弱随机数生成器可能会导致密钥或者加密值容易被黑客攻破的问题。
10、Date.toInstant()
Java 8引入了一个新的日期API。这不难理解,因为现有的这个实在是太难用了。实际上Joda一直以来都是Java日期API的首选。不过尽管有了新的API,但仍有一个严重的问题——大量的旧代码和库仍然在使用老的API。并且我们还知道这种现状仍将继续存在下去。到底该怎么做呢?
Java 8很优雅的解决了这个问题,它给Date类增加了一个新的方法toInstant(),它可以将Date转化成新的实现。这样你马上就可以切换到新的API,尽管现有的代码还在使用老的日期API(并且在可预见的未来仍将继续这样)。
如何强迫自己使用java8新特性
一、Lambda表达式
Lambda表达式可以说是Java 8最大的卖点,她将函数式编程引入了Java。Lambda允许把函数作为一个方法的参数,或者把代码看成数据。
一个Lambda表达式可以由用逗号分隔的参数列表、–符号与函数体三部分表示。例如:
Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e - System.out.println( e ) );
1 Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e - System.out.println( e ) );
为了使现有函数更好的支持Lambda表达式,Java
8引入了函数式接口的概念。函数式接口就是只有一个方法的普通接口。java.lang.Runnable与java.util.concurrent.Callable是函数式接口最典型的例子。为此,Java
8增加了一种特殊的注解@FunctionalInterface:
1 @FunctionalInterface
2 public interface Functional {
3 void method();
4 }
二、接口的默认方法与静态方法
我们可以在接口中定义默认方法,使用default关键字,并提供默认的实现。所有实现这个接口的类都会接受默认方法的实现,除非子类提供的自己的实现。例如:
1 public interface DefaultFunctionInterface {
2 default String defaultFunction() {
3 return "default function";
4 }
5 }
我们还可以在接口中定义静态方法,使用static关键字,也可以提供实现。例如:
1 public interface StaticFunctionInterface {
2 static String staticFunction() {
3 return "static function";
4 }
5 }
接口的默认方法和静态方法的引入,其实可以认为引入了C++中抽象类的理念,以后我们再也不用在每个实现类中都写重复的代码了。
三、方法引用
通常与Lambda表达式联合使用,可以直接引用已有Java类或对象的方法。一般有四种不同的方法引用:
构造器引用。语法是Class::new,或者更一般的Class T ::new,要求构造器方法是没有参数;
静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数;
特定类的任意对象方法引用。它的语法是Class::method。要求方法是没有参数的;
特定对象的方法引用,它的语法是instance::method。要求方法接受一个参数,与3不同的地方在于,3是在列表元素上分别调用方法,而4是在某个对象上调用方法,将列表元素作为参数传入;
四、重复注解
在Java 5中使用注解有一个限制,即相同的注解在同一位置只能声明一次。Java
8引入重复注解,这样相同的注解在同一地方也可以声明多次。重复注解机制本身需要用@Repeatable注解。Java
8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化。
五、扩展注解的支持
Java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解。
六、Optional
Java 8引入Optional类来防止空指针异常,Optional类最先是由Google的Guava项目引入的。Optional类实际上是个容器:它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查了。
七、Stream
Stream
API是把真正的函数式编程风格引入到Java中。其实简单来说可以把Stream理解为MapReduce,当然Google的MapReduce的灵感也是来自函数式编程。她其实是一连串支持连续、并行聚集操作的元素。从语法上看,也很像linux的管道、或者链式编程,代码写起来简洁明了,非常酷帅!
八、Date/Time API (JSR 310)
Java 8新的Date-Time API (JSR 310)受Joda-Time的影响,提供了新的java.time包,可以用来替代
java.util.Date和java.util.Calendar。一般会用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration这些类,对于时间日期的改进还是非常不错的。
九、JavaScript引擎Nashorn
Nashorn允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。
十、Base64
在Java 8中,Base64编码成为了Java类库的标准。Base64类同时还提供了对URL、MIME友好的编码器与解码器。
除了这十大新特性之外,还有另外的一些新特性:
更好的类型推测机制:Java 8在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。
编译器优化:Java 8将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters参数。
并行(parallel)数组:支持对数组进行并行处理,主要是parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。
并发(Concurrency):在新增Stream机制与Lambda的基础之上,加入了一些新方法来支持聚集操作。
Nashorn引擎jjs:基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。
类依赖分析器jdeps:可以显示Java类的包级别或类级别的依赖。
JVM的PermGen空间被移除:取代它的是Metaspace(JEP 122)。
Java8里面的java.util.Spliterator接口有什么用
首先先直接给一个答案:Spliterator(splitable iterator可分割迭代器)接口是Java为了并行遍历数据源中的元素而设计的迭代器,这个可以类比最早Java提供的顺序遍历迭代器Iterator,但一个是顺序遍历,一个是并行遍历
从最早Java提供顺序遍历迭代器Iterator时,那个时候还是单核时代,但现在多核时代下,顺序遍历已经不能满足需求了...如何把多个任务分配到不同核上并行执行,才是能最大发挥多核的能力,所以Spliterator应运而生啦
因为对于数据源而言...集合是描述它最多的情况,所以Java已经默认在集合框架中为所有的数据结构提供了一个默认的Spliterator实现,相应的这个实现其实就是底层Stream如何并行遍历(Stream.isParallel())的实现啦,因此平常用到Spliterator的情况是不多的...因为Java8这次正是一次引用函数式编程的思想,你只需要告诉JDK你要做什么并行任务,关注业务本身,至于如何并行,怎么并行效率最高,就交给JDK自己去思考和优化速度了(想想以前写如何并发的代码被支配的恐惧吧)作为调用者我们只需要去关心一些filter,map,collect等业务操作即可
所以想要看Spliterator的实现,可以直接去看JDK对于集合框架的实现,很多实现类你可以在Spliterators中找到的,也可以直接去你对应集合的stream方法中找到,比如ArrayList点进去的是Collection的默认实现,只需要提供一个Spliterator的实现,然后用StreamSupport就可以构造一个Stream了,相当方便
default StreamE stream() {
return StreamSupport.stream(spliterator(), false);
}
@Override
default SpliteratorE spliterator() {
return Spliterators.spliterator(this, 0);
}
对于Spliterator接口的设计思想,应该要提到的是Java7的Fork/Join(分支/合并)框架,总得来说就是用递归的方式把并行的任务拆分成更小的子任务,然后把每个子任务的结果合并起来生成整体结果。带着这个理解来看看Spliterator接口提供的方法
boolean tryAdvance(Consumer? super T action);
SpliteratorT trySplit();
long estimateSize();
int characteristics();
第一个方法tryAdvance就是顺序处理每个元素,类似Iterator,如果还有元素要处理,则返回true,否则返回false
第二个方法trySplit,这就是为Spliterator专门设计的方法,区分与普通的Iterator,该方法会把当前元素划分一部分出去创建一个新的Spliterator作为返回,两个Spliterator变会并行执行,如果元素个数小到无法划分则返回null
第三个方法estimateSize,该方法用于估算还剩下多少个元素需要遍历
第四个方法characteristics,其实就是表示该Spliterator有哪些特性,用于可以更好控制和优化Spliterator的使用,具体属性你可以随便百度到,这里就不再赘言
理解了接口方法的意思,现在再来看看自己的实现吧,由于大多数集合都被官方实现了,所以不能搞集合了,只有搞搞类似集合但又不是集合的东西...举以下这个例子,例子反正感觉不是很好,只能说帮助理解哈Spliterator接口了:
问题:求这个字符串"12%3 21sdas s34d dfsdz45 R3 jo34 sjkf8 3$1P 213ikflsd fdg55 kfd"中所有的数字之和例子:比如这种"12%sdf3",和就是12+3=15,这种"12%3 21sdas"和就是12+3+21=36
思路:字符串要用到Stream,只有把整个字符串拆分成一个个Character,而是否是并行,按道理讲只需要改一个标志位即可
先顺序执行代码方式:
/**
* 字符串中的数字计算器实现
*/
public class NumCounter {
private int num;
private int sum;
// 是否当前是个完整的数字
private boolean isWholeNum;
public NumCounter(int num, int sum, boolean isWholeNum) {
this.num = num;
this.sum = sum;
this.isWholeNum = isWholeNum;
}
public NumCounter accumulate(Character c){
if (Character.isDigit(c)){
return isWholeNum ? new NumCounter(Integer.parseInt("" + c), sum + num, false) : new NumCounter(Integer.parseInt("" + num + c), sum, false);
}else {
return new NumCounter(0, sum + num, true);
}
}
public NumCounter combine(NumCounter numCounter){
return new NumCounter(numCounter.num, this.getSum() + numCounter.getSum(), numCounter.isWholeNum);
}
public int getSum() {
return sum + num;
}
}
/**
* 测试类
*/
public class NumCounterTest {
public static void main(String[] args) {
String arr = "12%3 21sdas s34d dfsdz45 R3 jo34 sjkf8 3$1P 213ikflsd fdg55 kfd";
StreamCharacter stream = IntStream.range(0, arr.length()).mapToObj(arr::charAt);
System.out.println("ordered total: " + countNum(stream));
}
private static int countNum(StreamCharacter stream){
NumCounter numCounter = stream.reduce(new NumCounter(0, 0, false), NumCounter::accumulate, NumCounter::combine);
return numCounter.getSum();
}
}
执行结果如下:
如果按照普通方式直接把stream改为并行流...执行结果明显有点...不对
/**
* 测试类
*/
public class NumCounterTest {
public static void main(String[] args) {
String arr = "12%3 21sdas s34d dfsdz45 R3 jo34 sjkf8 3$1P 213ikflsd fdg55 kfd";
StreamCharacter stream = IntStream.range(0, arr.length()).mapToObj(arr::charAt);
// 调用parallel()变成并行流
System.out.println("ordered total: " + countNum(stream.parallel()));
}
private static int countNum(StreamCharacter stream){
NumCounter numCounter = stream.reduce(new NumCounter(0, 0, false), NumCounter::accumulate, NumCounter::combine);
return numCounter.getSum();
}
}
此时错误的并行执行结果如下:
为什么会执行错误,是因为默认的Spliterator在并行时并不知道整个字符串从哪里开始切割,由于切割错误,导致把本来完整的数字比如123,可能就切成了12和3,这样加起来的数字肯定不对
若是理解了上诉顺序执行的NumCounter的逻辑,再来看看Spliterator的实现
/**
* 字符串中的数字分割迭代计算器实现
*/
public class NumCounterSpliterator implements SpliteratorCharacter {
private String str;
private int currentChar = 0;
public NumCounterSpliterator(String str) {
this.str = str;
}
@Override
public boolean tryAdvance(Consumer? super Character action) {
action.accept(str.charAt(currentChar++));
return currentChar str.length();
}
@Override
public SpliteratorCharacter trySplit() {
int currentSize = str.length() - currentChar;
if (currentSize 10) return null;
for (int pos = currentSize/2 + currentSize; pos str.length(); pos++){
if (pos+1 str.length()){
// 当前Character是数字,且下一个Character不是数字,才需要划分一个新的Spliterator
if (Character.isDigit(str.charAt(pos)) !Character.isDigit(str.charAt(pos+1))){
SpliteratorCharacter spliterator = new NumCounterSpliterator(str.substring(currentChar, pos));
currentChar = pos;
return spliterator;
}
}else {
if (Character.isDigit(str.charAt(pos))){
SpliteratorCharacter spliterator = new NumCounterSpliterator(str.substring(currentChar, pos));
currentChar = pos;
return spliterator;
}
}
}
return null;
}
@Override
public long estimateSize() {
return str.length() - currentChar;
}
@Override
public int characteristics() {
return ORDERED + SIZED + SUBSIZED + NONNULL + IMMUTABLE;
}
}
/**
* 测试类
*/
public class NumCounterTest {
public static void main(String[] args) {
String arr = "12%3 21sdas s34d dfsdz45 R3 jo34 sjkf8 3$1P 213ikflsd fdg55 kfd";
StreamCharacter stream = IntStream.range(0, arr.length()).mapToObj(arr::charAt);
System.out.println("ordered total: " + countNum(stream));
SpliteratorCharacter spliterator = new NumCounterSpliterator(arr);
// 传入true表示是并行流
StreamCharacter parallelStream = StreamSupport.stream(spliterator, true);
System.out.println("parallel total: " + countNum(parallelStream));
}
private static int countNum(StreamCharacter stream){
NumCounter numCounter = stream.reduce(new NumCounter(0, 0, false), NumCounter::accumulate, NumCounter::combine);
return numCounter.getSum();
}
}
这下可以看到执行结果是正确的了
java8接口的变化的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于、java8接口的变化的信息别忘了在本站进行查找喔。
发布于:2022-12-07,除非注明,否则均为
原创文章,转载请注明出处。