流世幻羽

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

函数式接口

函数式接口在Java中是指:有且仅有一个抽象方法的接口。
函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可
以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
备注:“语法糖”是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实
底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部
类的“语法糖”,但是二者在原理上是不同的。

@FunctionalInterface注解

@FunctionalInterface
public interface ParentInterface {
    String method();
}

 

性能浪费的日志案例
注:日志可以帮助我们快速的定位问题,记录程序运行过程中的情况,以便项目的监控和优化。
一种典型的场景就是对参数进行有条件使用,例如对日志消息进行拼接后,在满足条件的情况下进行打印输出:

  1 package com.lamda;
  2 
  3 import org.junit.Test;
  4 
  5 import java.util.*;
  6 import java.util.function.Consumer;
  7 import java.util.function.Function;
  8 import java.util.function.Predicate;
  9 import java.util.function.Supplier;
 10 
 11 public class DemoChild {
 12     /**
 13      * 自定义函数式编程
 14      */
 15     @Test
 16     public void test01() {
 17         doSomeThing(() -> {
 18             System.out.println("1111");
 19             return "";
 20         });
 21     }
 22 
 23     private static void doSomeThing(ParentInterface child) {
 24         child.method();
 25     }
 26 
 27     //延迟加载
 28     @Test
 29     public void test02() {
 30         String msgA = "a";
 31         String msgB = "ab";
 32         String msgC = "acb";
 33         log(1, () -> {
 34             return msgA + msgB + msgC;
 35         });
 36     }
 37 
 38     public void log(int level, ParentInterface p) {
 39         if (level == 1) {
 40             System.out.println(p.method());
 41         }
 42     }
 43 
 44     //作为参数
 45     @Test
 46     public void test03() {
 47         startThread(() -> {
 48             System.out.println("abc");
 49         });
 50     }
 51 
 52     public static void startThread(Runnable task) {
 53         new Thread(task).start();
 54     }
 55 
 56     //返回值
 57     private static Comparator<String> newComparator() {
 58         return (a, b) -> b.length() - a.length();
 59     }
 60 
 61     @Test
 62     public void test04() {
 63         String[] array = {"abc", "bcd", "bbcd"};
 64         Arrays.sort(array, newComparator());
 65         System.out.println(Arrays.toString(array));
 66     }
 67 
 68     //另外一种排序写法
 69     private void sortOrder() {
 70         ArrayList<String> list = new ArrayList<String>();
 71         list.add("cba");
 72         list.add("aba");
 73         list.add("sba");
 74         list.add("nba");
 75         //排序方法  按照第一个单词的降序
 76         Collections.sort(list, new Comparator<String>() {
 77             @Override
 78             public int compare(String o1, String o2) {
 79                 return o2.charAt(0) - o1.charAt(0);
 80             }
 81         });
 82     }
 83 
 84     /**
 85      * java.util.function.Supplier<T> 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对
 86      * 象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象
 87      * 数据。
 88      * 打印结果 Helloworld
 89      */
 90     @Test
 91     public void test05() {
 92         String msgA = "Hello";
 93         String msgB = "world";
 94         System.out.println(get(() -> msgA + msgB));
 95     }
 96 
 97     public static String get(Supplier<String> p) {
 98         return p.get();
 99     }
100 
101     //案例求最大值
102     @Test
103     public void test06() {
104         int[] array = {2, 183, 1, 9};
105         Integer max = getMax(() -> {
106             int num = array[0];
107             for (int i : array) {
108                 if (i > num)
109                     num = i;
110             }
111             return num;
112 
113         });
114         System.out.println(max);
115     }
116 
117     public static Integer getMax(Supplier<Integer> p) {
118         return p.get();
119     }
120 
121     /**
122      * java.util.function.Consumer<T> 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,
123      * 其数据类型由泛型决定。
124      */
125     @Test
126     public void test7() {
127         consumeStr(s -> System.out.println(s.toUpperCase()),
128                 s -> System.out.println(s.toLowerCase())
129         );
130     }
131 
132     public void consumeStr(Consumer<String> s, Consumer<String> b) {
133         s.andThen(b).accept("zhaNgSAN");
134     }
135 
136     //demo,打印数组
137     public static void printInfo(Consumer<String> a, Consumer<String> b, String[] arr) {
138         for (String info : arr) {
139             a.andThen(b).accept(info);
140         }
141     }
142 
143     @Test
144     public void test8() {
145         String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男"};
146         printInfo(s -> System.out.println(s.split(",")[0]),
147                 s -> System.out.println(s.split(",")[1]),
148                 array
149         );
150     }
151 
152     /**
153      * 有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用
154      * java.util.function.Predicate<T> 接口。
155      */
156     @Test
157     public void test9() {
158         demo9(s -> s.length() > 5);
159     }
160 
161     private void demo9(Predicate<String> p) {
162         boolean helloWorld = p.test("HelloWorld");
163         System.out.println(helloWorld);
164     }
165 
166     /**
167      * 既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实
168      * 现“并且”的效果时,可以使用default方法 and 。其JDK源码为:
169      */
170     @Test
171     public void test10() {
172         demo10(s -> s.contains("H"), d -> d.contains("D"));
173     }
174 
175     private void demo10(Predicate<String> p, Predicate<String> b) {
176         boolean helloWorld = p.and(b).test("HelloWorld");
177         System.out.println(helloWorld);
178     }
179 
180     /**
181      * 既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实
182      * 现“并且”的效果时,可以使用default方法 and 。其JDK源码为:
183      */
184     @Test
185     public void test11() {
186         demo11(a -> a.contains("H"),
187                 b -> b.contains("e")
188         );
189     }
190 
191     private void demo11(Predicate<String> p, Predicate<String> b) {
192         boolean helloWorld = p.or(b).or(b).test("HelloWorld");
193         System.out.println(helloWorld);
194     }
195 
196     /**
197      * 既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实
198      * 现“并且”的效果时,可以使用default方法 and 。其JDK源码为:
199      */
200     @Test
201     public void test12() {
202         demo12(a -> a.contains("b"),
203                 b -> b.length() > 11
204         );
205     }
206 
207     private void demo12(Predicate<String> p, Predicate<String> b) {
208         boolean helloWorld = p.negate().test("HelloWorld");
209         System.out.println(helloWorld);
210     }
211 
212     /**
213      * 既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实
214      * 现“并且”的效果时,可以使用default方法 and 。其JDK源码为:
215      */
216     @Test
217     public void test13() {
218         demo13(a -> a.contains("b"),
219                 b -> b.length() > 11
220         );
221     }
222 
223     private void demo13(Predicate<String> p, Predicate<String> b) {
224         boolean helloWorld = p.negate().test("HelloWorld");
225         System.out.println(helloWorld);
226     }
227 
228     /**
229      * 数组当中有多条“姓名+性别”的信息如下,请通过 Predicate 接口的拼装将符合要求的字符串筛选到集合
230      * ArrayList 中,需要同时满足两个条件:
231      * 1. 必须为女生;
232      * 2. 姓名为4个字。
233      */
234     @Test
235     public void test14() {
236         String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "杨颖,女", "杨幂,女"};
237         List list = demo14(array,
238                 s -> "女".equals(s.split(",")[1]),
239                 s -> s.split(",")[0].length() == 4
240         );
241         System.out.println(list);
242 
243     }
244 
245     private List demo14(String[] array, Predicate<String> p, Predicate<String> b) {
246         List data = new ArrayList<String>();
247         for (String s : array) {
248             if (p.and(b).test(s))
249                 data.add(s);
250         }
251         return data;
252     }
253 
254 
255     /**
256      * java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,
257      * 后者称为后置条件
258      */
259     @Test
260     public void test15() {
261         String b = "5";
262         demo15(b, s -> Integer.parseInt(s));
263 
264 
265     }
266 
267     private void demo15(String b, Function<String, Integer> f) {
268         Integer apply = f.apply(b);
269         System.out.println(apply + 10);
270 
271     }
272 
273     @Test
274     public void test16() {
275         String b = "5";
276         demo16(b,
277                 s -> Integer.parseInt(s),
278                 c -> c *= 10);
279 
280 
281     }
282 
283     private void demo16(String b, Function<String, Integer> f, Function<Integer, Integer> c) {
284         Integer apply = f.andThen(c).apply(b);
285         System.out.println(apply);
286 
287     }
288 
289     /**
290      * 请使用 Function 进行函数模型的拼接,按照顺序需要执行的多个函数操作为
291      * 1. 将字符串截取数字年龄部分,得到字符串;
292      * 2. 将上一步的字符串转换成为int类型的数字;
293      * 3. 将上一步的int数字累加100,得到结果int数字。
294      */
295     @Test
296     public void test17() {
297         String nameAge="赵丽颖,18";
298 
299         int age = demo17(nameAge, s -> s.split(",")[1],
300                 b -> Integer.parseInt(b),
301                 n -> n += 100
302         );
303         System.out.println(age);
304 
305     }
306     private int demo17(String b, Function<String, String> one, Function<String, Integer> two,Function<Integer, Integer> three) {
307         return one.andThen(two).andThen(three).apply(b);
308     }
309 
310 
311 
312 
313 }

 

posted on 2019-08-21 15:30  流世幻羽  阅读(217)  评论(0编辑  收藏  举报