1. 程式人生 > 實用技巧 >95.java基礎9(java8新特性)

95.java基礎9(java8新特性)

121.java 8新特性(lambda表示式):

package com.atguigu.java1;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Consumer;
/**
 * Lambda表示式的使用
 * 1.舉例: (o1,o2) -> Integer.compare(o1,o2);
 * 2.格式:
 *      -> :lambda操作符 或 箭頭操作符
 *      ->左邊:lambda形參列表 (其實就是介面中的抽象方法的形參列表)
 *      ->右邊:lambda體 (其實就是重寫的抽象方法的方法體)
 * 3. Lambda表示式的使用:(分為6種情況介紹)
 *    總結:
 *    ->左邊:lambda形參列表的引數型別可以省略(型別推斷);如果lambda形參列表只有一個引數,其一對()也可以省略
 *    ->右邊:lambda體應該使用一對{}包裹;如果lambda體只有一條執行語句(可能是return語句),省略這一對{}和return關鍵字
 * 4.Lambda表示式的本質:作為函式式介面的例項
 * 5. 如果一個介面中,只聲明瞭一個抽象方法,則此介面就稱為函式式介面。我們可以在一個介面上使用 @FunctionalInterface 註解,
 *   這樣做可以檢查它是否是一個函式式介面。
 * 6. 所以以前用匿名實現類表示的現在都可以用Lambda表示式來寫。
 * @author shkstart
 * @create 2019 上午 11:40
 */
public class LambdaTest1 {
    //語法格式一:無參,無返回值
    @Test
    public void test1(){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("我愛北京天安門");
            }
        };
        r1.run();
        System.out.println("***********************");
        Runnable r2 = () -> {
            System.out.println("我愛北京故宮");
        };
        r2.run();
    }
    //語法格式二:Lambda 需要一個引數,但是沒有返回值。
    @Test
    public void test2(){
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("謊言和誓言的區別是什麼?");
        System.out.println("*******************");
        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("一個是聽得人當真了,一個是說的人當真了");
    }
    //語法格式三:資料型別可以省略,因為可由編譯器推斷得出,稱為“型別推斷”
    @Test
    public void test3(){
        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("一個是聽得人當真了,一個是說的人當真了");
        System.out.println("*******************");
        Consumer<String> con2 = (s) -> {
            System.out.println(s);
        };
        con2.accept("一個是聽得人當真了,一個是說的人當真了");
    }
    @Test
    public void test4(){
        ArrayList<String> list = new ArrayList<>();//型別推斷
        int[] arr = {1,2,3};//型別推斷
    }
    //語法格式四:Lambda 若只需要一個引數時,引數的小括號可以省略
    @Test
    public void test5(){
        Consumer<String> con1 = (s) -> {
            System.out.println(s);
        };
        con1.accept("一個是聽得人當真了,一個是說的人當真了");
        System.out.println("*******************");
        Consumer<String> con2 = s -> {
            System.out.println(s);
        };
        con2.accept("一個是聽得人當真了,一個是說的人當真了");
    }
    //語法格式五:Lambda 需要兩個或以上的引數,多條執行語句,並且可以有返回值
    @Test
    public void test6(){
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare(12,21));
        System.out.println("*****************************");
        Comparator<Integer> com2 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(com2.compare(12,6));
    }
    //語法格式六:當 Lambda 體只有一條語句時,return 與大括號若有,都可以省略
    @Test
    public void test7(){
        Comparator<Integer> com1 = (o1,o2) -> {
            return o1.compareTo(o2);
        };
        System.out.println(com1.compare(12,6));
        System.out.println("*****************************");
        Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);
        System.out.println(com2.compare(12,21));
    }
    @Test
    public void test8(){
        Consumer<String> con1 = s -> {
            System.out.println(s);
        };
        con1.accept("一個是聽得人當真了,一個是說的人當真了");
        System.out.println("*****************************");
        Consumer<String> con2 = s -> System.out.println(s);
        con2.accept("一個是聽得人當真了,一個是說的人當真了");
    }
}

122.java 8新特性(四大函式式介面):

