Java8新特性
- Lambda運算式
- 入門演示
- 案例1
- 如何解決 cannot be cast to java.lang.Comparable問題?
- 案例2
- 優化方式一 : 策略設計模式
- 優化方式二: 策略設計模式+匿名內部實作介面,減少創建物體類的麻煩
- 優化方式三: lambda運算式
- 優化方式四: stream流
- Lambda語法
- 語法格式一 : 無引數,無回傳值
- 注意: 區域內部類與區域變數
- 語法格式二: 有一個引數,無回傳值
- 語法格式三: 如果一個引數,那么小括號可以不寫
- 語法格式四:有兩個引數,有回傳值,lambda體中有多條陳述句
- 語法格式五:若lambda體中只有一條陳述句,那么return和{}都可以省略不寫
- 語法格式六: lambda運算式的引數串列的資料型別可以省略不寫,因為JVM編譯器可以通過背景關系推斷出資料型別,即“型別推斷”
- Lambda需要函式式介面的支持
- 函式式介面: 介面中只有一個抽象方法的介面,稱為函式式介面,可以使用@FunctionalIterface修飾,檢查當前介面是否式函式式介面
- 我們可以通過lambda來實作函式式介面里面的唯一的抽象方法
- 舉例一
- 涉及知識點一: Interage.compareTo()
- 涉及知識點二: Collections工具類
- 內置四大核心函式式介面
- Consumer :消費型介面
- Supplier:供給型介面
- Function
Lambda運算式
? Lambda是一個匿名函式,可以理解為一段可以傳遞的代碼(將代碼像資料一樣傳遞);可以寫出更簡潔、更靈活的代碼;作為一種更緊湊的代碼風格,是Java語言表達能力得到提升
入門演示
案例1
public class TestMain
{
//使用匿名內部類完成比較
@Test
public void test()
{
//比較器 匿名內部類,創建該介面的一個實作類
Comparator<People> com=new Comparator<People>() {
@Override
public int compare(People o1, People o2) {
return o1.getAge()-o2.getAge();
}
};
//TreeSet的特點是可排序、不重復
TreeSet<People> ts=new TreeSet<>(com);
ts.add(new People("大忽悠",20));
ts.add(new People("小忽悠",18));
ts.add(new People("大大大",22));
ts.add(new People("小朋友",17));
ts.forEach(System.out::println);
}
//lambda運算式替代匿名內部類
@Test
public void test1()
{
//比較器
Comparator<People> com=(p1,p2)-> p1.getAge()-p2.getAge();
//TreeSet的特點是可排序、不重復
TreeSet<People> ts=new TreeSet<>(com);
ts.add(new People("大忽悠",20));
ts.add(new People("小忽悠",18));
ts.add(new People("大大大",22));
ts.add(new People("小朋友",17));
ts.forEach(System.out::println);
}
}

如何解決 cannot be cast to java.lang.Comparable問題?
如何解決 cannot be cast to java.lang.Comparable問題?
案例2
要求對下面的代碼進行優化:
public class TestMain
{
List<People> peopleList= Arrays.asList(
new People("1號",18,3000),
new People("2號",21,4000),
new People("3號",19,5000),
new People("4號",20,3500)
);
//獲取年齡大于18的
public List<People> getAgeOver18()
{
List<People> list=new ArrayList<>();
for (People p:peopleList)
{
if(p.getAge()>18)
list.add(p);
}
return list;
}
//獲取工資大于3000的
public List<People> getMoneyOver3000()
{
List<People> list=new ArrayList<>();
for (People p:peopleList)
{
if(p.getMoney()>3000)
list.add(p);
}
return list;
}
@Test
public void test()
{
List<People> ageOver18 = getAgeOver18();
ageOver18.forEach(System.out::println);
System.out.println("======================================");
List<People> moneyOver3000=getMoneyOver3000();
moneyOver3000.forEach(System.out::println);
}
}
優化方式一 : 策略設計模式
宣告一個介面MyPrediect
public interface MyPrediect<T>
{
public boolean test(T t);
}
介面的實作類一FilterPeoAge,負責過濾年齡:
public class FilterPeoAge implements MyPrediect<People>{
@Override
public boolean test(People people) {
return people.getAge()>18;
}
}
介面實作類二FilterPeoMoney,負責過濾金錢
public class FilterPeoMoney implements MyPrediect<People>{
@Override
public boolean test(People people) {
return people.getMoney()>3000;
}
}
測驗演示:
public class TestMain
{
List<People> peopleList= Arrays.asList(
new People("1號",18,3000),
new People("2號",21,4000),
new People("3號",19,5000),
new People("4號",20,3500)
);
public List<People> FilterPeo(List<People> list,MyPrediect<People> mp)
{
List<People> peopleList=new ArrayList<>();
for (People p:list)
{
if(mp.test(p))
peopleList.add(p);
}
return peopleList;
}
@Test
public void test()
{
List<People> peopleList = FilterPeo(this.peopleList, new FilterPeoAge());
peopleList.forEach(System.out::println);
System.out.println("===========================");
List<People> peopleList1 = FilterPeo(peopleList, new FilterPeoMoney());
peopleList1.forEach(System.out::println);
}
}

