JAVA の基本 - ストリーム フロー (Java の詳細な注意事項)


この仲間からの Java の詳細なメモをすべて読むことができます

1. Stream について初めて知る

ここに画像の説明を挿入
次のコードを見ると、Stream を使用する方が便利であることがわかりますが、通常のコレクション トラバーサルを使用するのは少し複雑です。

public class Test01 {
    
    
	public static void main(String[] args) {
    
    
		ArrayList<String> list1 = new ArrayList<>();
		list1.add("张无忌");
		list1.add("周正若");
		list1.add("赵斌");
		list1.add("张强");
		list1.add("张三丰");
 
		// Stream流
		list1.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3)
				.forEach(name -> System.out.println(name));
		// 张无忌
		// 张三丰
 
		// 1.把所有“张”姓开头元素存储到新集合
		ArrayList<String> list2 = new ArrayList<>();
		for (String name : list1) {
    
    
			if (name.startsWith("张")) {
    
    
				list2.add(name);
			}
		}
		System.out.println(list2); // [张无忌, 张强, 张三丰]
 
		// 2.把所有“张”姓开头且长度为3的元素存储到新集合
		ArrayList<String> list3 = new ArrayList<>();
		for (String name : list2) {
    
    
			if (name.length() == 3) {
    
    
				list3.add(name);
			}
		}
		System.out.println(list3); // [张无忌, 张三丰]
	}
}

2. ストリームの概要

たとえば、上記の小さな例では、ストリーム フローの概念は次のとおりです。
ここに画像の説明を挿入
ストリーム フローの機能は次のとおりです。

3. ストリームの使用手順

ラムダ式を組み合わせて、コレクションと数値の操作を簡素化します。

  1. まずストリーム (パイプライン) を取得し、そこにデータを置きます。
  2. 中間メソッドを使用して、パイプライン上のデータを操作します。
  3. ファイナライザー メソッドを使用して、パイプライン上のデータを操作します。
フィルタリング、変換 中間メソッド メソッドが呼び出された後、他のメソッドを呼び出すことができます
統計、印刷 終了方法 最後のステップで、呼び出しが完了した後は、他のメソッドを呼び出すことはできません

1. ストリームを取得する

入手方法 メソッド名 説明する
単一列コレクション デフォルトのストリーム stream() コレクション内のデフォルトのメソッド
2列セット なし ストリームは直接使用できません。keySet() またはentrySet() を通じて単一列のコレクションに変換する必要があります。
配列 public static Stream ストリーム(T[ ] 配列) Arrays ツールクラスの静的メソッド
散在するデータの束 public static Stream of(T… 値) ストリームインターフェースの静的メソッド

1.1 単一列セット

public class StreamTest {
    
    
	public static void main(String[] args) {
    
    
		//单列集合获取Stream流
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "a","b","c","d","e");
		//获取到一个流水线,并把集合中的数据方法流水线上
		//Stream<String> stream1 = list.stream();
		//使用终结方法打印流水线上数据
		//stream1.forEach( s ->System.out.println(s) );
		
		list.stream().forEach(s -> System.out.println(s));
	}
}

1.2 2 列コレクション

public class StreamTest {
    
    
	public static void main(String[] args) {
    
    
		
		//双列集合获取Stream流 
		//1. 创建双列集合
		HashMap<String, Integer> hm = new HashMap<>();
		//2. 添加数据
		hm.put("aaa", 111);
		hm.put("bbb", 222);
		hm.put("ccc", 333);
		//3.1 获取Stream流方法一: keySet()
		//键
		 hm.keySet().stream().forEach(s -> System.out.println(s));
		//3.2 获取Stream流方法二:entrySet()
		 //键值对
		hm.entrySet().stream().forEach(s -> System.out.println(s));	 
	}
}

1.3 配列

Stream インターフェースの静的メソッドの詳細:

  • メソッドの仮パラメータは可変パラメータであり、散在するデータまたは配列の束を渡すことができます。
  • ただし、配列は参照データ型である必要があります。
  • 基本データ型が渡された場合、配列全体が要素と同等になり、ストリームに入れられます。
