記事ディレクトリ
この仲間からの 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. ストリームを取得する
入手方法 | メソッド名 | 説明する |
---|---|---|
単一列コレクション | デフォルトのストリーム 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);
}
}