JDK8 新特性學習筆記

java8新特性學習

java8的特色

  1. 速度更快(修改了HasMap、HasSet、CurrentHasMap等存儲結構)
  2. 代碼更少(增長了新的語法Lambda表達式)
  3. 強大的Stream API
  4. 便於並行
  5. 最大化減小空指針異常

1.Lambda表達式

1.一、Lambda表達式是什麼?

Lambda是一個匿名函數,咱們能夠把Lambda表達式理解爲一段能夠傳遞的代碼(將代碼像數據同樣傳遞)。能夠寫出更簡潔、更靈活的代碼。做爲一種更緊湊的代碼風格,使Java的語言表達能力獲得了提高。java

1.二、Lambda表達式的基礎語法

Java8中引入了一個新的操做符「->」,該操做符稱爲箭頭操做符或者Lambda操做符,該操做符將Lambda表達式拆分紅兩個部分:api

左側:Lambda表達式的參數列表。數組

右側:Lambda表達式中須要執行的功能,即Lambda體。app

語法格式一:無參數,無返回值dom

() -> System.out.println("hello Lambda");
複製代碼

語法格式二:有一個參數,而且無返回值ide

(x) -> System.out.println(x);
複製代碼

語法格式三:若只有一個參數,小括號能夠省略不寫函數

x -> System.out.println(x);
複製代碼

語法格式四:有兩個以上的參數,有返回值,而且Lambda體中有多條語句學習

Comparator<Integer> com = (x,y) -> {
    System.out.println("函數式接口");
    return Integer.compare(x,y);
};
複製代碼

語法格式五:若Lambda體中只有一條語句,return和大括號均可以省略不寫this

Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
複製代碼

語法格式六:Lambda表達式的參數列表的數據類型能夠省略不寫,由於JVM編譯器經過上下文推斷出數據類型spa

(Integer x,Integer y) -> Integer.compare(x,y);
複製代碼

源代碼

package com.zgy.deom1;

import java.util.Comparator;
import java.util.function.Consumer;

import org.junit.jupiter.api.Test;

public class TestLambda2 {

	/* * Lambda基本語法:參數列表 -> 方法體 */
	
	/* * 語法格式一:無參數,無返回值 * () -> System.out.println("Hello World"); */
	@Test
	public void test1() {
		int num = 0; //jdk8中當匿名內部類中使用的變量,會自動隱式添加final關鍵字,匿名內部類中依然不能將變量進行加減操做。
		Runnable r = new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("hello world"+num);
			}
		};
		r.run();

		System.out.println("=============================");
		
		Runnable r1 = () -> System.out.println("hello lambda"+num);
		r1.run();
	}
	
	/* * 語法格式二:有一個參數,沒有返回值 */
	@Test
	public void test2() {
		Consumer<String> c = (x) -> System.out.println(x);
		c.accept(1+"");
		
		//Lambda表達式中若是參數只有一個,那麼括號能夠省略不寫
		Consumer<Object> c1 = x -> System.out.println("哈哈哈");
		c1.accept("ABC");
	}
	
	/* * 語法格式三:有兩個參數,有返回值,Lambda體中有多條語句 */
	@Test
	public void test3() {
		Comparator<Integer> com = (x,y) -> {
			System.out.println("好好學習,每天向上!");
			return x+y;
		};
		
		int result = com.compare(20, 30);
		System.out.println("result:"+result);
		
		//若是Lambda體中只有一條語句,能夠省略「{}」和return
		Comparator<Integer> c = (Integer x,Integer y) -> Integer.compare(x, y);
		int num = c.compare(30, 30);
		System.out.println("maxNub"+num);
		
		//因爲JVM的類型推斷,因此Lambda參數列表的數據類型,能夠省略不寫
		Comparator<Integer> c1 = (x,y) -> Integer.compare(x, y);
		int num1 = c1.compare(30, 31);
		System.out.println("maxNub"+num1);
	}
	
	/* * 調用自定的函數式接口 */
	@Test
	public void test4() {
		MyFun myFun = x -> x+100;
		int value = myFun.getValue(100);
		System.out.println("value:"+value);
	}
	
}
複製代碼
package com.zgy.deom1;

