java8的lambda表達式和stream


java的lambda表達式和stream

1. Lambda表達式

java 8引入了Lambda表達式, 用以簡化單抽象方法接口的實現

參數類型不需要申明, 參數類型自動推斷

單抽象方法接口被稱為函數式接口,標注為@FunctionalInterface

  • java的單方法接口:
    • Comparator
    • Runnable
    • Callable

例子:

import java.util.Arrays;
import java.util.Comparator;

public class LambdaSample {

    public static void main(String[] args) throws Exception {
        String[] words = "Improving code with Lambda expressions in Java".split(" ");
//        Arrays.sort(words, new Comparator<String>() {
//            @Override
//            public int compare(String s1, String s2) {
//                // 忽略大小寫排序:
//                return s1.toLowerCase().compareTo(s2.toLowerCase());
//            }
//        });
        Arrays.sort(words, (s1, s2) -> {
            return s1.toLowerCase().compareTo(s2.toLowerCase());
        });
        System.out.println(Arrays.toString(words));
    }
}

s1, s2: 傳入的參數

->{}: 方法過程

Runnable() 練習:

public class LambdaPractice {

    public static void main(String[] args) throws Exception {
        // TODO: 將Runnable改為lambda表達式:
//        Thread t = new Thread(new Runnable() {
//            @Override
//            public void run() {
//                System.out.println("start new thread...");
//            }
//        });
//        t.start();
//        t.join();
        Thread t = new Thread(() -> {
            System.out.println("start new thread");
        });
        t.start();
        t.join();
    }
}

