Lambda表达式学习篇二(流-上)

一、从外部迭代到内部迭代

  使用for循环计算伦敦的艺术家人数:

int count=0;

  for(Artist artist:allArtists){

  if(artist.isFrom("London")){

  count++;

  }

  }

每次迭代集合类时,都需要写较多样本代码。

  调用iterator,产生一个新的Iterator对象,进而控制整个迭代过程,这就是外部迭代。

int count=0;

Iterator<Artist> iterator=allArtists.iterator();

while(iterator.hasNext()){

  Artist artist=iterator.next();

  if(artist.isFrom("London"))

  {

    count++;

  }

}

  再来看内部迭代。

1 long count=allArtists.stream()
2                      .filter(artist->artist.isFrom("London"))
3                      .count();

  stream是函数式编程方式在集合类上进行复杂操作的工具。这里的stream()方法的调用和iterator调用的方法类似,但是该方法返回的是一个接口:Stream,而不是一个对象。

二、实现机制

这里对上述内部迭代代码进行分析:

  allArtists.stream().filter(artist->artist.isFrom("London"));这行代码中filter只刻画了Stream,但没有产生新的集合。这种不产生新集合的方法叫作惰性求值方法;而像count这样会产生值得方法叫作及早求值方法。

  

  这样我们添加一两个例子:

allArtists.stream().filter(artist->{   System.out.println(artist.getName());
    return artist.isFrom("London");
});//这里不会出项任何显示结果
long count=allArtists.stream().filter(artist->{        System.out.println(artist.getName());               return artist.isFrom("London");

}).count();

//这里会显示出成员艺术家列表名单

判断很简单:返回值是否为Stream。

整个过程和建造者模式有共通之处。

三、常用的流操作

1、collec(toList()) 方法由Stream里的值生成一个列表,是一个及早求值操作。Stream的of方法使用一组初始值生产新的Steam。

List<String> collected = Stream.of("a","b","c").collect(Collectiors.toList());
assertEquals(Array.asList("a","b","c"),collected);                                                                                                                                                          

  2、map

  map可以将一个流中的值转换为成一个新的流。

  首先看一下一个平时所见的例子:

//for循环将字符串转换为大写List<String> collected=new ArrayList<>();
for(String string:asList("a","b","hello")){
String uppercaseString=string.toUpperCase();
    collected.add(upercaseString);
}
assertEquals(asList("A","B","HELLO"),colected);
//使用map操作将字符串转换为大写形式
List<String> collected=Stream.of("a","b","c").map(string->string.toUpperCase()).collect(toList());
assertEquals(asList("A","B","C"),collected);

3、filter

  遍历数据并检查其中的元素时,可尝试使用stream中提供的新方法filter,通map有点类似

使用循环遍历列表,使用条件语句判断

