函式式介面
- 函式式介面:有且僅有一個抽象方法的介面
- 函式式介面適用于Lambda運算式
- 只有確保介面中有且僅有一個抽象方法,Lambda才能順利推導
定義一個函式式介面
@FunctionalInterface //此注解表明是函式式介面
public interface MyInt {
void show();
}
測驗類
public class MyInterDemo {
public static void main(String[] args) {
/*函式式介面可以 用作引數傳遞,用作區域變數*/
//1.用作區域變數
MyInt mi = ()->{
System.out.println("函式式介面用作區域變數");
};
mi.show();
}
}
運行結果
函式式介面用作區域變數
注意
- 滿足函式式介面的情況下,@FunctionalInterface 可寫可不寫,建議寫上
- 標注@FunctionalInterface的情況下,如果是函式式介面,編譯通過;如果不是函式式介面,編譯不通過
函式式介面作為方法的引數
需求:定義一個類RunnableDemo,在里面提供兩個方法
一個方法是startThread(Runnable r),方法引數Runnable是一個函式式介面
在住方法中呼叫startThread方法
public class RunnableDemo {
public static void main(String[] args) {
//1.采用匿名內部類方式呼叫startThread方法
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "執行緒啟動了");
}
});
//2.采用Lambda運算式方式呼叫startThread方法
startThread(() -> System.out.println(Thread.currentThread().getName() + "執行緒啟動了"));
}
/**
* 函式式介面作為方法的引數
*
* @param r 函式式介面
*/
private static void startThread(Runnable r) {
new Thread(r).start();
}
}
運行結果
Thread-1執行緒啟動了
Thread-0執行緒啟動了
注意
- 如果方法的引數是一個函式式介面,可以使用Lambda運算式作為引數傳遞
函式式介面作為方法的回傳值
需求:定義一個類ComparatorDemo,在里面提供兩個方法
一個方法是Comparator< String> getComparator, 方法回傳值Comparator是一個函式式介面
在住方法中呼叫getComparator方法
public class ComparatorDemo {
public static void main(String[] args) {
//對字串長度進行排序
//1.定義集合,存盤字串元素
List<String> list = new ArrayList<>();
list.add("hello");
list.add("word");
list.add("javase");
System.out.println("排序前:" + list);
//2.排序
//自然排序
Collections.sort(list);
System.out.println("自然排序后:" + list);
//比較器排序
Collections.sort(list,getCompara());
System.out.println("比較器排序后:" + list);
}
/**
* 比較器排序
*
* @return
*/
private static Comparator<String> getCompara() {
//Lambda運算式方式,字串長度由小到大
return (s1, s2) -> s1.length() - s2.length();
}
}
運行結果
排序前:[hello, word, javase]
自然排序后:[hello, javase, word]
比較器排序后:[word, hello, javase]
注意
- 如果方法的回傳值是一個函式式介面,可以使用Lambda運算式作為結果回傳
常用函式式介面
Java8在Java.util.function包下提供了大量函式式介面
- Supplier
- Consumer
- Predicate
- Function
Supplier介面
Supplier < T >:包含一個無參的方法
- T get():獲得結果
- 該方法不需要引數,他會按照某種實作邏輯(Lambda運算式)回傳一個資料
- Supplier < T >被稱為生產型介面,如果我們指定了介面的泛型,那么get()就會生產什么樣的資料
案例1:
public class SupplierDemo {
public static void main(String[] args) {
//接受回傳的String型別的資料
//String s = getString(() -> {
// return "世界杯";
//});
String s = getString(() -> "世界杯");
Integer i = getInt(() -> 13);
//輸出資料
System.out.println(s);
System.out.println(i);
}
/**
* 回傳介面泛型型別的資料
*
* @param str
* @return
*/
private static String getString(Supplier<String> str) {
return str.get();
}
private static Integer getInt(Supplier<Integer> in) {
return in.get();
}
}
運行結果:
世界杯
13
案例2:
需求:定義一個類SupplierTest,里面有一個int getMax(Supplier< Integer> sup)用于回傳int陣列中的最大值
public class SupplierTest {
public static void main(String[] args) {
//定義int陣列
int[] arr = {5, 12, 65, 78, 22, 11};
//呼叫方法,并接識訓傳的資料
int maxValue = https://www.cnblogs.com/chawaner/p/getMax(() -> {
int max = arr[0];
//比較大小
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
});
//輸出資料
System.out.println(maxValue);
}
/**
* 回傳int陣列中的最大值
*
* @param sup
* @return
*/
private static int getMax(Supplier sup) {
return sup.get();
}
}
運行結果:
78
Consumer介面
Consumer< T>:包含兩個方法
- void accept(T t):對給定的引數執行此操作
- default Consumer< T> andThen(Consumer after):回傳一個組合的Consumer,依次執行此操作,然后執行afer操作
- Consumer< T>介面也被稱為消費型介面,消費的資料的型別由泛型決定
案例:
public class ConsumerDemo {
public static void main(String[] args) {
//消費一個字串資料, 輸出字串
opratorString("世界杯", s -> {
System.out.println(s);
});
opratorString("世界杯", s -> System.out.println(s));
opratorString("世界杯", System.out::println);
//對字串進行反轉,并輸出
opratorString("世界杯", s -> System.out.println(new StringBuilder(s).reverse().toString()));
System.out.println("------------------------");
//先輸出字串,然后輸出反轉后的字串
opratorString("世界杯", System.out::println,s -> System.out.println(new StringBuilder(s).reverse().toString()));
}
/**
* 定義一個方法,消費一個字串資料
*
* @param str
* @param con
*/
private static void opratorString(String str, Consumer<String> con) {
con.accept(str);
}
/**
* 方法多載
* 定義一個方法,用不同的方式,消費同一個字串資料兩次
*
* @param str
* @param con1
* @param con2
*/
private static void opratorString(String str, Consumer<String> con1, Consumer<String> con2) {
//con1.accept(str);
//con2.accept(str);
//上述代碼,可以替換成
con1.andThen(con2).accept(str);
}
}
運行結果:
世界杯
世界杯
世界杯
杯界世
------------------------
世界杯
杯界世
練習:
- String[] strArray = {"李信,30","蘇烈,32","白起,40"};
- 字串陣列有多條資訊,請按照格式:“姓名:XX,年齡:XX”的格式將資訊列印出來
- 要求:
-- 把列印姓名的動作作為第一個Consumer介面的Lambda實體
-- 把列印年齡的動作作為第二個Consumer介面的Lambda實體
-- 將兩個Consumer介面按照順序組合到一起使用
public class ConsumerTest {
public static void main(String[] args) {
//定義字串陣列
String[] strArray = {"李信,30", "蘇烈,32", "白起,23"};
//呼叫方法
/*printInfo(strArray, str -> {
String name = str.split(",")[0];
System.out.print("姓名:" + name);
},
str -> {
int age = Integer.parseInt(str.split(",")[1]);
System.out.println(",年齡:" + age);
}
);*/
//優化
printInfo(strArray, str -> System.out.print("姓名:" + str.split(",")[0]),
str -> System.out.println(",年齡:" + Integer.parseInt(str.split(",")[1]))
);
}
/**
* 遍歷字串陣列
*
* @param strArrary
* @param con1
* @param con2
*/
private static void printInfo(String[] strArrary, Consumer<String> con1, Consumer<String> con2) {
for (String s : strArrary) {
con1.andThen(con2).accept(s);
}
}
}
運行結果:
姓名:李信,年齡:30
姓名:蘇烈,年齡:32
姓名:白起,年齡:23
Predicate介面