public class StreamTest {
    
    
	public static void main(String[] args) {
    
    
		
		//数组获取Stream流 
		//1.创建基本数据类型数组
		int[] arr1 = {
    
    1,2,3,4,5,6,7,8,9,10};
		//获取stream
		Arrays.stream(arr1).forEach(s -> System.out.println(s));
		
		//2.创建引用数据类型数组
		String[] arr2 = {
    
    "a","b","c"};
		//获取stream
		Arrays.stream(arr2).forEach(s -> System.out.println(s));
		
		//方式是错误的!!!
		//Stream接口中静态方法of的细节
		//方法的形参是一个可变参数,可以传递一堆零散数据,也可以传递数组
		//但是数组必须是引用数据类型
		//如果传递的是基本数据类型,是会把整个数组相当做一个元素,放到一个stream流当中
		Stream.of(arr2).forEach(s -> System.out.println(s));
		Stream.of(arr1).forEach(s -> System.out.println(s)); //[I@1b28cdfa
	}
}

1.4 散在するデータ

詳細: 散在するデータの束は同じデータ型である必要があります。

public class StreamTest {
    
    
	public static void main(String[] args) {
    
    
		//零散数据获取Stream流 
		
		//基本数据类型
		Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
		
		//引用数据类型
		Stream.of("a","b","c","d","e").forEach(s -> System.out.println(s));
	}
}

2. Streamの中間メソッド

メソッド名 説明する
ストリームフィルター ( Predicate<? super T> predicate ) フィルター
ストリームフィルター ( Predicate<? super T> predicate ) 最初のいくつかの要素を取得する
ストリームスキップ (long n ) 最初のいくつかの要素をスキップする
個別のストリーム ( ) 要素の重複排除、依存関係(hashCodeおよびequalsメソッド)
static Stream concat (ストリーム a , ストリーム b ) 2 つのストリーム a と b を 1 つのストリームにマージします
ストリーム マップ ( Function<T ,R> マッパー) ストリーム内のデータ型の変換

注 1: 中間メソッドは新しいストリームを返します。元のストリームは 1 回しか使用できません。チェーン プログラミングを使用することをお勧めします。
注 2: Stream ストリーム内のデータを変更しても、元のコレクションまたは配列内のデータには影響しません。

public class StreamTest01 {
    
    
	public static void main(String[] args) {
    
    
		//1.过滤:把开头的留下,其余数据过滤不要
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "张三","李四","王五","赵六","张七");
		
		ArrayList<String> list2 = new ArrayList<>();
		Collections.addAll(list2, "张三","李四","王五","赵六","张三");
		
		ArrayList<String> list3 = new ArrayList<>();
		Collections.addAll(list3, "孙七","钱八");
		
		ArrayList<String> list4 = new ArrayList<>();
		Collections.addAll(list2, "张三-23","李四-24","王五-25");
		
		list.stream().filter(new Predicate<String>() {
    
    
			//匿名内部类太麻烦 需要缩写
			@Override
			public boolean test(String s) {
    
    
				//如果返回值为true,表示当前数据留下
				//如果返回值为false,表示当前数据舍弃
				return s.startsWith("张");
				
			}
		}).forEach(s -> System.out.println(s)); //张三 张七
		
		list.stream()
		    .filter(s -> s.startsWith("张"))
		    .forEach(s -> System.out.println(s));
		
		//2. 获取前几个元素  
		list.stream()
		    .limit(3)
		    .forEach(s -> System.out.println(s));  //张三 李四 王五
		//3. 跳过
		list.stream()
		    .skip(4)
		    .forEach(s -> System.out.println(s));  //张七
		
		//4.去重
		list2.stream()
		     .distinct()
		     .forEach(s -> System.out.println(s)); //张三 李四 王五 赵六
		
		//5. 合并
		Stream.concat(list2.stream(), list3.stream())
		      .forEach(s -> System.out.println(s));
		
		//6.转换数据类型
		//只能获取集合里面的年龄并打印
		//第一个类型:流中原本的数据类型
		//第二个类型:将要转变成为的数据类型
		list4.stream().map(new Function<String,Integer>() {
    
    
			@Override
			//apply: 依次表示流中的每一盒数据
			//返回值:表示转化之前的数据
			public Integer apply(String s) {
    
    
				String[] arr = s.split("-");
				String ageString = arr[1];
				int age = Integer.parseInt(ageString);
				return age;
			}
		}).forEach(s -> System.out.println(s));
		