當我們還需要安裝某個策略進行過濾時,只需要實作介面,完成相應策略過濾邏輯撰寫即可
優化方式二: 策略設計模式+匿名內部實作介面,減少創建物體類的麻煩
public class TestMain
{
List<People> peopleList= Arrays.asList(
new People("1號",18,3000),
new People("2號",21,4000),
new People("3號",19,5000),
new People("4號",20,3500)
);
public List<People> FilterPeo(List<People> list,MyPrediect<People> mp)
{
List<People> peopleList=new ArrayList<>();
for (People p:list)
{
if(mp.test(p))
peopleList.add(p);
}
return peopleList;
}
@Test
public void test()
{
List<People> peopleList = FilterPeo(this.peopleList, new MyPrediect<People>() {
@Override
public boolean test(People people) {
return people.getAge()>18;
}
});
peopleList.forEach(System.out::println);
System.out.println("===========================");
List<People> peopleList1 = FilterPeo(peopleList, new MyPrediect<People>() {
@Override
public boolean test(People people) {
return people.getMoney()>3000;
}
});
peopleList1.forEach(System.out::println);
}
}

優化方式三: lambda運算式
public class TestMain
{
List<People> peopleList= Arrays.asList(
new People("1號",18,3000),
new People("2號",21,4000),
new People("3號",19,5000),
new People("4號",20,3500)
);
public List<People> FilterPeo(List<People> list,MyPrediect<People> mp)
{
List<People> peopleList=new ArrayList<>();
for (People p:list)
{
if(mp.test(p))
peopleList.add(p);
}
return peopleList;
}
@Test
public void test()
{
List<People> peopleList = FilterPeo(this.peopleList, (people)-> people.getMoney()>4000);
peopleList.forEach(System.out::println);
}
}

優化方式四: stream流
public class TestMain
{
List<People> peopleList= Arrays.asList(
new People("1號",18,3000),
new People("2號",21,4000),
new People("3號",19,5000),
new People("4號",20,3500)
);
public List<People> FilterPeo(List<People> list,MyPrediect<People> mp)
{
List<People> peopleList=new ArrayList<>();
for (People p:list)
{
if(mp.test(p))
peopleList.add(p);
}
return peopleList;
}
@Test
public void test()
{
peopleList.stream().filter(people -> people.getMoney()>3000).limit(2).forEach(System.out::println);
}
}

Lambda語法
- 運算子:->
- 左側:引數串列
- 右側:執行代碼塊 / Lambda 體

即lambda是對介面的抽象方法的實作,可能有人會問,如果介面中抽象方法存在多個,那lambda是對哪個抽象方法的實作呢?
其實lambda需要一個函式式介面的支持,即當前介面只有一個抽象方法
語法格式一 : 無引數,無回傳值
@Test
public void test()
{
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("方法執行中.....");
}
};
runnable.run();
System.out.println("----------------------");
Runnable r1=()-> System.out.println("r1執行中....");
r1.run();
}

注意: 區域內部類與區域變數
區域內部類在JDK8之前只能使用成員變數和被final修飾的區域變數,JDK8之后,區域內部類如果使用區域變數那么區域變數默認被final修飾,但如果區域變數被重新賦值,那么區域內部類將不能在使用,具體看下例子:
public void show() {
int j = 0; //jdk1.8后默認被final修飾,1.8之前區域內部類只能訪問成員變數,和被final修飾的區域變數
class A{
public void showA() {
System.out.println(i);
System.out.println(j);
}
}
// j = 2;//如果對區域變數做了修改,則默認會變成不被final修飾,區域內部類不可呼叫
}
//注:有靜態成員的一定是靜態內部類
lambda這里跟匿名內部類用法一致
語法格式二: 有一個引數,無回傳值
public class TestMain
{
@Test
public void test()
{
Consumer<String> consumer=(x)-> System.out.println(x);
// void accept(T t); 對該抽象方法進行實作
consumer.accept("大忽悠");
}
}

