Java8函数式编程

  • Artist
    • name
    • members
    • origin
  • Track
    • name
  • Album
    • name
    • tracks (专辑上的曲目)
    • musicians

如何辨别Lambda表达式

Runnable noAtguments = () -> System.out.println("Hello,World");

ActionListener oneArgument = event -> System.out.println("button clicked");

Runnable multiStatement = () -> {
    System.out.println("Hello,");
    System.out.println(" world");
}

BinaryOperator<Long> add = (x,y) -> x + y;

BinaryOperator<Long> addExplicit = (Long x,Long y) -> x + y;

Java中重要函数接口

接口 参数 返回类型 示例
Predicate T boolean 这张唱片已经发行了吗
Consumer T void 输出一个值
Function T R 获得Artist对象的名字
Supplier None T 工厂方法
UnaryOperator T T 逻辑非(!)
BinaryOperator (T,T) T 求两个数的乘积

类型判断

使用菱形操作符,根据变量类型做推断

指定泛型的类型

Map<String,Integer> oldWordCounts = new HashMap<String, Integer>();
Map<String,Integer> oldWordCounts = new HashMap<>();

使用菱形操作符,根据方法签名做推断

useHashMap(new HashMap<>());
...

private void useHashMap(Map<String,String> values);

Predicate接口

predicate接口源码,接受一个对象,返回一个布尔值

public interface Predicate<T>{
    boolean test(T t);
}

外部迭代,内部迭代

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

int count = 0;
for(Artist artist : allArtist){
    if(artist.isFrom("London")){
        count++;
    }
}

使用迭代器计算来自伦敦艺术家人数

int count = 0;
Iterator<Artist> iterator = allArtist.iterator();
while(iterator.hasNext()){
    Artist artist = iterator.next();
    if(artist.isFrom("London")){
        count++;
    }
}

使用内部迭代器计算来自伦敦艺术家人数

Long count = allArtist.stream()
    				  .filter(artist -> artist.isFrom("London"))
    				  .count();

filter只是刻画出Stream,但没有产生新的集合,这种叫做惰性求值方法

count这种从Stream中产生值的方法叫做及早求值方法

  • 区分就看返回值,返回值是Stream,就是惰性求值

  • 返回值若是另一个值或者为空,就是及早求值

  • 整个过程和建造者模式有共通之处,建造者模式使用一系列操作设置属性和配置,最后调用一个build方法,这时对象才被真正创建

常用的流操作

collect(toList())

collect(toList())方法由Stream里的值生成一个列表,是一个及早求值操作

List<String> collected = Stream.of("a","b","c")
    						   .collect(Collectors.toList());
assertEquals(Arrays.asList("a","b","c"),collected);
//断言判断结果是否一致

map

map操作就可以将一个流中的值转换成一个新的流

正常使用for循环将字符串全部改成大写

List<String> collected = new ArrayList<>();
for(String string:asList("a","b","hello")){
    String uppercaseString = string.toUpperCase();
    collected.add(uppercaseString);
}

assertEquals(asList("A","B","HELLO"), collected);

使用map操作将字符串转换为大写形式

List<String> collected = Stream.of("a","b","hello")
    						   .map(string -> string.toUpperCase())
    						   .collect(collectors.toList());

assertEquals(asList("A","B","HELLO"), collected);

传给map的Lambda表达式只接受一个String类型的参数,返回一个新的String。参数和返回值不必属于同一种类型,但是Lambda表达式必须是Function接口的一个实例,Function接口是只包含一个参数的普通函数接口

该函数的接口是Function

I -> Function ->R


filter

filter遍历数据并检查其中的元素时

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

List<String> beginningWithNumbers = new ArrayList<>();
for(String value : asList("a","1abc","abc1")){
    if(isDigit0(value.get(0))){
        beginningWithNumbers.add(value);
    }
}

assertEquals(asList("1abc"),beginningWithNumbers);

函数式风格

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

assertEquals(asList("1abc"),beginningWithNumbers);

该函数的接口Predicate

I -> Predicate ->boolean


flatMap

flatMap方法可用Stream替换值,然后将多个Stream连接成一个Stream

包含多个列表的Stream

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

调用stream方法,将每个列表转换成Stream对象,其余部分有flatMap方法处理。flatMap方法的相关函数接口和map方法一样都是Function接口,只是方法的返回值限定为Stream类型罢了

Max和Min

Stream上常用的操作就是求最值

使用Stream查找最短曲目

List<Track> tracks = asList(new Track("Bakai",524),
                            new Track("Violets",378),
                            new Track("Time was",451));

Track shorttestTrack = tracks.stream()
    						 .min(Comparator.comparing(track -> track.getLength()))
    						 .get()

assertEquals(tracks.get(1),shorttestTrack);

reduce

使用reduce操作实现累加

Lambda表达式就是reducer,他执行求和操作,有两个参数:传入Stream中的当前元素和acc,将两个参数相加,acc就是累加器,保存当前的累加的结果

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

assertEquals(6,count);

//展开操作就是
BinaryOperator<Integer> accumulator = (acc, elelemnt) -> acc + element;
int count = accumulator.apply(
    			accumulator.apply(
                    accumulator.apply(0,1),
                2),
			3);

//使用命令式编程方式求和
int acc = 0;
for(Integer element : asList(1,2,3)){
    acc = acc + element;
}
assertEquals(6,acc);

整合操作

找出某张专辑上所有乐队的国籍

  1. 找出专辑上的所有表演者
  2. 分辨出那些表演者是乐队
  3. 找出每个乐队的国籍
  4. 将找出的国籍放入一个集合

  1. Album类有个方法getMusicians方法,该方法返回一个Stream对象,包含整张专辑中所有的表演者
  2. 使用filter方法对表演者进行过滤,只保留乐队
  3. 使用map方法将乐队映射为其所属国家
  4. 使用collect(Collectors.toList())方法将国籍放入一个列表

Set<String> orgins = album.getMusicians()
    					  .filter(artist -> artist.getName().startsWith("The"))
    					  .map(artist -> artist.getNationality())
    					  .collect(toSet());
上一篇:五彩歌词1——信息收集


下一篇:电竞陪玩app定制开发业务是怎样满足市场需求的?