@FunctionalInterface
public interface MyFun {

	int getValue(int x);
}
複製代碼

練習代碼

package com.zgy.deom1;


import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Test;

public class TestLambda {

	
	List<Employee> emps = Arrays.asList(
			new Employee(101,"張三",18,9999.99),
			new Employee(102,"李四",59,6666.66),
			new Employee(103,"王五",28,3333.33),
			new Employee(104,"趙六",8,7777.77),
			new Employee(105,"田七",38,5555.55)
			);
	
	/* * 使用Collections對員工列表進行排序,按工資從多到少比 * 關於Collections.sort()自定義排序規則,兩個參數x和y,若是要按照升序,就是x在前面;相反若是要按照降序,就是y在前面。 */
	@Test
	public void test1() {
		
		Collections.sort(emps, (x,y) -> Double.compare(y.getSalary(), x.getSalary()));
		for (Employee employee : emps) {
			System.out.println(employee);
		}
	}
	
	/* * 定義一個函數式接口,傳如一個參數,返回該參數的大寫形式 */
	@Test
	public void test2() {
		
		String str = strHandler("zgy", x -> x.toUpperCase());
		System.out.println("str:"+str);
	}
	
	//小寫轉大寫的方法
	public String strHandler(String str,MyFunction mf) {
		return mf.getValue(str);
	}
	
	/* * 聲明一個帶兩個泛型的函數式接口,泛型類型爲<T,R> T爲參數,R爲返回值,接口中聲明對應的抽象方法 * 再使用接口做爲參數,計算兩個long型參數的和 * 再計算兩個long型參數的積 */
	@Test
	public void test3() {
		
		//計算和
		System.out.println(getValue(100L, 200L, (x,y) -> x+y));
		
		//計算積
		System.out.println(getValue(500L, 900L, (x,y) -> x*y));
	}
	
	public long getValue(Long x,Long y,MyFunction2<Long, Long> mf) {
		
		return mf.getValue(x, y);
	}
}
複製代碼
package com.zgy.deom1;

public class Employee {

	private int id;
	private String name;
	private int age;
	private double salary;
	
	public Employee() {}
	
	public Employee(int id, String name, int age, double salary) {
		super();
		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 + "]";
	}

	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;
	}
	
}
複製代碼
package com.zgy.deom1;

@FunctionalInterface
public interface MyFunction {

	public String getValue(String x);
}
複製代碼
package com.zgy.deom1;

@FunctionalInterface
public interface MyFunction2<T,R> {

	public R getValue(T t1, T t2);
}
複製代碼

1.三、函數式接口

函數式接口:接口中只有一個抽象方法的接口,稱爲函數式接口,可使用註解@FunctionalInterface修飾,該註解的做用是能夠檢查該接口是否爲函數式接口。

1.四、Java8內置四大核心函數式接口

Consumer:消費型接口

​ void accept(T t);

Supplier:供給型接口

​ T get();

Function<T, R>:函數型接口

​ R apply(T t);

Predicate:斷言型接口

​ boolean test(T t);

其它子接口以下圖

源代碼

package com.zgy.deom1;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;

/* * JDK8 內置四大核心函數式接口 */
public class TestLambda3 {

	/* * 消費式接口:傳一個參數,沒有返回值 * Consumer<T> void accept(T t); */
	@Test
	public void test1() {
		say("好好學習,每天向上!", x -> System.out.println(x+new Date()));
	}
	
	public void say(String str, Consumer<String> c) {
		c.accept(str);
	}
	
	/* * 供給式接口:沒有參數,返回一個結果 * Supplier<T> T get(); */
	@Test
	public void test2() {
		List<Integer> listResult = getNumberArr(() -> {
			List<Integer> list = new ArrayList<>();
			for(int i=0; i<10; i++) {				
				list.add(new Random().nextInt());
			}
			return list;
		});
		
		for (Integer integer : listResult) {
			System.out.println("DATA:"+integer);
		}
	}
	
	public List<Integer> getNumberArr(Supplier<List<Integer>> s){
		return s.get();
	} 
	
	/* * 函數式接口:傳入一個參數,返回一個結果 * Function<T,R> R apply(T t); */
	@Test
	public void test3() {
		System.out.println(apply("ZGY:", (x) -> x+new Date()));
	}
	
