lambda表達式,又稱閉包(Closure)或稱匿名方法(anonymous method)。將Lambda表達式引入JAVA中的動機源於一個叫「行爲參數」的模式。這種模式可以解決需求變化帶來的問題,使代碼變得更加靈活。在JAVA8以前,參數模式十分囉嗦。Lambda表達式經過精簡的方式使用行爲模式克服了這個缺點java
代碼片斷
和代碼包裹
問題。減小重複思考和代碼
。都在java.util.function包裏在內部類中,this指向當前內部類對象本身,而在lambda表達式中,this指向的是表達式外部的類對象。編程
public class ScopeTest { @Test public void test_scope(){ Runnable runnable = () -> { this.print(); }; runnable.run(); } private void print(){ System.out.println("I can print"); } }
labmda表達式使用外部的變量時,不可修改,默認定義成final數組
只有一個抽象方法的接口咱們就稱之爲功能性接口,又簡稱 SAM 類型,即 Simple Abstract Method。會寫上註釋閉包
@FunctionalInterface //用這個註解來表示功能性接口 public interface Consumer<T> { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); }
常見的內置函數以下:app
name | function |
---|---|
java.lang.Runnable | 執行動做 |
java.util.function.Predicate <T> | 接收T對象並返回boolean |
java.util.function.Consumer<T> | 接收T對象,不返回值 |
java.util.function.Function<T,R> | 接收T對象,返回R對象 |
java.util.function.Supplier<T> | 提供T對象(例如工廠),不接收值 |
方法引用有不少種,它們的語法以下:函數式編程
@Test public void test_instance(){ Set<String> girls = new HashSet<>(); Set<String> names = new HashSet<>(); names.stream() //實例::methodName .filter(girls::contains) .collect(Collectors.toList()); } @Test public void test_this(){ Set<String> names = new HashSet<>(); names.stream() //this::methodName .filter(this::hasAuth) .collect(Collectors.toList()); } private boolean hasAuth(String authKey){ return true; }
Map<String,Person> map = new HashMap<>(); map.forEach((String name,Person person)->{ person.fly(); System.out.println(name+":"+person); }); map.forEach((name,person)->{ // 無須判斷類型,自動根據上下文推斷 person.fly(); System.out.println(name+":"+person); });
/** * 正常的代碼 */ @Test public void test_person(){ CnResult<Person> result = null; try { // 只有這裏取值是不一樣的,其餘的處理是同樣的,包括try,catch,打日誌,定義異常等 Person entity = this.getPerson(); result = CnResult.success(entity); }catch (CnException e){ logger.error(e.getMessage(),e); result = CnResult.error(e.getErrorCode(),e.getMessage()); } catch (Exception e) { logger.error(e.getMessage(),e); result = CnResult.error("1-1-1-1",e.getMessage()); } Assert.assertNotNull(result); } @Test public void test_animal(){ CnResult<Animal> result = null; try { // 只有這裏取值是不一樣的,其餘的處理是同樣的,包括try,catch,打日誌,定義異常等 Animal entity = this.getAnimal(); result = CnResult.success(entity); }catch (CnException e){ logger.error(e.getMessage(),e); result = CnResult.error(e.getErrorCode(),e.getMessage()); } catch (Exception e) { logger.error(e.getMessage(),e); result = CnResult.error("1-1-1-1",e.getMessage()); } Assert.assertNotNull(result); }
/** * lambda代碼 */ @Test public void test_lambda(){ //屏蔽全部細節,只把獲取對象的邏輯傳遞進去 CnResult<Person> person = WapperUtils.wapper(this::getPerson); Assert.assertNotNull(person); CnResult<Animal> animal = WapperUtils.wapper(this::getAnimal); Assert.assertNotNull(animal); } public class WapperUtils { private static final Logger logger = LoggerFactory.getLogger(WapperUtils.class); /** * 包裹 * * @param supplier * @param <T> * @return */ public static <T> CnResult<T> wapper(Supplier<T> supplier){ try { T entity = supplier.get(); CnResult<T> cnResult = CnResult.success(entity); return cnResult; }catch (CnException e){ logger.error(e.getMessage(),e); return CnResult.error(e.getErrorCode(),e.getMessage()); } catch (Exception e) { logger.error(e.getMessage(),e); return CnResult.error("1-1-1-1",e.getMessage()); } } }
@Test public void test_first() { List<Person> persons = new ArrayList<>(); persons.stream() /** * 沒有明確的語義。須要根據過程計算推理得出結果,也不清楚背後的業務和場景 * */ .filter(person -> person.getAge() >= 18) .collect(Collectors.toList()); } @Test public void test_second() { List<Person> persons = new ArrayList<>(); persons.stream() .filter(person -> { /** * 若是職責變動,得修改代碼結構,並且代碼愈來愈難理解 */ if (person.getAge() >= 18) { return true; } if (person.getName().startsWith("莊")) { return true; } return false; }) .collect(Collectors.toList()); } @Test public void test_third() { List<Person> persons = new ArrayList<>(); persons.stream() /** * 隨着業務變動須要不斷添加filter */ .filter(person -> person.getAge() >= 18) .filter(person -> person.getName().startsWith("莊")) .collect(Collectors.toList()); } @Test public void test_fourth() { List<Person> persons = new ArrayList<>(); persons.stream() /** * 隨着業務變動須要不斷添加filter */ .filter(Person::isAdult) .filter(Person::belongToZhuang) .collect(Collectors.toList()); } @Test public void test_final() { List<Person> persons = new ArrayList<>(); /** * 有明確的語義,不用再面向細節加工一下,並且也方便後面的擴展 */ persons.stream() .filter(Person::hasAuth) .collect(Collectors.toList()); }
@Test public void test_name_bad(){ List<Person> persons = new ArrayList<>(); /** * lambda一多的時候,沒有明確的參數,計算和理解起來很是吃力。 */ persons.stream() .filter(e->e.getAge()>18) .map(e->e.getName()) .filter(e->e.startsWith("莊")) .collect(Collectors.toList()); } @Test public void test_name(){ List<Person> persons = new ArrayList<>(); persons.stream() .filter(person->person.getAge()>18) .map(person->person.getName()) .filter(name->name.startsWith("莊")) .collect(Collectors.toList()); }
@Test public void test_bad() { List<Integer> values = new ArrayList<>(); int result = values.stream().mapToInt(e -> { int sum = 0; for (int i = 0; i < e; i++) { if (e % i == 0) { sum += i; } } return sum; }).sum(); System.out.println(result); } @Test public void test_() { List<Integer> values = new ArrayList<>(); int result = values.stream().mapToInt(this::toInt).sum(); System.out.println(result); } private Integer toInt(int e) { int sum = 0; for (int i = 0; i < e; i++) { if (e % i == 0) { sum += i; } } return sum; }
建議把多行lambda表達式主體轉移到一個命名函數中,而後使用方法引用函數