語法格式三: 如果一個引數,那么小括號可以不寫
Consumer<String> consumer=x-> System.out.println(x);
// void accept(T t); 對該抽象方法進行實作
consumer.accept("大忽悠");
語法格式四:有兩個引數,有回傳值,lambda體中有多條陳述句
public class TestMain
{
@Test
public void test()
{
// int compare(T o1, T o2);重寫該方法
Comparator<Integer> com=(x,y)->{
System.out.println("函式式介面");
return Integer.compare(x,y);
};
int compare = com.compare(1, 2);
System.out.println(compare);
}
}

語法格式五:若lambda體中只有一條陳述句,那么return和{}都可以省略不寫
public void test()
{
// int compare(T o1, T o2);重寫該方法
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
int compare = com.compare(1, 2);
System.out.println(compare);
}
語法格式六: lambda運算式的引數串列的資料型別可以省略不寫,因為JVM編譯器可以通過背景關系推斷出資料型別,即“型別推斷”
Lambda需要函式式介面的支持
函式式介面: 介面中只有一個抽象方法的介面,稱為函式式介面,可以使用@FunctionalIterface修飾,檢查當前介面是否式函式式介面
我們可以通過lambda來實作函式式介面里面的唯一的抽象方法
舉例一
public class TestMain
{
List<People> peopleList= Arrays.asList(
new People("1號",18,3000),
new People("2號",20,4000),
new People("3號",18,5000),
new People("4號",20,3500)
);
//先安裝年齡升序排序,年齡相同,再安裝money降序排序
@Test
void test()
{
//重寫下面這個方法,比較器可以為空
// public static <T> void sort(List<T> list, Comparator<? super T> c) {
// list.sort(c);
// }
Collections.sort(peopleList,(p1,p2)->{
if(p1.getAge()==p2.getAge())
return -p1.getMoney().compareTo(p2.getMoney());
else
return p1.getAge().compareTo(p2.getAge());
});
peopleList.forEach(System.out::println);
}
}

涉及知識點一: Interage.compareTo()
Integer obj2=100;
//比較大小
System.out.println(obj2.compareTo(100));
System.out.println(obj2.compareTo(102));
System.out.println(obj2.compareTo(10));
結果: 0 , -1 , 1 ,即大于回傳 1 ,小于回傳 -1 ,等于回傳 0
涉及知識點二: Collections工具類
詳細用法
內置四大核心函式式介面
Consumer<T> :消費型介面
void accept(T t);
Supplier<T>:供給型介面
T get(T t);
Function<T,R>:函式型介面
R apply(T t);
Predicate<T>:斷言型介面
boolean test(T t);
Consumer :消費型介面
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
測驗:
public class TestMain
{
@Test
void test()
{
//這里的lambda運算式實作了對應的抽象函式
happy(10000,(m)-> System.out.println("我有: "+m));
}
public void happy(Integer money,Consumer<Integer> com)
{
com.accept(money);
}
}

Supplier:供給型介面
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
測驗:
public class TestMain
{
@Test
void test()
{
List<String> numList=getNumList(5,()->UUID.randomUUID().toString().substring(0,8));
numList.forEach(System.out::println);
}
//需求: 產生指定個數的隨機id,并放入集合中
public List<String> getNumList(int num, Supplier<String> supplier)
{
ArrayList<String> integers = new ArrayList<String>();
for(int i=0;i<num;i++)
{
integers.add(supplier.get());
}
return integers;
}
}

Function<T,R>: 函式型介面
public interface Function<T, R>{
R apply(T t);
}
測驗:
public class TestMain
{
@Test
void test()
{
String str=StrHandler("\t\t\t 大忽悠 \t\t\t",(s)->s.trim());
System.out.println(str);
}
//需求: 處理字串
public String StrHandler(String str, Function<String,String> f)
{
return f.apply(str);//回傳被處理過后的字串
}
}

涉及知識點: trim()函式
trim()方法的使用
Predicate:斷言型介面
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
測驗:
public class TestMain
{
@Test
void test()
{
StrHandler("大忽悠啊",(str)->str.length()>3);
StrHandler("嘿嘿",(str)->str.length()>3);
}
//需求: 處理字串
public void StrHandler(String str, Predicate<String> predicate)
{
if(predicate.test(str))
System.out.println(str);
else
System.out.println("太短了");
}
}

其他常用函式式介面

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/293591.html
標籤:java