List<string>buginningWithNumbers=new ArrayList<>();
for(String value:asList("a","1abc","abc1"))
{
     if(isDigit(value.charAt(0))
     {
      buginningWithNumbers.add(value);
    }
}

函数式风格:

List<String>beginningWithNumbers=Stream.of("a","1abc","abc1").filter(value->isDigit(value.charAt(0))).collect(toList());

4、flatMap

  调用stream方法,将每个列表装换成Stream对象,其余不封由flatMap方法处理。例子如下:

List<Integer>together=Stream.of(asList(1,2),asList(3,4)).flatMap(numbers->numbers.stream()).collect(toList());
assertEquals(asLsit(1,2,3,4),together);

5、max和min

  Stream上常用的操作之一是求最大值和求最小值。

使用Stream查找最短曲目:

List<Track>tracks=asList(    new Track("Love",524),
      new Track("For my love",378),    new Track("For Your Love",451));
Track shortestTrack=track.stream().min(Comparator.comparing(track->track.getLength())).get();assertEquals(tracks.get(1),shortestTrack);

6、通用模式

  for循环查找专辑中最短的曲目

List<Track> tracks =asList(
      new Track("Dangers",524),
      new Track("Violets for Your Fures",378),
      new Track("Lost",451)
    );
Track shorttestTrack=track.get(0);
for(Track track:tracks){
   if(track.getLength()<shortestTrack.getLength()){
      shortestTrack=track;
  }
}    

  另外一种reduce模式

      Object accumulato=initialValue;
      for(Object element : collection)
     {
       accumulator=combine(accumulatror,element);
   }    

7、reduce

   reduce操作可以实现从一个值中生成一个值。在上述例子中用到count、mun和max方法,因为常用被纳入标准库中。这些其实都是reduce操作。

使用reduce求和

int count =Stream.of(1,2,3).reduce(0,(acc,element)->acc+element);
assertEquals(6,count);

Lambda表达式返回值是最新的acc,是上一轮acc的值和当前元素相加的结果。reducer的类型BinaryOperator;

下面展开reduce操作

BinaryOperator<Integer> accumulator=(acc,element)->acc+element;
int count=accumulator.apply(accumulator.apply(accumulator.apply(0,1),2),3)

8、整合操作

  Stream()方法众多,在此我们介绍了Collect,map,filter,flatMap,max,min。在这儿我们总结一个例子来供自己理解。

  第一个要解决的问题是,找出某张专辑上所有乐队的国籍。艺术家列表里既有个人,也有乐队。利用一点领域知识,假定一般乐队名以定冠词The开头。当然不是绝对的,但也差不多。

  需要注意的是,这个问题绝对不是简单地调用几个API就足以解决。这既不是使用map将一组值映射为另一组值,也不是过滤,更不是将一个Stream中的元素最终归约为一个值。首先,可以将这个问题分解为以下步骤。

  1、找出专辑上所有的表演者。

  2、分辨出哪些表演者是乐队。

  3、找出每个乐队的国籍。

  4、将找出的国籍放入一个集合。

  现在,找出每一步对应的Stream API也就相对容易了:

  1、Album类有个getMusicians方法,该方法返回一个Stream对象,包含整张专辑中所有的表演者;

  2、使用filter方法对表演者进行过滤,值保留乐队;

  3、使用map方法将乐队映射为其所属国家;

  4、使用collect(Collectors.toList())方法将国籍放入一个列表。

  

  最后,整合所有的操作,就得到如下代码:

Set<String> origins=album.getMusicians()               .filter(artist->artist.getName()               .startsWith("Th"))               .map(artist->artist.getNationality())               .collect(toSet());
时间: 2024-10-07 08:40:39

Lambda表达式学习篇二(流-上)的相关文章

Lambda表达式学习篇三(流-下)

一.重构遗留代码 为了进一步解释如何重构一流代码,本节将距离说明如何将一段使用循环进行集合操作的代码,重构成基于Stream的操作. 假定选取一组专辑,找出其中所有长度大于一分钟的曲目名称.下面是一个例子,首先初始化一个set对象,用来保存找到的曲目名称.然后使用for循环遍历所有专辑,每次循环中在使用一个for循环遍历每张专辑的每首曲目,检查其长度是否大于60秒,如果是,则将该曲目的名称加入set对象. 例如:遗留代码:找出代码大于一分钟的曲目 1 private static Set<Str

springMVC3学习(十二)--文件上传优化CommonsMultipartResolver

基于上一篇文件上传发现效率很慢,我们应该对它进行优化  使用springMVC对文件上传的解析器 来处理文件上传的时候需要在spring的applicationContext里面加上springMVC提供的MultipartResolver的申明 这样客户端请求的时候 springMVC会检查request里面是否包含多媒体信息 如果包含了就会使用MultipartResolver进行解析, springMVC会使用一个支持文件  处理的MultipartHttpServletRequest来包

java lambda表达式学习笔记

lambda是函数式编程(FP,functional program),在java8中引入,而C#很早之前就有了.在java中lambda表达式是'->',在C#中是‘=>’. 杜甫说:射人先射马,擒贼先擒王.学习一个库要学习它的入口类.lambda的入口类是Stream,一看Stream中的函数就会发现Function,Predicate等lambda元素. 一.几个概念     函数式接口 Functional Interface,除了static和default类型的方法外,只有一个函数

java 8 中lambda表达式学习

转自 http://blog.csdn.net/renfufei/article/details/24600507 http://www.jdon.com/idea/java/10-example-of-lambda-expressions-in-java8.html Lambda表达式的语法基本语法:(parameters) -> expression或(parameters) ->{ statements; } 下面是Java lambda表达式的简单例子: // 1. 不需要参数,返回值

WPF-MVVM模式学习笔记4——Lambda表达式学习

在学习MVVM的过程中,其中自定义了一个超类NotificationObject,如下 public abstract class NotificationObject : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void RaisePropertyChanged(string propertyName) { PropertyChang

[Java 8] (8) Lambda表达式对递归的优化(上) - 使用尾递归 .

递归优化 很多算法都依赖于递归,典型的比如分治法(Divide-and-Conquer).但是普通的递归算法在处理规模较大的问题时,常常会出现StackOverflowError.处理这个问题,我们可以使用一种叫做尾调用(Tail-Call Optimization)的技术来对递归进行优化.同时,还可以通过暂存子问题的结果来避免对子问题的重复求解,这个优化方法叫做备忘录(Memoization). 本文首先对尾递归进行介绍,下一票文章中会对备忘录模式进行介绍. 使用尾调用优化 当递归算法应用于大

Lambda表达式基础篇

一.简介 一个Lambda Expression(译为Lambda式) 就是一个包含若干表达式和语句的匿名函数.可以被用作创建委托对象或表达式树类型.Lambda 表达式对于编写 LINQ 查询表达式特别有用. 所有的Lambda式都使用操作符"=>",表示"goes to (转变为)".操作符左边部分是输入参数表,右边部分是表达式或语句块.接下来就看一下它的作用及用法. 二.何时用? 在Framework 2.0 以前,声明委托的唯一方法是通过方法命名,从F

lambda表达式学习笔记(1) -- 作为委托的lambda表达式

C#中的Lambda表达式就是C# 2中匿名方法的演变,因此从一个匿名函数开始一步步简化写法. 例子是获取一个string参数,然后返回一个int. 首先匿名方法的写法如下: Func<string, int> returnLength; returnLength = delegate (string text) { return text.Length; }; Console.Write(returnLength("Hello")); lambda表达式最冗长的形式是:

C++11 lambda表达式学习

lambda表达式是函数式编程的基础.咱对于函数式编程也没有足够的理解,因此这里不敢胡言乱语,有兴趣的可以自己查找相关资料看下.这里只是介绍C++11中的lambda表达式自己的认识.这里有参考文档http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2927.pdf 给出两个例子,可以看出lambda表达式的写法 [](int x, int y) { return x + y; } [](int x, int y) -> int {