b2c信息网

您现在的位置是:首页 > 昨日新闻 > 正文

昨日新闻

java8流式编程源码介绍的简单介绍

hacker2022-09-13 18:00:23昨日新闻84
本文目录一览:1、Java8的特性有哪些2、Java8有哪些新特性

本文目录一览:

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有哪些新特性

jdk1.8的新特性包括如下:

一、接口的默认方法与静态方法,也就是接口中可以有实现方法

二、Lambda 表达式

三、函数式接口与静态导入

四、Lambda 作用域

在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。

五、访问局部变量,等等其他新特性。

关于java学习,有什么书籍或者教程推荐不啦?

java Netty实战课程java高性能分布式RPC教程课程  免费下载

链接:

提取码:kvvv

Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程

           

用Java 8 增加的 Stream API 能实现哪些优雅的算法

Java 8引入了全新的Stream API。这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同。

Stream API引入的目的在于弥补Java函数式编程的缺陷。对于很多支持函数式编程的语言,map()、reduce()基本上都内置到语言的标准库中了,不过,Java 8的Stream API总体来讲仍然是非常完善和强大,足以用很少的代码完成许多复杂的功能。

创建一个Stream有很多方法,最简单的方法是把一个Collection变成Stream。我们来看最基本的几个操作:

public static void main(String[] args) {

ListInteger numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

StreamInteger stream = numbers.stream();

stream.filter((x) - {

return x % 2 == 0;

}).map((x) - {

return x * x;

}).forEach(System.out::println);

}

集合类新增的stream()方法用于把一个集合变成Stream,然后,通过filter()、map()等实现Stream的变换。Stream还有一个forEach()来完成每个元素的迭代。

为什么不在集合类实现这些操作,而是定义了全新的Stream API?Oracle官方给出了几个重要原因:

一是集合类持有的所有元素都是存储在内存中的,非常巨大的集合类会占用大量的内存,而Stream的元素却是在访问的时候才被计算出来,这种“延迟计算”的特性有点类似Clojure的lazy-seq,占用内存很少。

二是集合类的迭代逻辑是调用者负责,通常是for循环,而Stream的迭代是隐含在对Stream的各种操作中,例如map()。

要理解“延迟计算”,不妨创建一个无穷大小的Stream。

如果要表示自然数集合,显然用集合类是不可能实现的,因为自然数有无穷多个。但是Stream可以做到。

自然数集合的规则非常简单,每个元素都是前一个元素的值+1,因此,自然数发生器用代码实现如下:

class NaturalSupplier implements SupplierLong {

long value = 0;

public Long get() {

this.value = this.value + 1;

return this.value;

}

}

反复调用get(),将得到一个无穷数列,利用这个Supplier,可以创建一个无穷的Stream:

public static void main(String[] args) {

StreamLong natural = Stream.generate(new NaturalSupplier());

natural.map((x) - {

return x * x;

}).limit(10).forEach(System.out::println);

}

对这个Stream做任何map()、filter()等操作都是完全可以的,这说明Stream API对Stream进行转换并生成一个新的Stream并非实时计算,而是做了延迟计算。

当然,对这个无穷的Stream不能直接调用forEach(),这样会无限打印下去。但是我们可以利用limit()变换,把这个无穷Stream变换为有限的Stream。

利用Stream API,可以设计更加简单的数据接口。例如,生成斐波那契数列,完全可以用一个无穷流表示(受限Java的long型大小,可以改为BigInteger):

class FibonacciSupplier implements SupplierLong {

long a = 0;

long b = 1;

@Override

public Long get() {

long x = a + b;

a = b;

b = x;

return a;

}

}

public class FibonacciStream {

public static void main(String[] args) {

StreamLong fibonacci = Stream.generate(new FibonacciSupplier());

fibonacci.limit(10).forEach(System.out::println);

}

}

如果想取得数列的前10项,用limit(10),如果想取得数列的第20~30项,用:

ListLong list = fibonacci.skip(20).limit(10).collect(Collectors.toList());

最后通过collect()方法把Stream变为List。该List存储的所有元素就已经是计算出的确定的元素了。

用Stream表示Fibonacci数列,其接口比任何其他接口定义都要来得简单灵活并且高效。

发表评论

评论列表

  • 离鸢谜兔(2022-09-14 01:54:29)回复取消回复

    有实现方法二、Lambda 表达式三、函数式接口与静态导入四、Lambda 作用域在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。五、访问局部变量,等等其他新特性。关于java学习,

  • 美咩榆西(2022-09-13 19:58:48)回复取消回复

    = Stream.generate(new FibonacciSupplier());fibonacci.limit(10).forEach(System.out::println);}}如果想取得数列的前10项,用limit(10),如果想取得数列的第20~30项,用:ListLon