		list.stream()
		    .map(s ->Integer.parseInt(s.split("-")[1]))
		    .forEach(s -> System.out.println(s));
	}
}

3. Streamストリームの終了方法

メソッド名 説明する
void forEach (コンシューマアクション) トラバース
長いカウント ( ) 統計
toArray() ストリーム内のデータを収集し、配列に入れます。
コレクト (コレクター コレクター) ストリーム内のデータを収集し、コレクションに入れます。
public class StreamTest02 {
    
    
	public static void main(String[] args) {
    
    
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "张三", "李四", "王五", "赵六");
 
		// 遍历
 
		// Consumer的泛型:表示流中的数据类型
		// accept方法的形参s:依次表示流中的每一个数据
		//
		list.stream().forEach(new Consumer<String>() {
    
    
			@Override
			public void accept(String s) {
    
    
				System.out.println(s);
			}
		});
 
		list.stream().forEach(s -> System.out.println(s)); // 张三 李四 王五 赵六
 
		// 统计
		long count = list.stream().count();
		System.out.println(count); // 4
 
		// 收集数据放进数组
		Object[] arr1 = list.stream().toArray();
		System.out.println(Arrays.toString(arr1)); // [张三, 李四, 王五, 赵六]
 
		// 指定数据类型
		// Infunction的泛型:具体类型的数组
		// apply中形参:流中数据的个数,要跟数组长度一致
		// apply的返回值:具体类型的数组
		String[] arr2 = list.stream().toArray(new IntFunction<String[]>() {
    
    
			@Override
			public String[] apply(int value) {
    
    
				return new String[value];
			}
		});
		// toArray方法中的参数:只是创建一个指定类型的数组
		// toArray底层: 会此意得到流中的每一个数据,并把数据放到数组中
		// toArray的返回值:是一个装着流里面所有数据的数组
		System.out.println(Arrays.toString(arr2));
 
		// lambda表达式
		String[] arr3 = list.stream().toArray(value -> new String[value]);
		System.out.println(Arrays.toString(arr3));
	}
}

収集メソッド:

public class StreamTest {
    
    
	public static void main(String[] args) {
    
    
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "张三-男-23", "李四-男-24", 
                        "王五-男-25", "赵六-女-27", "孙八-女-28");
 
		//收集到List集合当中
		//需求:
		//将所有的男性收集起来
		List<String> newList = list.stream()
				.filter(s-> "男".equals(s.split("-")[1]))
				.collect(Collectors.toList());
		System.out.println(newList);  //[张三-男-23, 李四-男-24, 王五-男-25]
		
		//收集到Set集合当中
		Set<String> newSet = list.stream()
				.filter(s-> "男".equals(s.split("-")[1]))
				.collect(Collectors.toSet());
		System.out.println(newSet);
		
		//收集到Map集合当中
		//键: 姓名  值: 年龄
		
		//toMap:
		//参数一表示键的生成规则  参数二表示值得生成规则
		//参数一:  
		//Function泛型一:表示流中每一个数据的类型 ;
		//        泛型二:表示Map集合中键的数据类型
		//方法apply 形参:一次表示流里面的每一个数据
		//        方法体:生成键的代码 
		//        返回值:已生成的键
		//参数二:
		//Function泛型一:表示流中每一个数据的类型 ;
		//        泛型二:表示Map集合中值的数据类型
		//方法apply 形参:一次表示流里面的每一个数据
		//        方法体:生成值的代码 
		//        返回值:已生成的值
		Map<String, Integer> newMap = list.stream()
		.filter(s-> "男".equals(s.split("-")[1]))
		.collect(Collectors.toMap(new Function<String, String>() {
    
    
			@Override
			public String apply(String s) {
    
    
				return s.split("-")[0];
			}
		}, new Function<String, Integer >() {
    
    
			@Override
			public Integer apply(String s) {
    
    
				return Integer.parseInt(s.split("-")[2]);
			}
		}));
		System.out.println(newMap);  //{李四=24, 张三=23, 王五=25}
		