案例:
public class PredicateDemo {
public static void main(String[] args) {
//判斷字串長度是否大于8
System.out.println(checkString("Hello", s -> s.length() > 8));
System.out.println(checkString("HelloJava", s -> s.length() > 8));
//字串長度是否大于8 跟 字串長度是否小于15 做與運算
System.out.println(checkString("hello", s -> s.length() > 8, s -> s.length() < 15));
System.out.println(checkString("helloJava", s -> s.length() > 8, s -> s.length() < 15));
//字串長度是否大于8 跟 字串長度是否小于15 做或運算
System.out.println(checkString1("hello", s -> s.length() > 8, s -> s.length() < 15));
System.out.println(checkString1("helloJava", s -> s.length() > 8, s -> s.length() < 15));
}
/**
* 判斷給定的字串是否滿足要求
*
* @param str
* @param pre
* @return
*/
private static boolean checkString(String str, Predicate<String> pre) {
return pre.test(str);
//negate()邏輯非判斷,即否定判斷
//return pre.negate().test(str);
}
/**
* 同一個字串給出兩個不同的判斷條件,回傳兩個條件的結果做邏輯與運算的結果
* @param str
* @param pre1
* @param pre2
* @return
*/
private static boolean checkString(String str, Predicate<String> pre1,Predicate<String> pre2){
//return pre1.test(str) && pre2.test(str);
return pre1.and(pre2).test(str);
}
/**
* 同一個字串給出兩個不同的判斷條件,回傳兩個條件的結果做邏輯或運算的結果
* @param str
* @param pre1
* @param pre2
* @return
*/
private static boolean checkString1(String str, Predicate<String> pre1,Predicate<String> pre2){
return pre1.or(pre2).test(str);
}
}
運行結果:
false
true
false
true
true
true
注意:加上negate()就是否定判斷,結果相反
練習:
- String[] strArray = {"劉亦菲,30","劉萱,34","李冰冰,35","大喬,31","孫尚香,33"};
- 字串陣列有多條資訊,請通過Predicate介面的拼裝,將符合要求的字串篩選到集合ArraryList集合中,并遍歷
- 同時滿足如下要求:姓名長度大于2,年齡大于33
- 分析:有兩個判斷條件,需要使用兩個Predicate介面,對條件進行判斷;必須同時滿足兩個條件,可以使用and方法連接兩個判斷條件
public class PredicateTest {
public static void main(String[] args) {
//定義字串陣列
String[] strArray = {"劉亦菲,30", "劉萱,34", "李冰冰,35", "大喬,31", "孫尚香,33"};
//獲取符合條件的元素,加入集合中
ArrayList<String> arr = check(strArray, s -> s.split(",")[0].length() > 2,
s -> Integer.parseInt(s.split(",")[1]) > 33);
//遍歷集合
for (String s : arr) {
System.out.println(s);
}
}
private static ArrayList<String> check(String[] strArray, Predicate<String> p1, Predicate<String> p2) {
//定義集合
ArrayList<String> list = new ArrayList<>();
//遍歷字串陣列
for (String s : strArray) {
//如果元素符合條件,就把元素添加到集合里
if (p1.and(p2).test(s)) {
list.add(s);
}
}
return list;
}
}
運行結果:
李冰冰,35
Function介面