package com.atguigu.java1;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
 * java內建的4大核心函式式介面
 * 消費型介面 Consumer<T>     void accept(T t)
 * 供給型介面 Supplier<T>     T get()
 * 函式型介面 Function<T,R>   R apply(T t)
 * 斷定型介面 Predicate<T>    boolean test(T t)
 * @author shkstart
 * @create 2019 下午 2:29
 */
public class LambdaTest2 {
    @Test
    public void test1(){
        happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("學習太累了,去天上人間買了瓶礦泉水,價格為:" + aDouble);
            }
        });
        System.out.println("********************");
        happyTime(400,money -> System.out.println("學習太累了,去天上人間喝了口水,價格為:" + money));
    }
    public void happyTime(double money, Consumer<Double> con){
        con.accept(money);
    }
    @Test
    public void test2(){
        List<String> list = Arrays.asList("北京","南京","天津","東京","西京","普京");
        List<String> filterStrs = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("京");
            }
        });
        System.out.println(filterStrs);
        List<String> filterStrs1 = filterString(list,s -> s.contains("京"));
        System.out.println(filterStrs1);
    }
    //根據給定的規則,過濾集合中的字串。此規則由Predicate的方法決定
    public List<String> filterString(List<String> list, Predicate<String> pre){
        ArrayList<String> filterList = new ArrayList<>();
        for(String s : list){
            if(pre.test(s)){
                filterList.add(s);
            }
        }
        return filterList;
    }
}

123.java 8新特性(方法,構造器,屬組引用):

//方法引用
package com.atguigu.java2;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
 * 方法引用的使用
 * 1.使用情境:當要傳遞給Lambda體的操作,已經有實現的方法了,可以使用方法引用!
 * 2.方法引用,本質上就是Lambda表示式,而Lambda表示式作為函式式介面的例項。所以
 *   方法引用,也是函式式介面的例項。
 * 3. 使用格式:  類(或物件) :: 方法名
 * 4. 具體分為如下的三種情況:
 *    情況1     物件 :: 非靜態方法
 *    情況2     類 :: 靜態方法
 *    情況3     類 :: 非靜態方法
 * 5. 方法引用使用的要求:要求介面中的抽象方法的形參列表和返回值型別與方法引用的方法的
 *    形參列表和返回值型別相同!(針對於情況1和情況2)
 * Created by shkstart.
 */
public class MethodRefTest {
	// 情況一:物件 :: 例項方法
	//Consumer中的void accept(T t)
	//PrintStream中的void println(T t)
	@Test
	public void test1() {
		Consumer<String> con1 = str -> System.out.println(str);
		con1.accept("北京");
		System.out.println("*******************");
		PrintStream ps = System.out;
		Consumer<String> con2 = ps::println;
		con2.accept("beijing");
	}
	//Supplier中的T get()
	//Employee中的String getName()
	@Test
	public void test2() {
		Employee emp = new Employee(1001,"Tom",23,5600);
		Supplier<String> sup1 = () -> emp.getName();
		System.out.println(sup1.get());
		System.out.println("*******************");
		Supplier<String> sup2 = emp::getName;
		System.out.println(sup2.get());
	}
	// 情況二:類 :: 靜態方法
	//Comparator中的int compare(T t1,T t2)
	//Integer中的int compare(T t1,T t2)
	@Test
	public void test3() {
		Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
		System.out.println(com1.compare(12,21));
		System.out.println("*******************");
		Comparator<Integer> com2 = Integer::compare;
		System.out.println(com2.compare(12,3));
	}
	//Function中的R apply(T t)
	//Math中的Long round(Double d)
	@Test
	public void test4() {
		Function<Double,Long> func = new Function<Double, Long>() {
			@Override
			public Long apply(Double d) {
				return Math.round(d);
			}
		};
		System.out.println("*******************");
		Function<Double,Long> func1 = d -> Math.round(d);
		System.out.println(func1.apply(12.3));
		System.out.println("*******************");
		Function<Double,Long> func2 = Math::round;
		System.out.println(func2.apply(12.6));
	}
	// 情況三:類 :: 例項方法  (有難度)
	// Comparator中的int comapre(T t1,T t2)
	// String中的int t1.compareTo(t2)
	@Test
	public void test5() {
		Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
		System.out.println(com1.compare("abc","abd"));
		System.out.println("*******************");
		Comparator<String> com2 = String :: compareTo;
		System.out.println(com2.compare("abd","abm"));
	}
	//BiPredicate中的boolean test(T t1, T t2);
	//String中的boolean t1.equals(t2)
	@Test
	public void test6() {
		BiPredicate<String,String> pre1 = (s1,s2) -> s1.equals(s2);
		System.out.println(pre1.test("abc","abc"));
		System.out.println("*******************");
		BiPredicate<String,String> pre2 = String :: equals;
		System.out.println(pre2.test("abc","abd"));
	}
	// Function中的R apply(T t)
	// Employee中的String getName();
	@Test
	public void test7() {
		Employee employee = new Employee(1001, "Jerry", 23, 6000);
		Function<Employee,String> func1 = e -> e.getName();
		System.out.println(func1.apply(employee));
		System.out.println("*******************");
		Function<Employee,String> func2 = Employee::getName;
		System.out.println(func2.apply(employee));
	}
}
--------------------------------------------------------------------
package com.atguigu.java2;
/**
 * @author shkstart 郵箱:[email protected]
 */
