- 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);
整合操作
找出某张专辑上所有乐队的国籍
- 找出专辑上的所有表演者
- 分辨出那些表演者是乐队
- 找出每个乐队的国籍
- 将找出的国籍放入一个集合
- Album类有个方法getMusicians方法,该方法返回一个Stream对象,包含整张专辑中所有的表演者
- 使用filter方法对表演者进行过滤,只保留乐队
- 使用map方法将乐队映射为其所属国家
- 使用collect(Collectors.toList())方法将国籍放入一个列表
Set<String> orgins = album.getMusicians()
.filter(artist -> artist.getName().startsWith("The"))
.map(artist -> artist.getNationality())
.collect(toSet());