java-函数式接口和Stream流

news/2024/11/25 21:53:51/

java-函数式接口和Stream流

在这里插入图片描述

一、函数式接口

1.1函数式接口概述

  • 概念

    有且仅有一个抽象方法的接口

  • 如何检测一个接口是不是函数式接口

    @FunctionalInterface

    放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败

  • 注意事项

    定义函数式接口的时候,虽然@FunctionalInterface是可选的。但是,建议加上该注解

1.2函数式接口作为方法的参数

  • 代码演示

    public class RunnableDemo {public static void main(String[] args) {//在主方法中调用startThread方法//Lambda方式startThread(() -> System.out.println(Thread.currentThread().getName() + "线程启动了"));}private static void startThread(Runnable r) {new Thread(r).start();}
    }
    

1.3函数式接口作为方法的返回值

  • 代码演示

    public class ComparatorDemo {public static void main(String[] args) {//定义集合,存储字符串元素ArrayList<String> array = new ArrayList<String>();array.add("cccc");array.add("aa");array.add("b");array.add("ddd");System.out.println("排序前:" + array);Collections.sort(array, getComparator());System.out.println("排序后:" + array);}private static Comparator<String> getComparator() {//Lambda方式实现return (s1, s2) -> s1.length() - s2.length();}
    }
    

1.4 Supplier常用函数式接口

  • Supplier接口

    Supplier<T>接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。

  • 常用方法

    只有一个无参的方法

    方法名说明
    T get()按照某种实现逻辑(由Lambda表达式实现)返回一个数据
  • 代码演示

    public class SupplierDemo {public static void main(String[] args) {String s = getString(() -> "刘备");System.out.println(s);Integer i = getInteger(() -> 30);System.out.println(i);}//定义一个方法,返回一个整数数据private static Integer getInteger(Supplier<Integer> sup) {return sup.get();}//定义一个方法,返回一个字符串数据private static String getString(Supplier<String> sup) {return sup.get();}}
    

1.5 Consumer常用函数式接口

  • Consumer接口

    Consumer<T>接口也被称为消费型接口,它消费的数据的数据类型由泛型指定

  • 常用方法

    Consumer<T>:包含两个方法

    方法名说明
    void accept(T t)对给定的参数执行此操作
    default Consumer<T> andThen(Consumer after)返回一个组合的Consumer,依次执行此操作,然后执行 after操作
  • 代码演示

    public class ConsumerDemo {public static void main(String[] args) {//操作一operatorString("刘备", s -> System.out.println(s));//操作二operatorString("刘备", s -> System.out.println(new StringBuilder(s).reverse().toString()));System.out.println("--------");//传入两个操作使用andThen完成operatorString("刘备", s -> System.out.println(s), s -> System.out.println(new StringBuilder(s).reverse().toString()));}//定义一个方法,用不同的方式消费同一个字符串数据两次private static void operatorString(String name, Consumer<String> con1, Consumer<String> con2) {
    //        con1.accept(name);
    //        con2.accept(name);con1.andThen(con2).accept(name);}//定义一个方法,消费一个字符串数据private static void operatorString(String name, Consumer<String> con) {con.accept(name);}
    }
    

1.6 Predicate常用函数式接口

  • Predicate接口

    Predicate<T>接口通常用于判断参数是否满足指定的条件

  • 常用方法

    方法名说明
    boolean test(T t)对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
    default Predicate<T> negate()返回一个逻辑的否定,对应逻辑非
    default Predicate<T> and(Predicate other)返回一个组合判断,对应短路与
    default Predicate<T> or(Predicate other)返回一个组合判断,对应短路或
  • 代码演示

    public class PredicateDemo01 {public static void main(String[] args) {boolean b1 = checkString("hello", s -> s.length() > 8);System.out.println(b1);boolean b2 = checkString("helloworld",s -> s.length() > 8);System.out.println(b2);}//判断给定的字符串是否满足要求private static boolean checkString(String s, Predicate<String> pre) {
    //        return !pre.test(s);return pre.negate().test(s);}
    }public class PredicateDemo02 {public static void main(String[] args) {boolean b1 = checkString("hello", s -> s.length() > 8);System.out.println(b1);boolean b2 = checkString("helloworld", s -> s.length() > 8);System.out.println(b2);boolean b3 = checkString("hello",s -> s.length() > 8, s -> s.length() < 15);System.out.println(b3);boolean b4 = checkString("helloworld",s -> s.length() > 8, s -> s.length() < 15);System.out.println(b4);}//同一个字符串给出两个不同的判断条件,最后把这两个判断的结果做逻辑与运算的结果作为最终的结果private static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2) {return pre1.or(pre2).test(s);}//判断给定的字符串是否满足要求private static boolean checkString(String s, Predicate<String> pre) {return pre.test(s);}
    }
    

1.7 Function常用函数式接口

  • Function接口

    Function<T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值

  • 常用方法

    方法名说明
    R apply(T t) 将此函数应用于给定的参数
    default Function andThen(Function after)返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
  • 代码演示

    public class FunctionDemo {public static void main(String[] args) {//操作一convert("100",s -> Integer.parseInt(s));//操作二convert(100,i -> String.valueOf(i + 566));//使用andThen的方式连续执行两个操作convert("100", s -> Integer.parseInt(s), i -> String.valueOf(i + 566));}//定义一个方法,把一个字符串转换int类型,在控制台输出private static void convert(String s, Function<String,Integer> fun) {
    //        Integer i = fun.apply(s);int i = fun.apply(s);System.out.println(i);}//定义一个方法,把一个int类型的数据加上一个整数之后,转为字符串在控制台输出private static void convert(int i, Function<Integer,String> fun) {String s = fun.apply(i);System.out.println(s);}//定义一个方法,把一个字符串转换int类型,把int类型的数据加上一个整数之后,转为字符串在控制台输出private static void convert(String s, Function<String,Integer> fun1, Function<Integer,String> fun2) {String ss = fun1.andThen(fun2).apply(s);System.out.println(ss);}}
    

二、Stream流

2.1 概述

  • Stream是Java 8 API添加的一个新的抽象,称为流Stream,以一种声明性方式处理数据集合。它不是数据结构并不保存数据,它的主要目的在于计算
  • Stream流把真正的函数式编程风格引入到Java中
  • Stream流是对集合(Collection)对象功能的增强,与Lambda表达式结合,可以提高编程效率、间接性和程序可读性。

2.2 特点

  • 代码简洁:函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环

  • 多核友好:Java函数式编程使得编写并行程序如此简单,就是调用一下方法

2.3 流程

  • 将集合转换为Stream流

  • 操作Stream流(中间操作,终端操作

2.4 生成Stream流的方式

  • Collection体系集合

    使用默认方法stream()生成流, default Stream<E> stream()

  • Map体系集合

    Map转成Set集合,间接的生成流

  • 数组

    通过Stream接口的静态方法of(T... values)生成流

  • 代码演示

    public class StreamDemo {public static void main(String[] args) {//Collection体系的集合可以使用默认方法stream()生成流List<String> list = new ArrayList<String>();Stream<String> listStream = list.stream();Set<String> set = new HashSet<String>();Stream<String> setStream = set.stream();//Map体系的集合间接的生成流Map<String,Integer> map = new HashMap<String, Integer>();Stream<String> keyStream = map.keySet().stream();Stream<Integer> valueStream = map.values().stream();Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();//数组可以通过Stream接口的静态方法of(T... values)生成流String[] strArray = {"hello","world","java"};Stream<String> strArrayStream = Stream.of(strArray);Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");Stream<Integer> intStream = Stream.of(10, 20, 30);}
    }
    

2.5 Stream流中间操作方法

  • 概念

    中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作。

  • 常见方法

    方法名说明
    Stream<T> filter(Predicate predicate)用于对流中的数据进行过滤
    Stream<T> limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据
    Stream<T> skip(long n) 跳过指定参数个数的数据,返回由该流的剩余元素组成的流
    static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
    Stream<T> distinct() 返回由该流的不同元素(根据Object.equals(Object) )组成的流
    Stream<T> sorted()返回由此流的元素组成的流,根据自然顺序排序
    Stream<T> sorted(Comparator comparator)返回由该流的元素组成的流,根据提供的Comparator进行排序
    <R> Stream<R> map(Function mapper) 返回由给定函数应用于此流的元素的结果组成的流
    IntStream mapToInt(ToIntFunction mapper)返回一个IntStream其中包含将给定函数应用于此流的元素的结果

2.6 Stream流终结操作方法

  • 概念

    终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作。

  • 常见方法

    方法名说明
    void forEach(Consumer action)对此流的每个元素执行操作
    long count()返回此流中的元素数

2.7 Stream流综合练习【应用】

  • 案例需求

    现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作

    • 男演员只要名字为3个字的前三人

    • 女演员只要姓林的,并且不要第一个

    • 把过滤后的男演员姓名和女演员姓名合并到一起

    • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

    演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法

  • 代码实现

    public class Actor {private String name;public Actor(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
    }public class StreamTest {public static void main(String[] args) {//创建集合ArrayList<String> manList = new ArrayList<String>();manList.add("周润发");manList.add("成龙");manList.add("刘德华");manList.add("吴京");manList.add("周星驰");manList.add("李连杰");ArrayList<String> womanList = new ArrayList<String>();womanList.add("林心如");womanList.add("张曼玉");womanList.add("林青霞");womanList.add("柳岩");womanList.add("林志玲");womanList.add("王祖贤");//男演员只要名字为3个字的前三人Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3);//女演员只要姓林的,并且不要第一个Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);//把过滤后的男演员姓名和女演员姓名合并到一起Stream<String> stream = Stream.concat(manStream, womanStream);//把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
    //        stream.map(Actor::new).forEach(System.out::println);stream.map(Actor::new).forEach(p -> System.out.println(p.getName()));Stream.concat(manList.stream().filter(s -> s.length() == 3).limit(3),womanList.stream().filter(s -> s.startsWith("林")).skip(1)).map(Actor::new).forEach(p -> System.out.println(p.getName()));}
    }
    

2.8 Stream流的收集操作

  • 概念

    对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中。

  • 常用方法

    方法名说明
    R collect(Collector collector)把结果收集到集合中
  • 工具类Collectors提供了具体的收集方式

    方法名说明
    public static <T> Collector toList()把元素收集到List集合中
    public static <T> Collector toSet()把元素收集到Set集合中
    public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中
  • 代码演示

    public class CollectDemo {public static void main(String[] args) {//创建List集合对象List<String> list = new ArrayList<String>();list.add("刘备");list.add("关羽");list.add("张飞");list.add("赵云");//需求1:得到名字为3个字的流Stream<String> listStream = list.stream().filter(s -> s.length() == 3);//需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历List<String> names = listStream.collect(Collectors.toList());for(String name : names) {System.out.println(name);}//创建Set集合对象Set<Integer> set = new HashSet<Integer>();set.add(10);set.add(20);set.add(30);set.add(33);set.add(35);//需求3:得到年龄大于25的流Stream<Integer> setStream = set.stream().filter(age -> age > 25);//需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历Set<Integer> ages = setStream.collect(Collectors.toSet());for(Integer age : ages) {System.out.println(age);}//定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成String[] strArray = {"刘备,40", "关羽,35", "张飞,33", "赵云,25"};//需求5:得到字符串中年龄数据大于28的流Stream<String> arrayStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);//需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值Map<String, Integer> map = arrayStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));Set<String> keySet = map.keySet();for (String key : keySet) {Integer value = map.get(key);System.out.println(key + "," + value);}}
    }
    

Ending…


http://www.ppmy.cn/news/185474.html

相关文章

100篇带你入门——嵌入式系统开发平台

嵌入式系统开发是一项关键的技术领域&#xff0c;涵盖了从传统家用电器到现代智能手机、智能车辆等各种应用的广泛范围。在这个领域中&#xff0c;选择适合的开发平台对于项目的成功至关重要。本文将介绍几个常用的嵌入式系统开发平台&#xff0c;并进行比较分析&#xff0c;以…

【小张和Oracle数据库】Java两年半练习生裁员后竟然找到了一份DBA的工作?

一、引言 大家好&#xff0c;我叫张小念&#xff08;小名念念&#xff09;&#xff0c;家里人都叫宝儿。 一个java两年半的练习生&#xff0c;经历了起起伏伏的疫情时代&#xff0c;终于在java一行也算是入了门。 但是&#xff0c;计划永远赶不上变化&#xff0c; 有一天经…

联想笔记本电脑开机无法修复计算机,联想笔记本开机没反应怎么办 笔记本无法开机的解决方法...

笔记本电脑使用的时间长了&#xff0c;一样也是会出现一些小故障的&#xff0c;比如说像开机后&#xff0c;电源指示灯亮&#xff0c;但是电脑的显示器屏就是没有反应。下面小编就来给大家介绍一下联想笔记本开机没反应怎么办及笔记本无法开机的解决方法。 第一步&#xff1a;联…

联想t168服务器硬盘,联想万全T168服务器板载Sata+raid系统设置图解.doc

联想万全T168服务器板载Sata raid系统设置一、RAID?信息显示系统启动时&#xff0c;SATA?RAID?BIOS?初始化后&#xff0c;在屏幕上显示适配器的BIOS版本和磁盘阵列状态和当前的磁盘阵列配置。其中阵列状态“status”中包括了两种可能出现的情形&#xff1a;正常状态(Optima…

联想微型计算机内容不清楚,联想L2060wa显示器显示不清楚,特别是文字更无法看...

公告&#xff1a; 为响应国家净网行动&#xff0c;部分内容已经删除&#xff0c;感谢读者理解。 话题&#xff1a;联想L2060wa显示器显示不清楚,特别是文字更无法看清,不知道显示回答&#xff1a;将能找到的螺丝全部卸下3、将显示器仰放&#xff0c;然后显示器天侧前框你好&…

python爬取b站搜索结果播放地址_Golang 爬虫快速入门 | 获取B站全站的视频数据

提到爬虫&#xff0c;总会联想到Python。似乎Python是爬虫的唯一选择。爬虫只是完成一个访问页面然后收集数据的任务&#xff0c;用任何语言来写都能实现。相比较Python快速实现但是庞大的体型&#xff0c;Golang来写爬虫似乎是更好的又一选择。 HTTP请求 Golang语言的HTTP请…

启用计算机的fn键,联想 ThinkPad 笔记本 Fn 键 关闭与启用方法

为适应部分用户的传统使用习惯,采用媒体功能键设计的笔记本电脑,BIOS中一般预留了热键模式切换开关,可通过切换开关来满足个人使用需要。 1、电脑关机状态下,按下一键恢复按键。目前销售的联想笔记本电脑中,一键恢复按键多在电脑右侧(或左侧)以凹陷孔形式出现,建议使用捅…

联想笔记本计算机服务在哪里,北京联想电脑服务站都在哪里?我在宣武门应当到哪里去修电脑呢?(高额悬赏 )...

离你最近的是 联想产品客户服务中心 北京市宣武区南线阁41号院底商1-2 010-83547764/83558776/63542261 NewThinkCentre、笔记本、台式 联想产品客户服务中心 北京市海淀区知春路2号院3号楼3门1层 010-62059288/62052889 台式、NewThinkCentre、笔记本 联想产品客户服务中心 北…