案例:
public class FuctionDemo {
public static void main(String[] args) {
//字串轉int
convert("100", s -> Integer.parseInt(s));
//方法參考改進
convert("100", Integer::parseInt);
//int型別的資料加上一個數字,轉為字串輸出
convert(100, s -> String.valueOf(s + 566));
//字串轉int型別的資料,加上一個數字之后,轉為字串輸出
convert("100", Integer::parseInt, s -> String.valueOf(s + 788));
}
/**
* 字串轉int
*
* @param str
* @param fun
*/
private static void convert(String str, Function<String, Integer> fun) {
System.out.println(fun.apply(str));
}
/**
* int型別的資料做操作之后,轉為字串輸出
*
* @param i
* @param fun
*/
private static void convert(int i, Function<Integer, String> fun) {
System.out.println(fun.apply(i));
}
/**
* 字串轉int型別的資料,然后做操作之后,轉為字串輸出
*
* @param str
* @param f1
* @param f2
*/
private static void convert(String str, Function<String, Integer> f1, Function<Integer, String> f2) {
System.out.println(f1.andThen(f2).apply(str));
}
}
運行結果:
100
100
666
888
練習:按照指定要求操作資料
- String s = "劉亦菲,30";
- 請通過Function介面實作函式拼接
- 請按照指定的要求進行操作
- 1.截取字串,得到年齡
- 2.將截取到的年齡字串,轉為int型別的資料
- 3.將轉化后的int型別的資料,加70,得到新的int型別的資料,并輸出
public class FunctionTest {
public static void main(String[] args) {
String s = "劉亦菲,30";
operator(s, a -> a.split(",")[1], a -> Integer.parseInt(a), a -> a + 70);
operator(s, a -> a.split(",")[1], Integer::parseInt, i -> i + 70);
}
private static void operator(String str, Function<String, String> f1, Function<String, Integer> f2,
Function<Integer, Integer> f3) {
System.out.println(f1.andThen(f2).andThen(f3).apply(str));
}
}
運行結果:
100
100
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542823.html
標籤:Java
上一篇:函式式介面
下一篇:單調堆疊