public class Employee {
	private int id;
	private String name;
	private int age;
	private double salary;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	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 double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public Employee() {
		System.out.println("Employee().....");
	}
	public Employee(int id) {
		this.id = id;
		System.out.println("Employee(int id).....");
	}
	public Employee(int id, String name) {
		this.id = id;
		this.name = name;
	}
	public Employee(int id, String name, int age, double salary) {
		this.id = id;
		this.name = name;
		this.age = age;
		this.salary = salary;
	}
	@Override
	public String toString() {
		return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}';
	}
	@Override
	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (o == null || getClass() != o.getClass())
			return false;
		Employee employee = (Employee) o;
		if (id != employee.id)
			return false;
		if (age != employee.age)
			return false;
		if (Double.compare(employee.salary, salary) != 0)
			return false;
		return name != null ? name.equals(employee.name) : employee.name == null;
	}
	@Override
	public int hashCode() {
		int result;
		long temp;
		result = id;
		result = 31 * result + (name != null ? name.hashCode() : 0);
		result = 31 * result + age;
		temp = Double.doubleToLongBits(salary);
		result = 31 * result + (int) (temp ^ (temp >>> 32));
		return result;
	}
}
------------------------------------------------------------------------------
package com.atguigu.java2;
import java.util.ArrayList;
import java.util.List;
/**
 * 提供用於測試的資料
 * @author shkstart 郵箱:[email protected]
 */
public class EmployeeData {
	public static List<Employee> getEmployees(){
		List<Employee> list = new ArrayList<>();
		list.add(new Employee(1001, "馬化騰", 34, 6000.38));
		list.add(new Employee(1002, "馬雲", 12, 9876.12));
		list.add(new Employee(1003, "劉強東", 33, 3000.82));
		list.add(new Employee(1004, "雷軍", 26, 7657.37));
		list.add(new Employee(1005, "李彥巨集", 65, 5555.32));
		list.add(new Employee(1006, "比爾蓋茨", 42, 9500.43));
		list.add(new Employee(1007, "任正非", 26, 4333.32));
		list.add(new Employee(1008, "扎克伯格", 35, 2500.32));
		return list;
	}
}
//構造器和屬組引用
package com.atguigu.java2;
import org.junit.Test;
import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
/**
 * 一、構造器引用
 *      和方法引用類似,函式式介面的抽象方法的形參列表和構造器的形參列表一致。
 *      抽象方法的返回值型別即為構造器所屬的類的型別
 * 二、陣列引用
 *     大家可以把陣列看做是一個特殊的類,則寫法與構造器引用一致。
 * Created by shkstart
 */