2. 方法引入(java8中的:😃

jdk8中使用了::的用法。就是把方法當做參數傳到stream內部,使stream的每個元素都傳入到該方法里面執行一下,雙冒號運算就是Java中的[方法引用],[方法引用]的格式是:

  類名::方法名 

注意此處沒有()。

代碼示例:

import java.util.Arrays;

class SortedBy {
	static int name(String s1, String s2) {
		return s1.compareTo(s2);
	}

	static int nameIgnoreCase(String s1, String s2) {
		return s1.toLowerCase().compareTo(s2.toLowerCase());
	}

	static int length(String s1, String s2) {
		int n1 = s1.length();
		int n2 = s2.length();
		if (n1 == n2) {
			return s1.compareTo(s2);
		}
		return n1 < n2 ? -1 : 1;
	}
}

public class LambdaSort {

	public static void main(String[] args) throws Exception {
		String[] array = "Java Apple lambda functional OOP".split(" ");
		Arrays.sort(array, SortedBy::name);
		System.out.println(Arrays.toString(array));
	}
}

  • 匿名類

匿名類,就是沒有名稱的類,其名稱由Java編譯器給出,一般是形如:外部類名稱+$+匿名類順序,沒有名稱也就是其他地方就不能引用,不能實例化,只用一次,當然也就不能有構造器。

匿名類就是利用父類的構造函數和自身類體構造成一個類。

格式: new 父類(){子類內容}

Out out = new Out() {
  void show() {
    System.out.printIn("run in Inner");
  }
}

3. Stream

3.1 Stream介紹

Java8中引入了全新的Stream API, 在java.uti.stream包中

Stream API的特點:

  • Stream API提供了一套新的流式處理的抽象序列
  • Stream API支持函數式變成/鏈式操作
  • Stream 可以便是無限序列, 並且大多數情況下是惰性計算的

stream API 不同於java.io中的InputStream和OutputStream:

java.io Java.util.stream
存儲 順序讀寫的byte/char 順序輸出的任意java對象
用途 序列化至文件/網絡 內存計算/業務邏輯

stream API不同於java.util.List:

Jav.util.List java.util.stream
元素 已分配並存儲在內存 為分配, 實時計算
用途 操作一組已存在的java對象 惰性計算
  • 惰性計算
Stream<BigInteger> naturals = createNaturalStrem(); //不計算
Stream<BigInteger> s2 = naturals.map((n) -> n.multiply(n)); // 不計算
Stream<BigInteger> s3 = s2.limit(100); // 不計算
s3.forEach(System.out::printLn); // 計算

3.2 Stream創建

  • 通過指定元素/ 現有數組/現有Collection創建
    • strem.of(T… t)
    • Array.strem(array)
    • collection.stream()
  • 通過Supplier創建
  • 通過其他類的相關方法創建
  • 基本類型的Stream有: IntStrem/ LongStream/DoubleStream

例子:

package javatest;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @ClassName TestB
 * @Description TODO
 * @Author lingxiangxiang
 * @Date 11:37 AM
 * @Version 1.0
 **/
public class TestB {
    public static void main(String[] args) {
        String[] a = new String[]{"a", "b", "c", "d"};
        int[] b = new int[]{1, 2, 3, 4, 5};
        List<Integer> l1 = Arrays.asList(1, 2, 3, 4, 5);
        // 1. 通過Stream.of來創建
        Stream<Integer> s1 = Stream.of(1, 2, 3, 4, 5);
        // 2. 通過數組來創建
        Stream<String> s2 = Arrays.stream(a);
//        Stream<Integer> s3 = Arrays.stream(b); // 這樣的方法時錯誤的
        IntStream s4 = Arrays.stream(b);
        // 3. 通過Collection來創建
        Stream<Integer> s5 = l1.stream();
        // 4. 通過Supplier來創建
        Stream<BigInteger> s6 = Stream.generate(new NaturalSupplier());

        s1.forEach(System.out::println);
        s2.forEach(System.out::println);
        s4.forEach(System.out::println);
        s5.forEach(System.out::println);
        // limit的限定個數
        s6.limit(10).forEach(System.out::println);
    }
}
class NaturalSupplier implements Supplier<BigInteger> {
    BigInteger next = BigInteger.ZERO;
    @Override
    public BigInteger get() {
        next = next.add(BigInteger.ONE);
        return next;
    }

}

3.3 Stream的常用方法

3.3.1 map

map()方法: 將一個Stream的每個元素映射成另外一個元素並生成一個新的Stream, 可以將一個元素轉換成另外一種元素類型

// 例子1
import java.util.Arrays;
import java.util.stream.Stream;

public class StreamMapSample {

	public static void main(String[] args) throws Exception {
		String[] array = "Stream API supports functional-style operations".split(" ");
		Stream<String> stream = Arrays.stream(array);
		stream.map(String::toUpperCase).forEach(System.out::println);
	}
}


// 例子2

import java.util.Arrays;
import java.util.stream.Stream;

class Person {

	String name;
	char gender;

	public Person(String name, char gender) {
		this.name = name;
		this.gender = gender;
	}

	public String toString() {
		return "Persion(" + name + ", " + gender + ")";
	}
}

public class StreamMapSample2 {

	public static void main(String[] args) throws Exception {
		String[] inputs = { "Bob,M", "Alice,F", "Time,M", "Lily,F" };
		Stream<String> names = Arrays.stream(inputs);
		Stream<Person> persons = names.map((s) -> {
			int n = s.indexOf(',');
			String name = s.substring(0, n);
			char gender = s.charAt(n + 1);
			return new Person(name, gender);
		});
		persons.forEach(System.out::println);
	}
}

3.3.2 filter

將一個Stream的每個元素進行測試,通過測試的元素被過濾后生成一個新的Stream, 用於排除不滿足條件的元素

// 例子1
import java.util.function.Supplier;
import java.util.stream.Stream;

class NaturalSupplier implements Supplier<Long> {

	long x = 0;

	public Long get() {
		x++;
		return x;
	}

}

public class StreamFilterSample {

	public static void main(String[] args) throws Exception {
		Stream<Long> natural = Stream.generate(new NaturalSupplier());
		Stream<Long> odd = natural.filter((n) -> n % 2 == 1);
		odd.limit(20).forEach(System.out::println);
	}
}

// 例子2
import java.util.Arrays;
import java.util.stream.Stream;

public class StreamFilterSample2 {

	public static void main(String[] args) throws Exception {
		String[] array = { "Java", " Python ", " ", null, "\n\n", " Ruby " };
		Stream<String> normalized = Arrays.stream(array).filter(s -> s != null && !s.trim().isEmpty())
				.map(s -> s.trim());
		normalized.forEach(System.out::println);
	}
}

3.3.3 reduce

reduce()方法:

  • 將一個Stream的每個元素依次作用於BiFunction,並將結果合並
  • reduce是聚合方法
  • 聚合方法會立刻對Stream進行運算
public class StreamReduceSample {

    public static void main(String[] args) throws Exception {
        int r = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce((acc, x) -> acc * x).get();
        System.out.println(r);
        System.out.println(1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9);
    }
}

3.3.4 forEach

forEach 和 pre-java8 的對比

// Java 8
roster.stream()
 .filter(p -> p.getGender() == Person.Sex.MALE)
 .forEach(p -> System.out.println(p.getName()));
// Pre-Java 8
for (Person p : roster) {
 if (p.getGender() == Person.Sex.MALE) {
 System.out.println(p.getName());
 }
}

3.3.5其他操作

java.util.stream.Stream提供了許多實用的功能:

  • 轉換操作:map, filter, sorted, distinct(去重)

  • 合並操作:concat, flatMap

  • 並行處理:parallel

  • 聚合操作:reduce, count, max, min, sum, average

  • 其他操作:allMatch, anyMatch, forEach

  • Stream轉換為集合/數組類型:toArray, collect

  • limit(10): 取10個

  • skip(3): 忽律前三個

  • s5.sorted(Comparator.reverseOrder()).forEach(System.out::println);
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM