jdk8 lambda学习
1、函数式接口与lambda表达式
概述:
函数式接口也是 java interface 的一种,但还需要满足:
一个函数式接口只有一个抽象方法(SAM,single abstract method);
Object 类中的 public abstract method 不会被视为单一的抽象方法;
函数式接口可以有默认方法和静态方法;
函数式接口可以用@FunctionalInterface 注解进行修饰。
常用函数式接口分类:
supplier:供给型,无参有返回值
@FunctionalInterface interface Test3{ String printHello(); }
consumer:消费型,有参,无返回值
@FunctionalInterface interface Test{ void test(String str); }
predicate:断言型接口,有参,返回boolean
@FunctionalInterface interface Test2{ boolean compare(int a, int b); }
function:函数式接口,有参,有返回值
@FunctionalInterface interface Test1{ int add(int a, int b); }
lambda语法格式:
(parameters) -> expression
或 (parameters) ->{ statements; }
lambda表达式语法特征:
1、可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
2、可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
3、可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
4、可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
转换示例:
lambda表达式根据参数类型确定接口类型,接口要求为函数式接口,只需要关注接口方法实现,可以省略创建接口对象代码,lambda表达式本质上是得到接口对象
Test test0 = new Test() { @Override public void test(String str) { System.out.println(str); } }; Test test = (str) -> System.out.println(str);
Test1 test1 = (a, b) -> a+b; System.out.println(test1.add(3, 7)); Test2 test2 = (a, b) -> a>b; System.out.println(test2.compare(3, 7)); Test3 test3 = () -> "你好"; System.out.println(test3.printHello());
2、方法引用:
实例方法引用:
默认的,我们引用实例方法使用的是对象名.方法名语法,实例方法引用可以使用类名::方法名的语法
静态方法引用:
默认的,我们引用静态方法使用类名.方法名,静态方法引用可以使用类名::方法名的语法
构造方法引用:
默认的,我们使用new 类名(参数列表)调用,构造方法信用可以使用类名::new的语法
数组构造引用:
默认使用new 数据类型[长度]创建,数组构造引用可以使用数据类型[]::new的语法
public class Test06 { public static void main(String[] args) { //构造引用 Car car = Car.create(Car::new); //变成数组方便使用lambda List<Car> cars = Arrays.asList(car); //实例方法引用 cars.forEach(Car::repair); //静态方法引用 cars.forEach(Car::collide); //数组引用 Function<Integer, Car[]> arrCreate = Car[]::new; Car[] carArr = arrCreate.apply(3); } } class Car { public static Car create(final Supplier<Car> supplier) { return supplier.get(); } public static void collide(final Car car) { System.out.println("Collided " + car.toString()); } public void follow(final Car another) { System.out.println("Following the " + another.toString()); } public void repair() { System.out.println("Repaired " + this.toString()); } }
3、内部迭代与外部迭代
外部迭代是由用户自己在客户端中写的循环代码, 内部迭代是由Jdk在库中执行的循环代码, 即循环写的位置从外部转移到了jdk内部.
两种迭代方式速率差别不大,内部迭代优势:
用户只需要关注问题,无需关注如何解决问题的细节。
使得 JVM可以利用短路、并行等对性能的提升变成可能
final long count = 100000000; List<Long> list = new ArrayList<>(); for (long i = 0; i < count; i++) { list.add(i); } //=========传统方式进行外部迭代========= Instant begin = Instant.now(); for (Long i : list) { System.out.print(""); } System.out.println("--------------------------"); Instant end = Instant.now(); System.out.println("传统方式进行外部迭代" + count + "次,耗时(ms):" + Duration.between(begin, end).toMillis()); //=========jdk8 Collection.forEach(...)进行内部迭代======== begin = Instant.now(); list.forEach(i -> System.out.print("")); System.out.println("--------------------------"); end = Instant.now(); System.out.println("jdk8 Collection.forEach方式进行内部迭代" + count + "次,耗时(ms):" + Duration.between(begin, end).toMillis()); //=========jdk8 stream进行内部迭代======== begin = Instant.now(); list.stream().forEach(i -> System.out.print("")); System.out.println("--------------------------"); end = Instant.now(); System.out.println("jdk8 Stream方式进行内部迭代" + count + "次,耗时(ms):" + Duration.between(begin, end).toMillis()); //=========jdk8 parallelStream进行内部迭代======== begin = Instant.now(); list.parallelStream().forEach(i -> System.out.print("")); System.out.println("--------------------------"); end = Instant.now(); System.out.println("jdk8 parallelStream方式进行内部迭代" + count + "次,耗时(ms):" + Duration.between(begin, end).toMillis());
4、Stream的常用方法:
(1)、获得stream流:
//已知,可以通过集合框架.stream方法构建 Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream(); //可以使用Stream.of方法,将对象,对象参数列表转变成为流对象 Stream<Integer> integerStream = Stream.of(1, 2, 3); Stream<String> str = Stream.of("str"); //stream对象的.parallel()方法可以得到对应并行流 Stream<Integer> parallelStream = Stream.of(1, 2, 3).parallel(); //empty方法创建一个空流 Stream<Object> empty = Stream.empty();
并行流与串行流的区别在于并行流可以多线程处理,加快速率
(2)、forEach遍历
Arrays.asList(1, 2, 3).stream().forEach(obj -> System.out.print(obj + " "));
(3)、filter 流内数据筛选
//筛选出0~9当中>5的数 Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream(); stream.filter(i -> i > 5).forEach(i -> System.out.print(i + " "));
(4)、map 流内数据转换为其他类型
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream(); stream .filter(i -> i > 5) .map(i -> { switch (i) { case 1: return "一"; case 2: return "二"; case 3: return "三"; case 4: return "四"; case 5: return "五"; case 6: return "六"; case 7: return "七"; case 8: return "八"; case 9: return "九"; } return "未知"; }).forEach(d -> System.out.print(d + " ")); //map进行限制的其他接口:mapToInt()、mapToLong()、mapToDouble()
(5)、flatMap 流内数据转换为流再合并到到同一个流中,返回的是stream对象
//演示1对多 Arrays.asList("hello", "world").stream().map(str -> str.split("")).forEach(obj -> System.out.println(Arrays.toString(obj))); Arrays.asList("hello", "world").stream().flatMap(str -> Arrays.stream(str.split(""))).forEach(obj -> System.out.print(obj + " ")); //flatMapToLong、flatMapToDouble等就不多赘余描述了
(6)、distinct 去重, sorted 排序
List<Integer> integers = Arrays.asList(1, 1, 3, 5, 2, 6, 6); integers.stream() .distinct() .sorted() .forEach(i -> System.out.print(i + " ")); //自定义排序规则 System.out.println(); integers.stream() .distinct() .sorted((Integer o1, Integer o2) -> o1 < o2 ? 1 : (o1.equals(o2)) ? 0 : -1) .forEach(i -> System.out.print(i + " "));
(7)、skip跳过, limit截取 控制流内指针的方法
//使用skip + limit实现了类似分页的效果 int pageSize = 2; int pageNumber = 2; List<String> collect = Stream.of("a", "b", "c", "d", "e", "f") .skip(pageSize * (pageNumber - 1)) .limit(pageSize) .collect(Collectors.toList()); for (String str : collect) { System.out.println(str); }
(8)、获取值与匹配:findFirst、findAny、anyMatch、allMatch
/** * findFirst() 得到第一个元素 * findAny() 得到随机一个元素。这个一般是在并行流查找的使用使用。串行和findFirst没区别 * anyMatch() 任意匹配 * allMatch() 全部匹配 */ @Test public void testOther(){ System.out.println(Stream.of("a", "ab", "ccc").findFirst().get()); System.out.println(Stream.of("a", "ab", "ccc").findAny().get()); //想要将元素倒叙使用的是sort方法,指定好排序规则即可 boolean x = Stream.of("a", "ab", "ccc").anyMatch(str -> str.contains("c")); System.out.println("容器内有包含c字符的字符串?" + x); boolean b = Stream.of("a", "ab", "ccc").allMatch(str -> str.contains("c")); System.out.println("容器内字符串全部包含c字符?" + b); }
(9)、统计操作min、max、count、reduce(自定义统计策略)
/** * 聚合操作: * min、max、reduce */ @Test public void testPolymerization(){ int max = Stream.of(1, 3, 5, 7, 9) .max(Comparator.naturalOrder()).get(); System.out.println(max); int min = Stream.of(1, 3, 5, 7, 9) .min(Comparator.naturalOrder()).get(); System.out.println(min); long count = Stream.of(1, 3, 5, 7, 9) .filter(number -> number > 3) .count(); System.out.println("大于三的数量有:" + count); //如果我们想要类似sum操作,怎么办呢?使用reduce方法达到想要的效果 Integer sum = Stream.of(1, 3, 5, 7, 9).reduce((a, b) -> a + b).get(); System.out.println("1 + 3 + 5 + 7 + 9 =" + sum); Integer sum1 = Stream.of(1, 2, 3, 4, 5).reduce(100, (a, b) -> a + b); System.out.println("100 + 1 + 2 + 3 + 4 + 5 = " + sum1); //前面两个reduce区别在于第二个可以设置初始值,但是都要求聚合产生的数据类型不能发生变化。reduce一次操作的结果作为上一次操作的参数 //reduce的第三种方法可以支持聚合产生的结果为其他类型,非元素内容类型 //例如,使用reduce方式3实现count操作 Integer count1 = Stream.of("a", "bc", "ca", "d", "abc") .filter(str -> str.length() > 1) .reduce(0, (identity, ele) -> identity + 1, (identity, ele) -> null); System.out.println("字符串列表中长度>1的字符串个数为:" + count1); //第三个参数是指的在并行流的情况下,各个线程得到的结果的合并方式,前面写为null是因为不是并行流它并不会生效 Integer count2 = Stream.of("a", "bc", "ca", "d", "abc") .parallel() .filter(str -> str.length() > 1) .reduce(0, (identity, ele) -> identity + 1, (identity, ele) -> identity + ele); System.out.println("并行流得到的字符串列表中长度>1的字符串个数为:" + count2); }
(10)、static concat 流的合并
/** * static concat 合并,类似mysql中的字符串合并,这里是流的合并 */ @Test public void testConcat() { Stream.concat(Stream.of(1, 2, 3), Stream.of("a", "b", "c")).forEach(obj -> System.out.print(obj + " ")); }
(11)、peek:lambda表达式提供的debug
/** * peek方法:stream提供的一个方便调试的方法,可以在peek代码块内进行打印中间结果 * 注意,peek方法一定要对流对象进行了操作才会触发,我们的例子使用了collect操作触发 * 该方法主要用于调试,方便debug查看Stream内进行处理的每个元素。 * * idea目前有插件可以支持直接debug在stream过程函数中 */ @Test public void testPeek(){ Stream.of("a", "ab", "abc", "abcd") .filter(str -> str.length() > 2) .peek(str -> System.out.println("经过过滤的数据:" + str)) .map(str -> str.toUpperCase()) .peek(str -> System.out.println("处理之后的数据:" + str)) .collect(Collectors.toList()); }
(12)、collect 数据收集,将数据从流变为普通java对象等
@Test /** collect 数据收集,将流内数据提取出来 */ public void testCollect() { Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream(); List<Integer> integerList = stream .filter(i -> i > 5) .collect(Collectors.toList()); integerList.forEach(i -> System.out.print(i + " ")); //系统提供的收集器:Collectors.toList()、 Collectors.toSet().... }
5、Collector收集器学习
收集器Collector 将stream流中元素迭代操作变成最终形式
收集动作与执行步骤组成
1、supplier() 创建接受容器
2、accumulator() 将新元素加入容器
3、combiner() 合并两个结果容器(并行流使用,将多个线程产生的结果容器合并)
4、finisher() 转换到最终形态的操作
属性:
Set<> characteristics
特征集合:
Collector.Characteristics 枚举对象类型
CONCURRENT 并发的
UNORDERED 无序的
IDENTITY_FINISH 表示中间结果容器类型与最终结果类型一致。设置此特性时finiser()方法不会被调用
自定义收集器:
of方法:
static <T,R> Collector<T,R,R> of(Supplier<R> supplier, BiConsumer<R,T> accumulator, BinaryOperator<R> combiner, Collector.Characteristics... characteristics)
static <T,A,R> Collector<T,A,R> of(Supplier<A> supplier, BiConsumer<A,T> accumulator, BinaryOperator<A> combiner, Function<A,R> finisher, Collector.Characteristics... characteristics)
收集器工具类:Collectors
内置收集方法:
toList() 将流内数据转换为List对象
/** * 自定义获取toList收集器。 这里定义为方法的原因是方便对于不同的类型T进行复用 * @param <T> * @return */ public static <T> Collector<T, ?, List<T>> toList() { return Collector.of( () -> new ArrayList<>(), (ts, t) -> ts.add(t), (list, list2) -> { list.addAll(list2); return list; }, new Collector.Characteristics[0]); } @Test public void test01() { //Collectors的toList收集器 List<String> collect = Stream.of("q", "w", "e", "r").collect(Collectors.toList()); //自定义收集器达到toList效果 List<String> collect1 = Stream.of("q", "w", "e", "r").collect(toList()); for (String str : collect1) { System.out.print(str + " "); } }
6、Collectors收集器工具类学习
(1)、收集为集合。toCollection、toList、toSet、toMap、toCurrentMap
/** * Collectors的提供常见收集器使用: * toCollection() * toList() * toSet() * toMap(keyFunction, valueFunction) * toMap(keyFunction, valueFunction, keySameValueCombineFunction) 最后一个方法是当key相同的时候,value的合并的function * toMap(keyFunction, valueFunction, keySameValueCombineFunction, Supplier) 最后一个方法是指定map容器的创建方式 * toConcurrentMap 收集过程并行操作,不做过多赘余说明 */ @Test public void test02(){ Set<String> collect = Stream.of("a", "b", "c").collect(Collectors.toSet()); List<String> collect2 = Stream.of("a", "b", "c").collect(Collectors.toList()); TreeSet<String> collect1 = Stream.of("a", "b", "c").collect(Collectors.toCollection(() -> new TreeSet<>())); //得到数据是否为大写的map Map<String, Boolean> collect3 = Stream.of("a", "b", "c").collect(Collectors.toMap(str -> str, str -> str.equals(str.toUpperCase()) ? true : false)); //统计元素出现的次数 Map<String, Integer> collect4 = Stream.of("a", "b", "c", "b").collect(Collectors.toMap( str -> str, str -> 1, (valueMapper, value) -> valueMapper.intValue() + 1)); TreeMap<String, Integer> collect5 = Stream.of("a", "b", "c", "b").collect(Collectors.toMap( str -> str, str -> 1, (valueMapper, value) -> valueMapper.intValue() + 1, TreeMap::new)); System.out.println(collect); System.out.println(collect1); System.out.println(collect2); System.out.println(collect3); System.out.println(collect4); System.out.println(collect5); }
(2)、join 字符流内容收集方式为连接
/** * join 聚合连接 */ @Test public void test03(){ //无任何介质连接,得到结果abc String collect = Stream.of("a", "b", "c").collect(Collectors.joining()); //连接符号为, 得到a,b,c String collect1 = Stream.of("a", "b", "c").collect(Collectors.joining(",")); //连接符号为:, 前缀为:{ 后缀为:} String collect2 = Stream.of("a", "b", "c").collect(Collectors.joining(",", "{", "}")); System.out.println(collect); System.out.println(collect1); System.out.println(collect2); }
(3)、mapping:处理数据然后收集 collectingAndThen:针对原来的收集器增加后置处理动作
/** * mapping 处理数据然后收集,相当于先mapping操作然后收集 * collectingAndThen 针对原来的收集器,增加新的后置收集处理动作 */ @Test public void test04(){ //转大写再收集 List<String> collect = Stream.of("a", "b", "c").collect(Collectors.mapping((a) -> a.toUpperCase(), Collectors.toList())); for (String str : collect) { System.out.print(str + " "); } //在转为list的基础上进行求总数。也就是说收集器的作用就是计算元素个数 Integer collect1 = Stream.of("a", "b", "c").collect(Collectors.collectingAndThen(Collectors.toList(), list -> list.size())); }
(4)、聚合操作:counting、minBy、maxBy、avragingInt、summingLong等
/** * 聚合操作 * counting 求总数 * minBy 最小值 * maxBy 最大值 * * averagingInt int类型求平均值 * averagingLong Long类型求平均值 * averagingDouble Double类型求平均值 * * summingLong 获得Long类型的SummaryStatistics数据 * summingInt 获得Int类型的SummaryStatistics数据 * summingDouble 获得Double类型的SummaryStatistics数据 * SummaryStatistics 数据可以取得以下数据: getCount()、getSum()、getMin()、getAverage()、getMax() */ @Test public void test05() { Long count = Stream.of("a", "b", "c").collect(Collectors.counting()); String min = Stream.of("1", "2", "3").collect(Collectors.minBy(Comparator.naturalOrder())).get(); String max = Stream.of("1", "2", "3").collect(Collectors.maxBy(Comparator.naturalOrder())).get(); Double avg = Stream.of(1, 2, 3).collect(Collectors.averagingInt(i -> Integer.valueOf(i))); System.out.println("count=" + count); System.out.println("min=" + min); System.out.println("max=" + max); System.out.println("avg=" + avg); //SummaryStatistics 数据可以取得以下数据: getCount()、getSum()、getMin()、getAverage()、getMax() DoubleSummaryStatistics collect = Stream.of(1, 2, 3).collect(Collectors.summarizingDouble(obj -> (double) obj)); System.out.println("最大值:" + collect.getMax() + ", 最小值:" + collect.getMin()); }
(5)、reduce 自定义收集实现累加等
/** * 抱歉,自己之前弄明白又记不起来了 * reduce 做聚合操作,得到单个元素 * reduce(function ) 传递一个聚合方法,默认将聚合的结果作为第一个参数与第二个参数开始聚合 * reduce( identity, function) 带了一个参与聚合的初始值 * reduce( identity, mapper, op) mapper指的是将新元素展缓为identity类型的方法,op指的是元素合并的方法 */ @Test public void test06() { int count = Stream.of(1, 2, 3).collect(Collectors.reducing((a, b) -> a + b)).get(); Integer collect = Stream.of(1, 2, 3).collect(Collectors.reducing(100, (a, b) -> a + b)); ArrayList<Integer> list = new ArrayList<>(); ArrayList<Integer> collect1 = Stream.of(1, 2, 3).collect(Collectors.reducing( list, (i) -> { ArrayList<Integer> al = new ArrayList<>(); al.add(i); return al; }, (ArrayList<Integer> list1, ArrayList<Integer> list2) -> { list1.addAll(list2); return list1; })); for (Integer i : collect1) { System.out.println(i); } }
(6)、groupingBy流内元素分组收集
/** * 测试groupingBy * Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier, 获得key的方法 * Supplier<M> mapFactory, 初始化map的方法 * Collector<? super T, A, D> downstream) 结果收集器 * <p> * Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, 初始化map的方法抵用hashMap的new方法 * Collector<? super T, A, D> downstream) * <p> * groupingBy(Function<? super T, ? extends K> classifier) 默认的结果收集器是toList() * <p> * groupingByConcurrent 并行流分组 */ @Test public void test07() { @Data class Box { private int width; private int height; private String name; public Box(int width, int height, String name) { this.width = width; this.height = height; this.name = name; } } List<Box> boxList = new ArrayList<>(); boxList.add(new Box(2, 3, "盒子1")); boxList.add(new Box(2, 4, "盒子2")); boxList.add(new Box(2, 5, "盒子3")); boxList.add(new Box(3, 3, "盒子4")); boxList.add(new Box(3, 5, "盒子6")); boxList.add(new Box(5, 3, "盒子7")); //将盒子根据宽度进行分装,得到map Map<Integer, List<Box>> collect = boxList.stream().collect(Collectors.groupingBy(o -> o.getWidth())); Map<Integer, List<Box>> list1 = new HashMap<>(); list1.put(2, new ArrayList<Box>() {{ add(new Box(2, 3, "盒子10")); }}); //指定获得初始容器的方法 Map<Integer, List<Box>> collect1 = boxList.stream().collect(Collectors.groupingBy(o -> o.getWidth(), () -> list1, Collectors.toList())); //分组求总数,类似 select count(*) from dual group by width Map<Integer, Long> collect2 = boxList.stream().collect(Collectors.groupingBy(o -> o.getWidth(), Collectors.counting())); System.out.println(1); //多条件分组,就是收集器为其他的分组收集器 }
(7)、partitioningBy 简单分组,分为满足要求与不满足要求的两组
/** * 分组,不过分为true组和false组,相对groupingBy范围小一些 * partitioningBy(Predicate<? super T> predicate, 判断函数 * Collector<? super T, A, D> downstream) 收集器 * <p> * partitioningBy(Predicate<? super T> predicate) 使用默认的toList收集器 */ @Test public void test08() { //得到奇偶集合 Map<Boolean, List<Integer>> collect = Stream.of(1, 2, 3).collect(Collectors.partitioningBy(i -> i % 2 == 0)); //得到奇偶分别个数 Map<Boolean, Long> collect1 = Stream.of(1, 2, 3).collect(Collectors.partitioningBy(i -> i % 2 == 0, Collectors.counting())); System.out.println(1); }
7、lambda简单练习
package com.zhen.orc.jdk8; import lombok.Data; import org.junit.Test; import java.util.*; import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; /** * 网上随意找一些练习题刷一下 * * @author zhen */ public class Test05 { @Test public void test01() { //有如下7个元素黄药师,冯蘅,郭靖,黄蓉,郭芙,郭襄,郭破虏,使用Stream将以郭字开头的元素存入新数组 Stream.of("黄药师", "冯蘅", "郭靖", "黄蓉", "郭芙", "郭襄", "郭破虏").filter(str -> str.startsWith("郭")).collect(Collectors.toList()).toArray(); } @Test public void test02() { //已知ArrayList集合中有如下元素{陈玄风、梅超风、陆乘风、曲灵风、武眠风、冯默风、罗玉风},使用Stream //1、取出前2个元素并在控制台打印输出。 //2、取出后2个元素并在控制台打印输出。 ArrayList al = new ArrayList(); al.add("陈玄风"); al.add("梅超风"); al.add("陆乘风"); al.add("曲灵风"); al.add("武眠风"); al.add("冯默风"); al.add("罗玉风"); System.out.print("前两个元素为:"); al.stream().limit(2).forEach(str -> System.out.print(str + " ")); System.out.println(); System.out.print("后两个元素为:"); al.stream().sorted((str1, str2) -> -1).limit(2).forEach(str -> System.out.print(str + " ")); } @Test public void test03() { //有如下整数1,-2,-3,4,-5 //使用Stream取元素绝对值并打印 Stream.of(1, -2, -3, 4, -5).map(i -> Math.abs(i)).forEach(i -> System.out.print(i + " ")); } @Test public void test04() { //给定一个数字列表,如何返回一个由每个数的平方构成的列表呢? //比如给定【1,2,3,4,5】, 应该返回【1,4,9,16,25】 List<Integer> collect = Stream.of(1, 2, 3, 4, 5).map(i -> (int) Math.pow(i, 2)).collect(Collectors.toList()); System.out.println(collect); } @Test public void test05() { //有两个集合,一个有6个男演员,一个有6个女演员,完成下面的功能 //男演员只要名字为3个字的前三人 //女演员只要姓林的,并且不要第一个 //把过滤后的男演员姓名和女演员姓名合并到一起 //把上一步操作后的元素作为构造方法的参数创建演员对象(实例化一个Actor类,此处尝试使用map),遍历数组 //1、初始化集合 ArrayList<String> manArray = new ArrayList<>(); manArray.add("刘德华"); manArray.add("成龙"); manArray.add("吴彦祖"); manArray.add("周润发"); manArray.add("周星驰"); manArray.add("吴京"); ArrayList<String> womanList = new ArrayList<>(); womanList.add("林心如"); womanList.add("孙俪"); womanList.add("柳岩"); womanList.add("林青霞"); womanList.add("王祖贤"); womanList.add("张曼玉"); @Data class Actor { private String name; public Actor(String name) { this.name = name; } @Override public String toString() { return "Actor{" + "name='" + name + '\'' + '}'; } } Stream.concat( //合并 //男演员 manArray.stream() //名字为3个的 .filter(str -> str.length() == 3) //前3人 .limit(3), //女演员 womanList.stream() //只要姓林的 .filter(str -> str.startsWith("林")) //不要第1个 .skip(1)) //转化为对象 .map(str -> new Actor(str)) //遍历对象 .forEach(actor -> System.out.println(actor)); } @Test public void test06() { /* (1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。 (2) 交易员都在哪些不同的城市工作过? (3) 查找所有来自于剑桥的交易员,并按姓名排序。 (4) 返回所有交易员的姓名字符串,按字母顺序排序。 (5) 有没有交易员是在米兰工作的? (6) 打印生活在剑桥的交易员的所有交易额。 (7) 所有交易中,最高的交易额是多少? (8) 找到交易额最小的交易。 */ //交易类 @Data class Trader { private final String name; private final String city; public Trader(String name, String city) { this.name = name; this.city = city; } } //交易记录类 @Data class Transaction { private final Trader trader; private final int year; private final int value; public Transaction(Trader trader, int year, int value) { this.trader = trader; this.year = year; this.value = value; } } //初始数据 Trader raoul = new Trader("Raoul", "Cambridge"); Trader mario = new Trader("Mario", "Milan"); Trader alan = new Trader("Alan", "Cambridge"); Trader brian = new Trader("Brian", "Cambridge"); List<Transaction> transactions = Arrays.asList( new Transaction(raoul, 2012, 1000), new Transaction(raoul, 2011, 400), new Transaction(brian, 2011, 300), new Transaction(mario, 2012, 710), new Transaction(mario, 2012, 700), new Transaction(alan, 2012, 950) ); //1、找出2011年发生的所有交易,并按交易额排序(从低到高)。 transactions.stream().filter(transaction -> transaction.getYear() == 2011).sorted((transactions1, transactions2) -> transactions1.getValue()> transactions2.getValue() ? 1 : (transactions1.getValue() == transactions2.getValue() ? 0 : -1)).forEach(transaction -> System.out.println(transaction)); //2、交易员都在哪些不同的城市工作过? Map<String, HashSet<String>> collect = transactions.stream() .collect( Collectors.groupingBy(transaction -> transaction.getTrader().getName(), Collector.of( () -> new HashSet<>(), (set, item) -> set.add(item.getTrader().getCity()), (set1, set2) -> { set1.addAll(set2); return set1; }, new Collector.Characteristics[0]))); collect.entrySet().stream().forEach( entry -> { System.out.print(entry.getKey() + "工作过的城市:"); entry.getValue().stream().forEach(str -> System.out.print(str + " ")); System.out.println(); } ); //3、查找所有来自于剑桥的交易员,并按姓名排序。 System.out.print("来自剑桥的交易员有:"); transactions.stream() .filter(transaction -> transaction.getTrader().getCity().equals("Cambridge")) .map(transaction -> transaction.getTrader()) .distinct() .sorted(Comparator.comparing(Trader::getName)).forEach(trader -> { System.out.print(trader.getName() + " "); }); System.out.println(); //4、返回所有交易员的姓名字符串,按字母顺序排序。 System.out.print("所有交易员的姓名(字母排序):"); transactions.stream().map(transaction -> transaction.getTrader().getName()).distinct().sorted(Comparator.naturalOrder()).forEach(str -> { System.out.print(str + " "); }); System.out.println(); //5、有没有交易员是在米兰工作的 boolean workInMilan = transactions.stream().anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan")); //6、打印生活在剑桥的交易员的所有交易额 Long cambridgeTraderMoney = transactions.stream() .filter(transaction -> transaction.getTrader().getCity().equals("Cambridge")) .map(transaction -> transaction.getValue()).collect(Collectors.counting()); //7、 所有交易中,最高的交易额是多少? int maxTraderValue = transactions.stream().collect(Collectors.maxBy(Comparator.comparing(transaction -> transaction.getValue()))).get().getValue(); //8、找到交易额最小的交易 Transaction transaction1 = transactions.stream().collect(Collectors.minBy(Comparator.comparing(transaction -> transaction.getValue()))).get(); } }