05月11, 2019

【Java8】 之 Lambda 表达式 和 流式API

Lambda 表达式和流API 是 java8 新出的特性

一、Lambda表达式

Lambda表达式的出现取代了匿名类、取消了模板、允许使用函数式风格编写代码。使得程序不必依赖于匿名类那样死板,程序员可以根据需求直接在方法中自定义代码。下边通过几个例子介绍一下。

1、用Lambda表达式代替Runnable

之前实现Runnable接口

newThread(newRunnable() {         
            @Override
              public   void   run() {             
                     System.out.println("Lambda");        
               }      
  }).start();

利用Lambda 表达式:

newThread(()-> System.out.println("Lambda")).start();

通过这个例子可以看出Lambdab表达式的语法:

(params)->expression(params)->statement(params)->{ statements }

如果方法没有参数(就像上边那个输出),那么参数列表就不用写。

2、利用Lambda 表达式进行事件处理

比如一个按钮的监听事件,

JButton btn=newJButton("Button");       
 btn.addActionListener(newActionListener() {

         @Override
         public  void  actionPerformed(ActionEvent e){     
              System.out.println("Lambda");           
         }      
 });

使用Lambda表达式实现:

JButton btn=newJButton("Button");   

 btn.addActionListener((e)->{          
        System.out.println("Lambda");     
 });

由于方法中可能要写好多逻辑代码,所以使用()->{}模板。

3、实现集合自定义排序

对一个List 集合自定义排序最常见的方法:

List nameList=newArrayList();        

nameList.add("Tom");        

nameList.add("John");        

nameList.add("Watson");        

Collections.sort(nameList,newComparator() {          

       @Override
        public   int   compare(Strings1,Strings2) {
              returns2.length()-s1.length() ;///根据字符串长度比较
        }       
 });

使用Lambda表达式实现:

Collections.sort(nameList,(s1,s2)->{returns2.length()-s1.length();});

同样使用()->{}模板。

4、对列表进行迭代

普通forEach进行迭代(输出上边的nameList中的值):

for (Stringname:nameList) {        
        System.out.println(name);   
 }

利用Lambda 表达式进行迭代:

nameList.forEach(n-> System.out.println(n));///普通写法

nameList.forEach(System.out::println);///使用::双冒号操作符进行方法引用

二、流API(Stream API)

StreamAPI 是java8 中处理集合的关键组件,提供了丰富的函数式操作,其中的Stream与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念,Java8中的Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulkdataoperation)。

1、Stream 的创建

任何的集合都可以转换成Stream

/********数组转为流*********/

String[] names={"Tim","Tom","Tommy"};

///转换为流

Stream stringStream=Stream.of(names);      

 Stream stringStream1=Arrays.stream(names);

/*******集合转为流*******/

List nameList=newArrayList(); 

nameList.add("Tim"); 

nameList.add("John"); 

nameList.add("Watson"); 

nameList.add("Amy"); 

nameList.add("Sam"); 

nameList.add("Tom"); 

nameList.add("Tommy");

//转为流

Stream nameStream=nameList.stream();

Stream nameStream1=nameList.parallelStream();

2、Stream 的简单使用 Stream的使用分为两种类型:

  • Intermediate:一个Stream可以调用0到多个Intermediate类型操作,每次调用会对Stream做一定的处理,返回一个新的Stream,这类操作都 是惰性化的(lazy),就是说,并没有真正开始流的遍历。 常用操作:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel

  • Terminal:一个Stream只能执行一次terminal 操作,而且只能是最后一个操作,执行terminal操作之后,Stream就被消费掉了,并且产生一个结果。 常用操作:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny

下边通过几个例子介绍一下常用的方法。

Intermediate:

首先使用filter()过滤首字母是“T”的姓名,然后使用map()遍历并转换为小写字母,最后打印。

nameStream.filter(s -> s.startsWith("T")).map(String::toLowerCase).forEach(System.out::println);

输出为:

tim

tom

tommy

这里要注意一下以下这种写法是错误的,

nameStream.filter(s->s.startsWith("T"));nameStream.map(String::toLowerCase);nameStream.forEach(s->System.out.println(s));

这样会报stream has already been operated upon or closed异常,这是因为一个 Stream 只可以使用一次,如果再想用,需要再次流化。

flatMap()示例

Listlist=newArrayList();

list.add("aaa");

list.add("bbb");

Stream.of(nameList,list).flatMap(s->s.stream()).collect(Collectors.toList()).forEach(s-> System.out.println(s));

输出为:

Tim

John

Watson

Amy

Sam

Tom

Tommy

aaa

bbb

代码解释:flatMap()将集合nameList和list 扁平化,就是将最底层的元素放到一起,结果没有 List了, 直接就是字符串,然后经过collect ()聚合成List,最后将结果输出。

  • limit():获取自流
Stream subStream=nameStream.limit(2);
  • skip():跳过前边的元素
nameStream.skip(3).forEach(s->System.out.println(s));

输出为:

Amy

Sam

Tom

Tommy

很明显结果在之前的基础上去掉了前3个。

  • distinct() :去重

Terminal:

  • toArray() :转化为数组
String[] s1=nameStream.filter(s->s.startsWith("T")).toArray(String[]::new);
  • min(): 取最小值、max()取最大值

  • collect(): 聚合函数,可以将一堆元素聚合为集合(上边已经用过了)。

  • count(): 计算流中元素总数

  • anyMatch(): 判断流中是否含有匹配元素(返回boolean 类型)

System.out.println(nameStream.anyMatch(s->s.startsWith("T")));///判断是否含有“T”开头的元素

输出为:

true
  • allMatch(): 判断流中元素是否全部匹配

  • nonMatch(): 判断流中元素是否全不匹配

  • findFirst(): 找到满足条件的第一个元素

  • findAny(): 找到任意一个元素就返回

扫鸭扫鸭,求关注

alt

本文链接:http://blog.keepting.cn/blog//post/lambda_streamapi.html

-- EOF --

Comments