public class ConstructorRefTest {
	//構造器引用
    //Supplier中的T get()
    //Employee的空參構造器:Employee()
    @Test
    public void test1(){
        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println("*******************");
        Supplier<Employee>  sup1 = () -> new Employee();
        System.out.println(sup1.get());
        System.out.println("*******************");
        Supplier<Employee>  sup2 = Employee :: new;
        System.out.println(sup2.get());
    }
	//Function中的R apply(T t)
    @Test
    public void test2(){
        Function<Integer,Employee> func1 = id -> new Employee(id);
        Employee employee = func1.apply(1001);
        System.out.println(employee);
        System.out.println("*******************");
        Function<Integer,Employee> func2 = Employee :: new;
        Employee employee1 = func2.apply(1002);
        System.out.println(employee1);
    }
	//BiFunction中的R apply(T t,U u)
    @Test
    public void test3(){
        BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);
        System.out.println(func1.apply(1001,"Tom"));
        System.out.println("*******************");
        BiFunction<Integer,String,Employee> func2 = Employee :: new;
        System.out.println(func2.apply(1002,"Tom"));
    }
	//陣列引用
    //Function中的R apply(T t)
    @Test
    public void test4(){
        Function<Integer,String[]> func1 = length -> new String[length];
        String[] arr1 = func1.apply(5);
        System.out.println(Arrays.toString(arr1));
        System.out.println("*******************");
        Function<Integer,String[]> func2 = String[] :: new;
        String[] arr2 = func2.apply(10);
        System.out.println(Arrays.toString(arr2));
    }
}

124.java 8 新特性(Stream API):

-------------------------------初始操作---------------------------------------------------
package com.atguigu.java3;
import com.atguigu.java2.Employee;
import com.atguigu.java2.EmployeeData;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
 * 1. Stream關注的是對資料的運算,與CPU打交道
 *    集合關注的是資料的儲存,與記憶體打交道
 * 2.
 * ①Stream 自己不會儲存元素。
 * ②Stream 不會改變源物件。相反,他們會返回一個持有結果的新Stream。
 * ③Stream 操作是延遲執行的。這意味著他們會等到需要結果的時候才執行
 * 3.Stream 執行流程
 * ① Stream的例項化
 * ② 一系列的中間操作(過濾、對映、...)
 * ③ 終止操作
 * 4.說明:
 * 4.1 一箇中間操作鏈,對資料來源的資料進行處理
 * 4.2 一旦執行終止操作,就執行中間操作鏈,併產生結果。之後,不會再被使用
 *  測試Stream的例項化
 * @author shkstart
 * @create 2019 下午 4:25
 */