	public String apply(String a, Function<String, String> f) {
		return f.apply(a);
	};
	
	/* * 斷言型接口:傳入一個參數,返回一個布爾值 * Predicate<T> boolean test(T t); */
	@Test
	public void test4() {
		System.out.println(test(40, x -> x>0));
	}
	
	public String test(int x, Predicate<Integer> p) {
		if(p.test(x)) {
			return "大於0";
		}else {
			return "小於0";
		}
	}
}
複製代碼

1.五、方法引用與構造器引用

  1. 方法引用:若Lambda體中的內容有方法已經實現了,咱們可使用「方法引用」(能夠理解爲方法引用是Lambda表達式的另一種表現形式)

    主要有三種語法格式:

    1. 對象 :: 實例方法名
    2. 類 :: 靜態方法名
    3. 類 :: 實例方法名

    注意:

    1. Lambda體中調用方法的參數列表與返回值類型,要與函數式接口中抽象方法的函數列表和返回值類型保持一致。
    2. 若Lambda參數列表中的第一個參數是實例方法的調用者,第二個參數是實例方法的參數,能夠用使用ClassName :: method
  2. 構造器引用:

    格式:ClassName :: new

    注意:須要調用的構造器參數列表要與函數式接口中抽象方法的參數列表保持一致

  3. 數組引用:

    格式:Type :: new;

源代碼

package com.zgy.deom1;

import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;

public class TestMethodRef {

	/* * 方法引用和構造器引用 */
	
	@Test
	public void test1() {
		//對象 :: 實例方法名
		Consumer<String> c = System.out::println;
		c.accept("ZGY");
		
		Employee e = new Employee(111,"ZGY",22,1000);
		Supplier<String> s = e::getName;
		System.out.println(s.get());
	}
	
	@Test
	public void test2() {
		//類名::方法名
		Comparator<Integer> c = Integer::compare;
		System.out.println(c.compare(800, 210));
	}
	
	@Test
	public void test3() {
		//類名::實例方法名
		BiPredicate<String, String> bp = String::equals;
		System.out.println(bp.test("AAA", "AAA"));
	}
	
	@Test
	public void test4() {
		//構造器引用
		Supplier<Employee> e = Employee::new;
		Employee employee = e.get();
		employee.setName("ZGY");
		System.out.println(employee);
	}
}
複製代碼

二、Stream API

2.一、什麼是Stream

流(Stream)究竟是什麼?

流,是數據渠道,用於操做數據源(集合、數組等)所生成的元素序列。集合講的是數據,而流講的是計算!

注意:

  1. Stream本身不會存儲元素。
  2. Stream不會改變源對象,相反他們會返回一個持有結果的新Stream。
  3. Stream是延遲執行的,這意味着它們會等到須要結果的時候纔會執行。

2.二、Stream的操做三個步驟

  1. 建立Stream源碼

    package com.zgy.deom1;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Stream;
    
    import org.junit.jupiter.api.Test;
    
    /* * 建立Stream的幾種方式 */
    public class TestStreamAPI1 {
    
    	@Test
    	public void test1() {
    		//1.能夠經過Collection系列集合提供的stream()或parallelStream()
    		List<String> list = new ArrayList<>();
    		Stream<String> stream = list.stream();
    		
    		//2.經過Arrays中的靜態方法stream()獲取數組流
    		Employee[] employees = new Employee[10];
    		Stream<Employee> stream2 = Arrays.stream(employees);
    		
    		//3.經過Stream類中的靜態方法of()
    		Stream<String> stream3 = Stream.of("AA","BB","CC","DD");
    		
    		//4.經過迭代的方式建立無限流
    		Stream<Integer> stream4 = Stream.iterate(0, x -> x+2);
    		stream4.limit(5).forEach(System.out::println);
    		
    		//5.經過生成的方式建立無限流
    		Stream<Double> stream5 = Stream.generate(() -> Math.random());
    		//下面limit、forEach分別是
    		stream5.limit(20).forEach(System.out::println);
    	}
    }
    複製代碼
相關文章
相關標籤/搜索