目录
3. 内置函数式接口(Built-in Functional Interfaces)
Collectors.mapping()将Stream中的元素,映射后,收集至新集合
一、Java8中Interface接口
interface接口 的设计目的是面向接口编程,提高扩展性。
●Java8中,接口中除了抽象方法外,还可以定义default默认方法和static静态方法。
○default修饰的默认方法,属于实例方法,可以被实现类调用或重写。
- 调用:实现类必须implements接口,才能调用该接口的default默认方法。
- 重写:实现类implements不同接口时,接口中存在相同签名的方法(名称、参数、类型完全一致),则实现类必须重写该方法,明确方法定义;
○static修饰的静态方法,属于类的静态方法。但它不能被子类继承,只能用interface接口名称调用。
二、Lambda 表达式
- Lambda 表达式本质是一个匿名函数,用于把函数作为参数,传入方法中,实现函数式编程风格。
- 使用Lambda 表达式可以使代码变的更加简洁紧凑。
语法格式
(parameters)-> expression 或 (parameters)->{ statements;} 接口名 对象名=(参数类型 参数名称)->{方法体} (参数类型,参数名称): 抽象方法的参数,形参 ->固定写法 {}存放方法的内容
public static void main(String[] args) { new Thread(new Runnable() { // 1.定义了一个没有名字的内部类 // 2.实现了Runnable接口 // 3.创建Runnable实现类对象 @Override public void run() { System.out.println("子线程1执行任务"); } }).start(); new Thread(() -> System.out.println("子线程2执行任务")).start(); System.out.println("主线程执行任务"); } 运行结果: 子线程1执行任务 主线程执行任务 子线程2执行任务
创建函数式接口类型的对象
函数式接口:接口中只有一个抽象方法(static default,抽象方法只能有1个)//创建函数式接口类型的对象 //函数式接口:接口中只有一个抽象方法(static default,抽象方法只能有1个) //接口名 对象名=(参数类型 参数名称)->{方法体} //(参数类型,参数名称): 抽象方法的参数,形参 //->固定写法 //{}存放方法的内容 //lambda的精简写法 //a.参数的类型省略 //b.()可以省略,参数个数只有1个的时候可以省略 //c.{ return ;}可以省略,只有一条语句的时候才能省略 public class Demo02 { public static void main(String[] args) { goSWimining(new Swimable() { @Override public void swimming() { System.out.println("zkt在游泳"); } }); //接口名对象名=(参数类型参数名称)->{方法体} goSWimining(() -> { System.out.println("zkt1在游泳"); }); goSWimining(() -> System.out.println("zkt2在游泳")); } public static void goSWimining(Swimable s) { s.swimming(); } } interface Swimable { void swimming(); }
1. lambda的精简写法
- 参数的类型省略
- ()可以省略,参数个数只有1个的时候可以省略
- { return ;}可以省略,只有一条语句的时候才能省略
public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(Arrays.asList(3,2,1,5,6,7)); //写法1:匿名内部类写Compartor实现类对象 // Collections.sort(list,new Comparator<Integer>() { // // @Override // public int compare(Integer o1, Integer o2) { // // TODO Auto-generated method stub // return o2-o1; // } // }); //写法2:1ambda表达式写法 Collections.sort(list,(Integer o1,Integer o2)->{return o2-o1;}); //写法3:省略参数类型 Collections.sort(list,( o1, o2)->{return o2-o1;}); //写法4:省略{return ;} Collections.sort(list,( o1, o2)->o2-o1); System.out.println(list); }
public class Demo04 { public static void main(String[] args) { List<Person> persons = new ArrayList<Person>(); persons.add(new Person("zkt1", 21,177)); persons.add(new Person("zkt2", 17,180)); persons.add(new Person("zkt3", 24,187)); Collections.sort(persons,(p1,p2)->{return p1.getAge()-p2.getAge();}); persons.forEach((t)->{System.out.println(t);}); } } class Person { private String name; private int age; private int height; public Person(String name, int age, int height) { super(); this.name = name; this.age = age; this.height = height; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", height=" + height + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } }
2. 函数式接口 Functional Interface
只有一个抽象方法的接口(可以定义多个非抽象方法)。可以使用@FunctionalInterface接口定义,强化语义规范。
函数式接口,也被称为SAM 接口(Single Abstract Method Interfaces)作用
基于函数式接口,可以使用Lambda表达式进行实现,实现函数式编程。//lambda表达式使用的前提: //1.方法的参数或者变量的类型是接口 //2.这个接口中只能有一个抽象方法 public class Demo05 { public static void main(String[] args) { test(new Flyable() { @Override public void fly() { System.out.println("我能飞"); } }); test(() -> { System.out.println("我能飞"); }); } public static void test(Flyable fly) { fly.fly(); } } @FunctionalInterface //函数式接口注解,表示此接口只有一个 interface Flyable { public abstract void fly(); }
public class Demo01 { public static void main(String[] args) { //调用函数式接口中的方法 method((arr) -> { int sum = 0; for (int i : arr) { sum = sum + i; } return sum; }); } //使用自定义的函数式接口作为方法的参数 public static void method(Opertor op) { int[] arr = { 1, 2, 3, 4 }; int sum = op.getSum(arr); System.out.println(sum); } } @FunctionalInterface interface Opertor { int getSum(int[] arr); }
3. 内置函数式接口(Built-in Functional Interfaces)
在 Java 8 中专门有一个包放函数式接口java.util.function,该包下的所有接口都有 @FunctionalInterface 注解,提供函数式编程方式。
3.1 Supplier<T>
供给型接口
抽象方法 描述 T get() 返回一个自定义数据( 无参数,有返回值) public class Demo02Supplier { public static void main(String[] args) { // Supplier --- 供给型接口 // T get();--方法没有参数,有返回值,需要对外提供一个符合泛型类型的对象数据 System.out.println("main中的方法"); printMax(()->{ System.out.println("Supplier对象的get方法"); int[] arr = {1,3,5,10,4}; Arrays.sort(arr); return arr[arr.length-1]; }); } //输出数组中最大的元素 public static void printMax(Supplier<Integer> sup) { System.out.println("printMax方法"); int max = sup.get(); System.out.println(max); } } 运行结果: main中的方法 printMax方法 Supplier对象的get方法 10
public class Demo03Supplier2 { public static void main(String[] args) { // Supplier --- 供给型接口 // T get(); // 1-100之间的随机数 //getRandNum(() -> (int) (Math.random() * 100 + 1)); // 20-100随机的数--偶数 Supplier<Integer> sup = () -> { while(true) { int random = (int) (Math.random() * 80 + 20); if((random & 1) == 0) { return random; } } }; getRandNum(sup); } public static void getRandNum(Supplier<Integer> sup) { Integer integer = sup.get(); System.out.println(integer); } }
3.2 Consumer<T>
消费型接口
抽象方法 描述 void accept(T t) 接收一个参数进行消费,无返回结果 (因为没有返回值,接口里面执行内容和调用方没什么关联 – 解耦 public class Demo04ConSumer { public static void main(String[] args) { // ConSumer消费型接口 void accept(T t); // 方法有参数,没有返回值,消费一个数据,数据类型由泛型决定 //字符串转大写 Consumer<String> con1 = s -> System.out.println(s.toUpperCase()); //printUpper(con1, "HelloWorld"); //字符串转小写 Consumer<String> con2 = s -> System.out.println(s.toLowerCase()); //printLower(con2, "HelloWorld"); printUpeerAndLower(con1,con2,"hxjxky"); } public static void printUpper(Consumer<String> con, String str) { con.accept(str); } public static void printLower(Consumer<String> con, String str) { con.accept(str); } public static void printUpeerAndLower(Consumer<String> con1,Consumer<String> con2, String str) { // con1.accept(str); // con2.accept(str); //使用默认方法andThen() //在消费一个数据的时候,可以先做一个操作,然后再做一个操作,实现操作组合 con1.andThen(con2).accept(str); } } 运行结果: HXJXKY hxjxky
3.3 Function<T,R>
函数型接口
Function 接口接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose, andThen)。
抽象方法 描述 R apply(T t) 传入一个参数,返回需要的结果 public class Demo05Function { // interface Function<T, R> ---转换接口 // R apply(T t); public static void main(String[] args) { //将字符串数字转成数字 //Function<String, Integer> fun =(str)->{return Integer.parseInt(str);}; //简写方式 Function<String, Integer> fun =str-> Integer.parseInt(str); method(fun,"12345"); //打印字符串的长度 method(str-> str.length(), "aabmdijej"); } public static void method(Function<String,Integer> f,String str) { Integer num = f.apply(str); System.out.println(num); } } 运行结果: 12345 9
public class Demo06Function2 { public static void main(String[] args) { method(str->str.length(), num->new double[num], "abdf"); } //将一个字符串转成对应的长度的double类型的数组 // string-->Integer // Integer-->double[] public static void method(Function<String, Integer> f1, Function<Integer, double[]> f2, String str) { Integer num = f1.apply(str); double[] d = f2.apply(num); System.out.println(Arrays.toString(d)); } } 运行结果: [0.0, 0.0, 0.0, 0.0]
3.4 Predicate<T,R>
断言型接口
Predicate接口是只有一个参数的返回布尔类型值的 断言型 接口。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与and,或or,非negate):
抽象方法 描述 boolean test(T t) 传入一个参数,返回布尔值(满足:true,不满足:false) public class Demo07Predicate { // Predicate boolean test(T t)--传入一个参数,返回值为布尔类型的 // 根据传入的参数,进行某些判断,结果boolean // 断言型接口 public static void main(String[] args) { //判断某个数字是否是偶数 //boolean b=method((num)->{return (num&1)==0;},102); Predicate<Integer> p1=num->(num&1)==0; boolean b=method(p1,102); System.out.println("102是否是偶数:"+b); //判断某个数字是否大于100 Predicate<Integer> p2=num->num>=100; boolean b1 =method(p2, 22); System.out.println("22是否是大于100:"+b1); boolean b2 =method(p1,p2,5); System.out.println(b2); } public static boolean method(Predicate<Integer> pre,Integer num) { boolean b=pre.test(num); return b; } public static boolean method(Predicate<Integer> p1,Predicate<Integer> p2,Integer num) { //与运算 boolean b=p1.and(p2).test(num); //或运算 boolean b1=p1.or(p2).test(num); //非 boolean b2=p1.negate().test(num); return b2; } } 运行结果: 102是否是偶数:true 22是否是大于100:false true
三、Stream流
- java.util.Stream 表示能应用在一组元素上一次执行的操作序列。
- Stream操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,可以连续完成多个操作。
public class Demo01 { public static void main(String[] args) { List<String> list = new ArrayList<String>(); Collections.addAll(list,"张三","李四","王五","张kt"); //1.拿到所有姓张的元素 ArrayList<String> listZhangArrayList = new ArrayList<String>(); for (String string : list) { if(string.startsWith("张")) { listZhangArrayList.add(string); } } //2.拿到长度为3的元素 ArrayList<String> threeArrayList = new ArrayList<String>(); for (String string : listZhangArrayList) { if(string.length() ==3) threeArrayList.add(string); } //3.打印保存 for (String string : threeArrayList) { System.out.println(string); } System.out.println("================"); list.stream(). filter(str->str.startsWith("张")) .filter(str->str.length()==3). forEach(str->System.out.println(str)); } }
1. 创建Stream
Stream 的创建需要指定一个数据源。
//Stream流的创建方法 public class Demo02 { // 1.Collection集合提供方法 default Stream<E> steam() // 2.Stream接口提供of public static void main(String[] args) { // 1.Collection集合提供方法 default Stream<E> steam() List<String> list = new ArrayList<String>(); Stream<String> stream1 = list.stream(); System.out.println(stream1); Set<String> set = new HashSet<String>(); stream1 = set.stream(); System.out.println(stream1); Map<Integer, String> map = new HashMap<Integer, String>(); Stream<Integer> strem2 = map.keySet().stream(); Stream<String> strem3 = map.values().stream(); Stream<Map.Entry<Integer, String>> strem4 = map.entrySet().stream(); //方式2: Stream<String> strem5 =Stream.of("aa","bb","cc"); String[] strs = {"aa","bb","cc"}; Stream<String> strem6 =Stream.of(strs); int[] ints= {1,2,3,4,5}; Stream<int[]> strem7 =Stream.of(ints); } }
2. foreach方法
List<String> list = new ArrayList<String>(); Collections.addAll(list, "z张三", "l李四", "w王五", "z张kt"); // 1.foreach方法-- list.stream().forEach(str-> System.out.println(str)); System.out.println(list.stream().count()); 运行结果: z张三 l李四 w王五 z张kt 4
2. Filter 过滤
过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作。所以过滤后的结果,可以继续进行其它Stream操作(例如forEach,forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作)。
List<String> list = new ArrayList<String>(); Collections.addAll(list, "张三", "李四", "王五", "z张柯特"); // 3.filter() list.stream().filter((str)->str.length()==2).forEach(System.out::println); 运行结果: 张三 李四 王五
3. limit(long )--获取流中的前n个元素
List<String> list = new ArrayList<String>(); Collections.addAll(list, "张三", "李四", "王五", "z张柯特"); // 4.Stream limit(long )--获取流中的前n个元素 list.stream().limit(3).forEach(System.out::println); 运行结果: 张三 李四 王五
4. skip()--跳过前几个元素
List<String> list = new ArrayList<String>(); Collections.addAll(list, "张三", "李四", "王五", "z张柯特"); // 5.skip()--跳过前几个元素 list.stream().skip(2).forEach(System.out::print); 运行结果: 王五z张柯特
5. Map 映射
映射是一个中间操作, 会将元素根据指定的 Function 接口来依次将元素转成另外的对象。
List<String> list = new ArrayList<String>(); Collections.addAll(list, "张三", "李四", "王五", "z张柯特"); // 6.map()--可以将一种流转成另一种流 list.stream().map((str)->{return str.length();}).forEach(System.out::println); 运行结果: 2 2 2 4
6. Sorted 排序
排序是一个 中间操作,返回的是排序好后的 Stream。(不影响原数据)
List<String> list = new ArrayList<String>(); Collections.addAll(list, "z张三", "l李四", "w王五", "z张柯特"); // 7.sorted() sorted(Compartor) list.stream().sorted((s1,s2)->{return s2.length()-s1.length();}).forEach(System.out::println); 运行结果: z张柯特 z张三 l李四 w王五
7. Match 匹配
Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是 最终操作 ,并返回一个 boolean 类型的值。
List<String> list = new ArrayList<String>(); Collections.addAll(list, "z张三", "l李四", "w王五", "z张柯特"); // 8.allMatch()--判断所有的元素是否满足某个条件 // anyMatch() noneMatch boolean b=list.stream().allMatch(str->str.length()==3); System.out.println(b); boolean b1=list.stream().anyMatch(str->str.length()==3); System.out.println(b1); boolean b3 = list.stream().noneMatch(str -> str.length() == 4); System.out.println(b3); 运行结果: false true false
8. distinct去掉重复的元素9
public class Demo03 { public static void main(String[] args) { ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList("aa","bb","cc")); arrayList.stream().distinct().forEach(System.out::println); ArrayList<Person> persons = new ArrayList<Person>(); persons.add(new Person("zkt1")); persons.add(new Person("zkt2")); persons.add(new Person("zkt1")); persons.add(new Person("zkt2")); persons.stream().distinct().forEach(System.out::println); } } class Person{ private String nameString; public Person(String nameString) { super(); this.nameString = nameString; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((nameString == null) ? 0 : nameString.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (nameString == null) { if (other.nameString != null) return false; } else if (!nameString.equals(other.nameString)) return false; return true; } @Override public String toString() { return "Person [nameString=" + nameString + "]"; } } 运行结果: aa bb cc Person [nameString=zkt1] Person [nameString=zkt2]
9. Collectors
public static void main(String[] args) { // ● Collectors.toList() // ● Collectors.toSet() // ● Collectors.toMap() // Collectors.toCollection() List<String> langList = Arrays.asList("abc", "debft", "gkh", "abc"); LinkedList<String> newList2 = langList.stream().filter((s) -> s.contains("b")) .collect(Collectors.toCollection(LinkedList::new)); List<String> newList1 = langList.stream().filter((s) -> s.contains("b")).collect(Collectors.toList()); Set<String> newset1 = langList.stream().filter((s) -> s.contains("b")).collect(Collectors.toSet()); Map<String, Integer> newmap1 = langList.stream().filter(s -> s.contains("b")).distinct() .collect(Collectors.toMap(s -> s, s -> s.length())); System.out.println(newList2); System.out.println(newset1); System.out.println(newmap1); } 运行结果: [abc, debft, abc] [abc, debft] {abc=3, debft=5}
Collectors.mapping()将Stream中的元素,映射后,收集至新集合
public static void main(String[] args) { List<String> numberStrings = Arrays.asList("4344", "6641", "3432", "6432", "6423", "9423"); //Collectors.mapping()将Stream中的元素,映射后,收集至新集合 //过滤掉不包含字符3的元素,并将其转成Integer类型的集合 List<Integer> intList = numberStrings.stream().filter(s -> s.contains("3")) .collect(Collectors.mapping(s -> Integer.parseInt(s), Collectors.toList())); for (Integer integer : intList) { System.out.println(integer); } }
Collectors.groupingBy() 分组
public static void main(String[] args) { // Collectors.groupingBy() 分组 List<String> langList = Arrays.asList("abc", "de", "gkhf", "abc"); // 按照首字符分组 Map<Character, List<String>> map = langList.stream() .collect(Collectors.groupingBy((s) -> s.charAt(0), Collectors.toList())); System.out.println(map); // 按照长度分组 Map<Integer, List<String>> map1 = langList.stream() .collect(Collectors.groupingBy((s) -> s.length(), Collectors.toList())); System.out.println(map1); } 运行结果: {a=[abc, abc], d=[de], g=[gkhf]} {2=[de], 3=[abc, abc], 4=[gkhf]}
10. Parallel Streams 并行流
Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
public static void main(String[] args) { ArrayList<Integer> arrayList = new ArrayList<Integer>(); // 获取并行流的方法1:.parallelStream() Stream<Integer> stream1 = arrayList.parallelStream(); // 获取并行流的方法2:stream().parallel() Stream<Integer> stream2 = arrayList.stream().parallel(); //检查查并行流 testParaller(); } // 并行 private static void testParaller() { long number=Stream.of(9, 3, 4, 6, 1).parallel().filter(num -> { System.out.println(Thread.currentThread().getName() +"@"+ num); return true; }).count(); System.out.println(number); }
函数式接口总结
- Predicate、Function、Consumer、Comparator
- 通过链式编程,使得它可以方便地对数据进行链式处理。
- 方法参数都是函数式接口类型。
- 一个 Stream 只能操作一次,操作完就关闭了,继续使用这个 Stream 会报错。
- Stream 不保存数据,不改变数据源。