public class StreamAPITest {
    //建立 Stream方式一:通過集合
    @Test
    public void test1(){
        List<Employee> employees = EmployeeData.getEmployees();
//        default Stream<E> stream() : 返回一個順序流
        Stream<Employee> stream = employees.stream();
//        default Stream<E> parallelStream() : 返回一個並行流
        Stream<Employee> parallelStream = employees.parallelStream();
    }
    //建立 Stream方式二:通過陣列
    @Test
    public void test2(){
        int[] arr = new int[]{1,2,3,4,5,6};
        //呼叫Arrays類的static <T> Stream<T> stream(T[] array): 返回一個流
        IntStream stream = Arrays.stream(arr);
        Employee e1 = new Employee(1001,"Tom");
        Employee e2 = new Employee(1002,"Jerry");
        Employee[] arr1 = new Employee[]{e1,e2};
        Stream<Employee> stream1 = Arrays.stream(arr1);
    }
    //建立 Stream方式三:通過Stream的of()
    @Test
    public void test3(){
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
    }
    //建立 Stream方式四:建立無限流
    @Test
    public void test4(){
//      迭代
//      public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        //遍歷前10個偶數
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
//      生成
//      public static<T> Stream<T> generate(Supplier<T> s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }
}
-------------------------------中間操作---------------------------------------------------
package com.atguigu.java3;
import com.atguigu.java2.Employee;
import com.atguigu.java2.EmployeeData;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
 * 測試Stream的中間操作
 * @author shkstart
 * @create 2019 下午 4:42
 */
public class StreamAPITest1 {
    //1-篩選與切片
    @Test
    public void test1(){
        List<Employee> list = EmployeeData.getEmployees();
//        filter(Predicate p)——接收 Lambda , 從流中排除某些元素。
        Stream<Employee> stream = list.stream();
        //練習:查詢員工表中薪資大於7000的員工資訊
        stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);
        System.out.println();
//        limit(n)——截斷流,使其元素不超過給定數量。
        list.stream().limit(3).forEach(System.out::println);
        System.out.println();
//        skip(n) —— 跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit(n) 互補
        list.stream().skip(3).forEach(System.out::println);
        System.out.println();
//        distinct()——篩選,通過流所生成元素的 hashCode() 和 equals() 去除重複元素
        list.add(new Employee(1010,"劉強東",40,8000));
        list.add(new Employee(1010,"劉強東",41,8000));
        list.add(new Employee(1010,"劉強東",40,8000));
        list.add(new Employee(1010,"劉強東",40,8000));
        list.add(new Employee(1010,"劉強東",40,8000));
//        System.out.println(list);
        list.stream().distinct().forEach(System.out::println);
    }
    //對映
    @Test
    public void test2(){
//        map(Function f)——接收一個函式作為引數,將元素轉換成其他形式或提取資訊,該函式會被應用到每個元素上,並將其對映成一個新的元素。
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
//        練習1:獲取員工姓名長度大於3的員工的姓名。
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<String> namesStream = employees.stream().map(Employee::getName);
        namesStream.filter(name -> name.length() > 3).forEach(System.out::println);
        System.out.println();
        //練習2:
        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
        streamStream.forEach(s ->{
            s.forEach(System.out::println);
        });
        System.out.println();
//        flatMap(Function f)——接收一個函式作為引數,將流中的每個值都換成另一個流,然後把所有流連線成一個流。
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out::println);
    }
    //將字串中的多個字元構成的集合轉換為對應的Stream的例項
    public static Stream<Character> fromStringToStream(String str){//aa
        ArrayList<Character> list = new ArrayList<>();
        for(Character c : str.toCharArray()){
            list.add(c);
        }
       return list.stream();
    }
    @Test
    public void test3(){
        ArrayList list1 = new ArrayList();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        ArrayList list2 = new ArrayList();
        list2.add(4);
        list2.add(5);
        list2.add(6);
//        list1.add(list2);
        list1.addAll(list2);
        System.out.println(list1);
    }
    //3-排序
    @Test
    public void test4(){
//        sorted()——自然排序
        List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
        list.stream().sorted().forEach(System.out::println);
        //拋異常,原因:Employee沒有實現Comparable介面
//        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted().forEach(System.out::println);
//        sorted(Comparator com)——定製排序
        List<Employee> employees = EmployeeData.getEmployees();
        employees.stream().sorted( (e1,e2) -> {
           int ageValue = Integer.compare(e1.getAge(),e2.getAge());
           if(ageValue != 0){
               return ageValue;
           }else{
               return -Double.compare(e1.getSalary(),e2.getSalary());
           }
        }).forEach(System.out::println);
    }
}
-------------------------------終止操作---------------------------------------------------
package com.atguigu.java3;
import com.atguigu.java2.Employee;
import com.atguigu.java2.EmployeeData;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
 * 測試Stream的終止操作
 * @author shkstart
 * @create 2019 下午 6:37
 */
public class StreamAPITest2 {
    //1-匹配與查詢
    @Test
    public void test1(){
        List<Employee> employees = EmployeeData.getEmployees();
//        allMatch(Predicate p)——檢查是否匹配所有元素。
//          練習:是否所有的員工的年齡都大於18
        boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
        System.out.println(allMatch);
//        anyMatch(Predicate p)——檢查是否至少匹配一個元素。
//         練習:是否存在員工的工資大於 10000
        boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000);
        System.out.println(anyMatch);
//        noneMatch(Predicate p)——檢查是否沒有匹配的元素。
//          練習:是否存在員工姓“雷”
        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
        System.out.println(noneMatch);
//        findFirst——返回第一個元素
        Optional<Employee> employee = employees.stream().findFirst();
        System.out.println(employee);
//        findAny——返回當前流中的任意元素
        Optional<Employee> employee1 = employees.parallelStream().findAny();
        System.out.println(employee1);
    }
    @Test
    public void test2(){
        List<Employee> employees = EmployeeData.getEmployees();
        // count——返回流中元素的總個數
        long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
        System.out.println(count);
//        max(Comparator c)——返回流中最大值
//        練習:返回最高的工資:
        Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());
        Optional<Double> maxSalary = salaryStream.max(Double::compare);
        System.out.println(maxSalary);
//        min(Comparator c)——返回流中最小值
//        練習:返回最低工資的員工
        Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(employee);
        System.out.println();