		//lambda表达式
		Map<String, Integer> newMap1 = list.stream()
				.filter(s-> "男".equals(s.split("-")[1]))
				.collect(Collectors.toMap( 
						s-> s.split("-")[0], 
						s-> Integer.parseInt(s.split("-")[2])));
		System.out.println(newMap1);
	}
}

4. 練習する

1. データのフィルタリング

要件:
セットを定義し、整数 1、2、3、4、5、6、7、8、9、10 を追加して
奇数をフィルターし、偶数のみを残します。
そして結果を保存します

public class StreamDemo {
    
    
	public static void main(String[] args) {
    
    
		// 1.定义一个集合
		ArrayList<Integer> list = new ArrayList<>();
		// 2.添加数据
		Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
 
		// 3.过滤奇数,只留偶数
		// 进行判断,如果是偶数,返回true
		List<Integer> list2 = list.stream()
				.filter(n -> n % 2 == 0)
				.collect(Collectors.toList());
		System.out.println(list2); //[2, 4, 6, 8, 10]
	}
}

2. データ操作 - 年齢によるフィルター

要件:
ArrayList コレクションを作成し、次の文字列を追加します。文字列の前に名前があり、その後に年齢
「zhangsan, 23」、
「lisi, 24」、
「wangwu, 25」
が続きます。 24 歳に相当し、その結果が Map コレクションに収集されます。名前がキー、年齢が値です

public class StreamDemo {
    
    
	public static void main(String[] args) {
    
    
		// 1.定义一个集合
		ArrayList<String> list = new ArrayList<>();
		//2.集合添加字符串
		list.add( "zhangsan,23");
		list.add("lisi,24");
		list.add("wangwu,25");
		//3.保留年龄大于24岁的人
		Map<String, Integer> map = list.stream()
		.filter(s -> Integer.parseInt(s.split(",")[1]) >= 24)
		.collect(Collectors.toMap(
				s -> s.split(",")[0], 
				s -> Integer.parseInt(s.split(",")[1])));
		System.out.println(map);  //{lisi=24, wangwu=25}
	}
}

3. データ改ざん・出演者情報請求審査

現在、2 つの ArrayList コレクションがあり、
最初のコレクションには 6 人の俳優の名前と年齢が保存されています。2 番目のコレクション: 6 人の女優の名前と年齢を保存します。名前と年齢はカンマで区切ってください。例: Zhang San, 23 は、
次の操作を完了する必要があります:
俳優には名前が 3 文字である最初の 2 文字のみが必要で、
女優にはヤンという姓のみが必要で、最初の 1 文字は必要ありません。
フィルターされた俳優の名前と名前を結合します。女優名をまとめて
前のステップの俳優情報を Actor オブジェクトにカプセル化します。
すべてのアクター オブジェクトを List コレクションに保存します。
備考: アクタークラス Actor、属性は: 名前、年齢

public class StreamDemo {
    
    
	public static void main(String[] args) {
    
    
		// 1.定义两个集合
		ArrayList<String> manList = new ArrayList<>();
		ArrayList<String> womenList = new ArrayList<>();
 
		// 2.添加数据
		Collections.addAll(manList, "蔡坤坤,24", "叶购成,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖梁梁,27");
		Collections.addAll(womenList, "赵小颖,35", "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33");
 
		// 3. 男演员只要名字为3个字的前两个人
		Stream<String> stream1 = manList.stream()
		.filter(s -> s.split(",")[0].length() == 3)
		.limit(2);
//		.forEach(s -> System.out.println(s)); // 蔡坤坤,24  叶购成,23
																													// 叶购成,23
		//4.女演员只要姓杨的 并且不要第一个
		Stream<String> stream2 = womenList.stream()
		.filter(s -> s.split(",")[0].startsWith("杨"))
		.skip(1);
//		.forEach(s -> System.out.println(s));  //杨小幂,33
		
		//5.把过滤的男演员和女演员信息合并在一起
		//演员信息封装进Actor对象
		
		//String -> Actor对象(类型转换)
		List<Actor> list = Stream.concat(stream1, stream2)
		.map(s -> new Actor(s.split(",")[0],Integer.parseInt(s.split(",")[1])))
		.collect(Collectors.toList());
		System.out.println(list);
	}
}

おすすめ

転載: blog.csdn.net/weixin_68658847/article/details/130534700