//        forEach(Consumer c)——內部迭代
        employees.stream().forEach(System.out::println);
        //使用集合的遍歷操作
        employees.forEach(System.out::println);
    }
    //2-歸約
    @Test
    public void test3(){
//        reduce(T identity, BinaryOperator)——可以將流中元素反覆結合起來,得到一個值。返回 T
//        練習1:計算1-10的自然數的和
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);
//        reduce(BinaryOperator) ——可以將流中元素反覆結合起來,得到一個值。返回 Optional<T>
//        練習2:計算公司所有員工工資的總和
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
//        Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
        Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
        System.out.println(sumMoney.get());
    }
    //3-收集
    @Test
    public void test4(){
//        collect(Collector c)——將流轉換為其他形式。接收一個 Collector介面的實現,用於給Stream中元素做彙總的方法
//        練習1:查詢工資大於6000的員工,結果返回為一個List或Set
        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
        employeeList.forEach(System.out::println);
        System.out.println();
        Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
        employeeSet.forEach(System.out::println);
    }
}

125.java 8 新特性(Optional):

--------------------------------------------------------------------------------
package com.atguigu.java4;
/**
 * @author shkstart
 * @create 2019 下午 7:22
 */
public class Boy {
    private Girl girl;
    @Override
    public String toString() {
        return "Boy{" +
                "girl=" + girl +
                '}';
    }
    public Girl getGirl() {
        return girl;
    }
    public void setGirl(Girl girl) {
        this.girl = girl;
    }
    public Boy() {
    }
    public Boy(Girl girl) {
        this.girl = girl;
    }
}
--------------------------------------------------------------------------------
package com.atguigu.java4;
/**
 * @author shkstart
 * @create 2019 下午 7:23
 */
public class Girl {
    private String name;
    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Girl() {
    }
    public Girl(String name) {
        this.name = name;
    }
}
--------------------------------------------------------------------------------
package com.atguigu.java4;
import org.junit.Test;
import java.util.Optional;
/**
 * Optional類:為了在程式中避免出現空指標異常而建立的。
 * 常用的方法:ofNullable(T t)
 *            orElse(T t)
 * @author shkstart
 * @create 2019 下午 7:24
 */
public class OptionalTest {
/*
Optional.of(T t) : 建立一個 Optional 例項,t必須非空;
Optional.empty() : 建立一個空的 Optional 例項
Optional.ofNullable(T t):t可以為null
 */
    @Test
    public void test1(){
        Girl girl = new Girl();
//        girl = null;
        //of(T t):保證t是非空的
        Optional<Girl> optionalGirl = Optional.of(girl);
    }
    @Test
    public void test2(){
        Girl girl = new Girl();
//        girl = null;
        //ofNullable(T t):t可以為null
        Optional<Girl> optionalGirl = Optional.ofNullable(girl);
        System.out.println(optionalGirl);
        //orElse(T t1):如果單前的Optional內部封裝的t是非空的,則返回內傳入的t.
        //如果內部的t是空的,則返回orElse()方法中的預設引數t1.
        Girl girl1 = optionalGirl.orElse(new Girl("趙麗穎"));
        System.out.println(girl1);
    }
    public String getGirlName(Boy boy){
        return boy.getGirl().getName();
    }
    @Test
    public void test3(){
        Boy boy = new Boy();
        boy = null;
        String girlName = getGirlName(boy);
        System.out.println(girlName);
    }
    //優化以後的getGirlName():
    public String getGirlName1(Boy boy){
        if(boy != null){
            Girl girl = boy.getGirl();
            if(girl != null){
                return girl.getName();
            }
        }
        return null;
    }
    @Test
    public void test4(){
        Boy boy = new Boy();
        boy = null;
        String girlName = getGirlName1(boy);
        System.out.println(girlName);
    }
    //使用Optional類的getGirlName():
    public String getGirlName2(Boy boy){
        Optional<Boy> boyOptional = Optional.ofNullable(boy);
        //此時的boy1一定非空
        Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪麗熱巴")));
        Girl girl = boy1.getGirl();
        System.out.println(girl);
        Optional<Girl> girlOptional = Optional.ofNullable(girl);
        //girl1一定非空
        Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
        return girl1.getName();
    }
    @Test
    public void test5(){
        Boy boy = null;
//        boy = new Boy();
//        boy = new Boy(new Girl("蒼老師"));
        String girlName = getGirlName2(boy);
        System.out.println(girlName);
    }
}