찾다
Javajava지도 시간Java8에서 스트림 스트리밍 프로그래밍을 사용하는 방법

1. 스트림 중간 작업

스트림의 중간 작업은 필터 필터링, 맵 매핑 변환, 플랫맵 병합, 개별 중복 제거, 정렬 정렬 및 기타 작업을 포함하여 스트림 체인의 데이터 처리 작업을 의미합니다. 이러한 작업은 여러 중간 작업을 연결하여 복잡한 데이터 처리를 수행할 수 있는 새로운 Stream 개체를 반환합니다. 중간 작업에는 종료 작업이 트리거되어야 한다는 점에 유의해야 합니다.

다음은 Stream의 일반적인 중간 작업을 카테고리별로 설명합니다.

1.1. 필터: 조건을 충족하는 요소 필터링

filter() 메서드는 데이터 필터링을 구현하는 데 자주 사용됩니다. 즉, 컬렉션 및 배열과 같은 데이터 소스에서 지정된 조건을 충족하는 요소를 필터링할 수 있습니다. 그리고 새로운 스트림을 반환합니다.

블랙리스트에 있는 휴대폰 번호 목록이 있고 "133"으로 시작하는 모든 요소를 ​​필터링해야 한다고 가정합니다. 그런 다음 filter()를 사용하여 이를 달성할 수 있습니다. -

//将数组转换为一个字符串列表
List<String> numbers = Arrays.asList("13378520000","13278520000","13178520000","13358520000");
//通过stream()方法创建一个流,接着使用filter()方法过滤出前缀为“133”的元素,最终通过collect() 方法将结果收集到一个新列表中
List<String> filterdNumbers = numbers.stream().filter(s -> s.startsWith("133")).collect(Collectors.toList());
System.out.println(filterdNumbers);


//打印结果:[13378520000, 13358520000]

1.2, map: 매핑 변환 요소

map() 메소드는 스트림의 각 요소를 매핑하고, 이를 다른 요소로 변환하거나, 여기에서 정보를 추출하고, 새 스트림을 반환하는 데 사용됩니다.

다음 두 가지 경우에 따라 요소를 다른 요소로 변환하고 요소의 정보를 추출하는 map()을 학습합니다. -

1.2.1 요소 변환

휴대폰 번호 문자 목록이 있다고 가정합니다. , 처음 7자리를 기반으로 휴대폰 번호의 위치를 ​​확인하려면 모든 휴대폰 번호의 처음 7개 하위 문자열을 가져와야 합니다. 이를 달성하려면 map() 메서드를 사용할 수 있습니다.

List<String> numbers = Arrays.asList("13378520000","13278520000","13178520000","13558520000");
//通过stream()方法创建一个流,使用map()方法将每个字符串转换为截取前7位的字符,最后使用collect()方法将结果收集到一个新列表中
List<String> filterdNumbers = numbers.stream().map(s -> s.substring(0,7)).collect(Collectors.toList());
System.out.println(filterdNumbers);


//打印结果:[1337852, 1327852, 1317852, 1355852]

1.2 .2. 요소 정보 추출

사용자 개체 목록이 있다고 가정하면 map() 메서드를 사용하여 각 개체의 휴대전화 번호를 추출해야 합니다:

List<People> peopleList = Arrays.asList(
        new People("王二","13378520000"),
        new People("李二","13278520000"),
        new People("张四","13178520000")
);
//通过stream()方法创建一个流,使用map()方法提取每个用户的手机号,最后使用collect()方法将结果收集到一个新列表中
List<String> tel = peopleList.stream().map(People::getTel).collect(Collectors.toList());
System.out.println(tel);


//打印结果:[13378520000, 13278520000, 13178520000]

1.3, flatMap: 다중 병합 스트림을 하나의 스트림으로

flatMap() 메서드는 다대다 매핑을 달성하거나 여러 목록을 하나의 목록 작업으로 병합할 수 있습니다.

1.3.1 다대다 매핑 구현

잔액 목록 A와 B가 있다고 가정합니다. 그룹 A의 각 요소를 그룹 B의 모든 요소에 순차적으로 추가해야 합니다. 이를 달성하려면 flatMap을 사용하세요. -

List<Integer> listA = Arrays.asList(1, 2, 3);
List<Integer> listB = Arrays.asList(4, 5, 6);
List<Integer> list = listA.stream().flatMap(a -> listB.stream().map(b -> a +b)).collect(Collectors.toList());
System.out.println(list);


//打印结果:  [5, 6, 7, 6, 7, 8, 7, 8, 9]	

1.3.2 여러 목록을 하나의 목록으로 병합

여러 개의 휴대폰 번호 문자열 목록이 포함된 목록이 있다고 가정합니다. into A 목록은 flatMap() 메서드를 사용하여 구현할 수 있습니다:

List<List<String>> listOfLists = Arrays.asList(
        Arrays.asList("13378520000", "13278520000"),
        Arrays.asList("13178520000", "13558520000"),
        Arrays.asList("15138510000", "15228310000")
);
List<String> flatMapList = listOfLists.stream().flatMap(Collection::stream).collect(Collectors.toList());
System.out.println(flatMapList);


//打印结果:[13378520000, 13278520000, 13178520000, 13558520000, 15138510000, 15228310000]

1.4.distinct: 중복 요소 제거

distinct() 메서드는 스트림에서 중복 요소를 제거하고 중복 없는 목록을 생성하는 데 사용할 수 있습니다.

반복되는 휴대전화 번호 문자열이 포함된 목록이 있다고 가정하면, Unique()를 사용하여 작업을 중복 제거할 수 있습니다. -

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15138510000");
List<String> disNumbers = numbers.stream().distinct().collect(Collectors.toList());
System.out.println(disNumbers);		


//打印结果:[13378520000, 15138510000, 13178520000]		

한 가지 주의할 점은, 스트림 중복을 제거하기 위해 구별을 사용할 때 요소를 결정해야 한다는 것입니다. 스트림 equals() 및 hashCode() 메소드가 구현된 이유는 이 두 메소드가 두 객체가 동일한지 여부를 판단하는 기준이기 때문입니다.

1.5, sorted: 요소 정렬

sorted() 메서드는 스트림의 요소를 정렬하는 데 사용됩니다.

People 개체 그룹을 연령별로 정렬해야 한다고 가정합니다. 다음은 각각 오름차순과 내림차순으로 정렬됩니다. -

1.5.1, 오름차순

기본적으로 오름차순 - 오름차순으로 정렬됩니다. 주문 -

List<People> peopleList = Arrays.asList(
        new People("王二",20),
        new People("李二",30),
        new People("张四",31)
);
List<People> newpeopleList=peopleList.stream().sorted(Comparator.comparing(People::getAge)).collect(Collectors.toList());
//打印结果
newpeopleList.stream().forEach(System.out::println);

인쇄 결과:

People{name='王二', age=20}
People{name='leetwo', age=30}
People{name='Zhang Si', age= 31}

1.5.2. 내림차순 정렬

reversed() 메소드를 사용하여 역순으로 정렬합니다. 즉, 오름차순으로 정렬합니다— ', age=30}

People{name='王二', age=20}

1.6, peek: 각 요소의 정보를 볼 수 있지만 흐름을 수정하지는 않습니다. 스트림의 요소 상태


peek() 메서드는 스트림의 요소 상태를 수정하지 않고 스트림의 요소를 보는 데 사용됩니다. 이 메서드는 스트림의 모든 단계에서 사용할 수 있으며 스트림 작동에 영향을 주거나 스트림 작동을 종료하지 않습니다.

List<People> peopleList = Arrays.asList(
        new People("王二",20),
        new People("李二",30),
        new People("张四",31)
);
List<People> newpeopleList = peopleList.stream().sorted(Comparator.comparing(People::getAge).reversed()).collect(Collectors.toList());
//打印结果
newpeopleList.stream().forEach(System.out::println);

인쇄 결과:

13378520000

133

13278520000

132

peek() 메서드는 forEach와 매우 유사하며 스트림의 요소를 순회하는 데 사용할 수 있습니다. 그러나 둘 사이에는 큰 차이가 있습니다. . 요점은 forEach가 스트림의 종료 작업이라는 것입니다. 이는 스트림이 처리되었으며 더 이상 작업을 수행할 수 없음을 의미합니다. forEach 이후 스트림, 그러나 peek 메서드는 괜찮습니다. 위의 경우에서 볼 수 있듯이 요소를 인쇄하기 위해 처음으로 peek를 호출한 후 요소 뒤에는 요소의 처음 세 자리를 가로채는 맵 작업이 이어질 수도 있습니다. 끈.

이것이 peek() 메서드와 forEach의 가장 큰 차이점입니다.

1.7、limit 和 skip:截取流中的部分元素

limit()和skip()都是用于截取Stream流中部分元素的方法,两者区别在于,limit()返回一个包含前n个元素的新流,skip()则返回一个丢弃前n个元素后剩余元素组成的新流。

int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
System.out.print("取数组前5个元素:");
Arrays.stream(arr).limit(5).forEach(n -> System.out.print(n + " ")); // 输出结果为:1 2 3 4 5


System.out.print("跳过前3个元素,取剩余数组元素:");
Arrays.stream(arr).skip(3).forEach(n -> System.out.print(n + " ")); // 输出结果为:4 5 6 7 8 9 10

二、Stream终止操作

Stream的终止操作是指执行Stream流链中最后一个步骤,到这一步就会结束整个流处理。在Java8中,Stream终止操作包括forEach、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst和findAny等。这些终止操作都有返回值。需要注意一点是,如果没有执行终止操作的话,Stream流是不会触发执行的,例如,一个没有终止操作的peek()方法代码是不会执行进而打印——

list.stream().peek(t -> System.out.println("ddd"))

当加上终止操作话,例如加上collect,就会打印出“ddd”——

list.stream().peek(t -> System.out.println("ddd")).collect(Collectors.toList());

下面按类别分别讲解各个终止操作的使用。

2.1、forEach:遍历流中的每个元素

该forEach前面已经提到,这里不做过多介绍。

2.2、count:统计流中元素的数量

count可以统计流中元素的数量并返回结果。

假设有一个包含多个手机号字符串的列表,需要统计去重后的手机号数量,就可以使用count方法——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15138510000");
long count = numbers.stream()
        .distinct()//去重
        .count();//统计去重后的手机号
System.out.println(count);


//打印结果:3

2.3、reduce:将流中的所有元素归约成一个结果

reduce()可以将流中的所有元素根据指定规则归约成一个结果,并将该结果返回。

常用语法格式如下:

Optional<T> result = stream.reduce(BinaryOperator<T> accumulator);

可见,reduce方法会返回一个Optional类型的值,表示归约后的结果,需要通过get()方法获取Optional里的值。

假设有一个包含多个手机号字符串的List列表,需要在去重之后,再将列表所有字符串拼按照逗号间隔接成一个字符串返回,那么就可以通过reduce来实现——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15138510000");
Optional result = numbers.stream()
        .distinct() //去重
        .reduce((a ,b) -> a+","+b);//指定规则为,相临两个字符通过逗号“,”间隔
System.out.println(result.get());

//打印结果:13378520000,15138510000,13178520000

2.4、collect:将流中的元素收集到一个容器中,并返回该容器

collect的作用是将流中的元素收集到一个新的容器中,返回该容器。打个比喻,它就像一个采摘水果的工人,负责将水果一个个采摘下来,然后放进一个篮子里,最后将篮子交给你。我在前面的案例当中,基本都有用到collect,例如前面2.1的filter过滤用法中的List filterdNumbers = numbers.stream().filter(s -> s.startsWith("133")).collect(Collectors.toList()),就是将过滤出前缀为“133”的字符串,将这些过滤处理后的元素交给collect这个终止操作。这时collect就像采摘水果的员工,把采摘为前缀“133”的“水果”通过toList()方法收集到一个新的List容器当中,然后交给你。最后你就可以得到一个只装着前缀为“133”的元素集合。

在Java8的collect方法中,除里toList()之外,还提供了例如toSet,toMap等方法满足不同的场景,根据名字就可以知道,toSet()返回的是一个Set集合,toMap()返回的是一个Map集合。

2.5、min 和 max:找出流中的最小值和最大值

min和max用来查找流中的最小值和最大值。

假设需要在查找出用户列表中年龄最小的用户,可以按照以下代码实现——

List<People> peopleList = Arrays.asList(
        new People("王二",20),
        new People("李二",30),
        new People("张四",31)
);
//查找年龄最小的用户,若没有则返回一个null
People people = peopleList.stream().min(Comparator.comparing(People::getAge)).orElse(null);
System.out.println(people);

//打印结果:People{name=&#39;王二&#39;, age=20}

max的用法类似,这里不做额外说明。

2.6、anyMatch、allMatch 和 noneMatch:判断流中是否存在满足指定条件的元素

2.6.1、anyMatch

anyMatch用于判断,如果流中至少有一个元素满足给定条件,那么返回true,反之返回false,即 true||false为true这类的判断。

假设在一个手机号字符串的List列表当中,判断是否包含前缀为“153”的手机号,就可以使用anyMatch——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15338510000");
boolean hasNum = numbers.stream().anyMatch(n -> n.startsWith("153"));
System.out.println(hasNum);

//打印结果:true

2.6.2、allMatch

allMatch用于判断,流中的所有元素是否都满足给定条件,满足返回true,反之false,即true&&false为false这类判断。

假设在一个手机号字符串的List列表当中,判断手机号是否都满足前缀为“153”的手机号,就可以用allMatch——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15338510000");
boolean hasNum = numbers.stream().allMatch(n -> n.startsWith("153"));
System.out.println(hasNum);

//打印结果:false

2.6.3、noneMatch

noneMatch用于判断,如果流中没有任何元素满足给定的条件,返回true,如果流中有任意一个条件满足给定条件,返回false,类似!true为false的判断。

假设在一个手机号字符串的List列表当中,判断手机号是否都不满足前缀为“153”的手机号,就可以用noneMatch——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "1238510000");
//numbers里没有前缀为“153”的手机号
boolean hasNum = numbers.stream().noneMatch(n -> n.startsWith("153"));
System.out.println(hasNum);


//打印结果:true

这三个方法其实存在一定互相替代性,例如在3.6.1中,满足!anyMatch表示所有手机号都不为“153”前缀,才得到true,这不就是noneMatch,主要看在项目当中如何灵活应用。

2.7、findFirst 和 findAny:返回流中第一个或任意一个元素

2.7.1、findFirst

findFirst用于返回流中第一个元素,如果流为空话,则返回一个空的Optional对象——

假设需要对一批同手机号的黑名单用户按照时间戳降序排序,然后取出第一个即时间戳为最早的用户,就可以使用findFirst——

List<People> peopleList = Arrays.asList(
        new People("王二","13178520000","20210409"),
        new People("李二","13178520000","20230401"),
        new People("张四","13178520000","20220509"),
        new People("赵六","13178520000","20220109")
);
/**
 * 先按照时间升序排序,排序后的结果如下:
 *   People{name=&#39;王二&#39;, tel=&#39;13178520000&#39;, time=&#39;20210409&#39;}
 *   People{name=&#39;赵六&#39;, tel=&#39;13178520000&#39;, time=&#39;20220109&#39;}
 *   People{name=&#39;张四&#39;, tel=&#39;13178520000&#39;, time=&#39;20220509&#39;}
 *   People{name=&#39;李二&#39;, tel=&#39;13178520000&#39;, time=&#39;20230401&#39;}
 *
 *排序后,People{name=&#39;王二&#39;, tel=&#39;13178520000&#39;, time=&#39;20210409&#39;}成了流中的第一个元素
 */
People people = peopleList.stream().sorted(Comparator.comparing(People::getTime)).findFirst().orElse(null);
System.out.println(people);

//打印结果:People{name=&#39;王二&#39;, tel=&#39;13178520000&#39;, time=&#39;20210409&#39;}

2.7.2、findAny

findAny返回流中的任意一个元素,如果流为空,则通过Optional对象返回一个null。

假设有一个已经存在的黑名单手机号列表blackList,现在有一批新的手机号列表phoneNumber,需要基于blackList列表过滤出phoneNumber存在的黑名单手机号,最后从过滤出来的黑名单手机号当中挑选出来出来任意一个,即可以通过findAny实现——

//blackList是已经存在的黑名单列表
List<String> blackList = Arrays.asList("13378520000", "15138510000");
//新来的手机号列表
List<String> phoneNumber = Arrays.asList("13378520000", "13178520000", "1238510000","15138510000","13299920000");
String blackPhone = phoneNumber.stream()
        //过滤出phoneNumber有包含在blackList的手机号,这类手机号即为黑名单手机号。
        .filter(phone -> blackList.contains(phone))
        //获取过滤确定为黑名单手机号的任意一个
        .findAny()
        //如果没有则返回一个null
        .orElse(null);
System.out.println(blackPhone);

//打印结果:13378520000

三、并行流

前面的案例主要都是以顺序流来讲解,接下来,就是讲解Stream的并行流。在大数据量处理场景下,使用并行流可以提高某些操作效率,但同样存在一些需要考虑的问题,并非所有情况下都可以使用。

3.1、什么是并行流:并行流的概念和原理

并行流是指通过将数据按照一定的方式划分成多个片段分别在多个处理器上并行执行,这就意味着,可能处理完成的数据顺序与原先排序好的数据情况是不一致的。主要是用在比较大的数据量处理情况,若数据量太少,效率并不比顺序流要高,因为底层其实就使用到了多线程的技术。

并行流的流程原理如下:

1、输入数据:并行流的初始数据一般是集合或者数组,例如Arrays.asList("13378520000", "13178520000", "1238510000","15138510000","13299920000");

2、划分数据:将初始数据平均分成若干个子集,每个子集可以在不同的线程中独立进行处理,这个过程通常叫“分支”(Forking),默认情况下,Java8并行流使用到了ForkJoinPool框架,会将Arrays.asList("13378520000", "13178520000", "1238510000","15138510000","13299920000")划分成更小的颗粒进行处理,可能会将该数组划分成以下三个子集:

[13378520000, 13178520000]    [1238510000, 13338510000]    [13299920000]

3、处理数据:针对划分好的子集并行进行相同的操作,例如包括过滤(filter)、映射(map)、去重(distinct)等,这个过程通常叫“计算”(Computing),例如需要过滤为前缀包括“133”的字符集合,那么,各个子集,就会处理得到以下结果:

[13378520000]    [13338510000]    []

4、合并结果:将所有子集处理完成的结果进行汇总,得到最终结果。这个过程通常叫“合并”(Merging),结果就会合并如下:

[13378520000,13338510000]  

5、返回结果:返回最终结果。

通俗而言,就是顺序流中,只有一个工人在摘水果,并行流中,是多个工人同时在摘水果。

3.2、创建并行流:通过 parallel() 方法将串行流转换为并行流

可以通过parallel()方法将顺序流转换为并行流,操作很简单,只需要在顺序流上调用parallel()即可。

List<String> numbers = Arrays.asList("13378360000","13278240000","13178590000","13558120000");
//通过stream().parallel()方法创建一个并行流,使用map()方法将每个字符串转换为截取前7位的字符,最后使用collect()方法将结果收集到一个新列表中
List<String> filNums = numbers.stream().parallel().map(s -> s.substring(0,7)).collect(Collectors.toList());
System.out.println(filNums);


//打印结果:[1337836, 1327824, 1317859, 1355812]

3.3、并行流的注意事项:并行流可能引发的线程安全,以及如何避免这些问题

在使用并发流的过程中,可能会引发以下线程安全问题:并行流中的每个子集都在不同线程运行,可能会导致对共享状态的竞争和冲突。

避免线程问题的方法如下:避免修改共享状态,即在处理集合过程当中,避免被其他线程修改集合数据,可以使用锁来保证线程安全。

使用无状态操作:在并行流处理过程尽量使用无状态操作,例如filter、map之类的,可以尽量避免线程安全和同步问题。

四、Optional

4.1、什么是 Optional:Optional 类型的作用和使用场景

在实际开发当中,Optional类型通常用于返回可能为空的方法、避免null值的传递和简化复杂的判断逻辑等场景。调用Optional对象的方法,需要通过isPresent()方法判断值是否存在,如果存在则可以通过get()方法获取其值,如果不存在则可以通过orElse()方法提供默认值,或者抛出自定义异常处理。

4.2、如何使用 Optional:如何使用 Optional 类型

使用Optional类型主要目的是在数据可能为空的情况下,提供一种更安全、更优雅的处理方式。

以下是使用Optional类型的常用方法:

4.2.1、ofNullable()和isPresent()方法

将一个可能为null的对象包装成Optional类型的对象,然后根据isPresent方法判断对象是否包含空值——

String str = null;
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional对象不为空");
}else {
    System.out.println("Optional对象为空");
}

//打印结果:Optional对象为空

4.2.2、get()方法

获取Optional对象中的值,如果对象为空则抛出NoSuchElementException异常——

String str = null;
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional对象不为空");
}else {
    System.out.println("Optional对象为空");
    optStr.get();
}

控制台打印结果:

Exception in thread "main" java.util.NoSuchElementException: No value present
    at java.util.Optional.get(Optional.java:135)
    at com.zhu.fte.biz.test.StreamTest.main(StreamTest.java:144)
Optional对象为空

4.2.4、orElse()方法

获取Optional对象中的值,如果对象为空则返回指定的默认值——

String str = null;
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional对象不为空");
}else {
    System.out.println("Optional对象为空,返回默认值:" + optStr.orElse("null"));
}


//打印结果:Optional对象为空,返回默认值:null

当然,如果不为空的话,则能正常获取对象中的值——

String str = "测试";
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional对象不为空,返回值:" + optStr.orElse("null"));
}else {
    System.out.println("Optional对象为空,返回默认值:" + optStr.orElse("null"));
}

//打印结果:Optional对象不为空,返回值:测试

那么,问题来了,它是否能判断“ ”这类空格的字符串呢,我实验了一下,

String str = "     ";
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional对象不为空,返回值:" + optStr.orElse("null"));
}else {
    System.out.println("Optional对象为空,返回默认值:" + optStr.orElse("null"));
}


//打印结果:Optional对象不为空,返回值:

可见,这类空字符串,在orElse判断当中,跟StringUtils.isEmpty()类似,都是把它当成非空字符串,但是StringUtils.isBlank()则判断为空字符串。

4.2.5、orElseGet()方法

orElseGet()和orElse()类似,都可以提供一个默认值。两者区别在于,orElse方法在每次调用时都会创建默认值,而orElseGet只在需要时才会创建默认值。

4.3、Optional 和 null 的区别: Optional 类型与 null 值的异同

两者都可以表示缺失值的情况,两者主要区别为:Optional类型是一种包装器对象,可以将一个可能为空的对象包装成一个Optional对象。这个对象可以通过调用ofNullable()of()或其他方法来创建。而null值则只是一个空引用,没有任何实际的值。

Optional类型还可以避免出现NullPointerException异常,具体代码案例如下:

String str = null;
//错误示范:直接调用str.length()方法会触发NullPointerException
//int length = str.length()

//通过Optional类型避免NullPointerException
Optional<String> optionalStr = Optional.ofNullable(str);
if (optionalStr.isPresent()){//判断Optional对象是否都包含非空值
    int length = optionalStr.get().length();
    System.out.println("字符串长度为:" + length);
}else {
    System.out.println("字符串为空!");
}

//使用map()方法对Optional对象进行转换时,确保返回对结果不为null
Optional<Integer> optionalLength = optionalStr.map(s -> s.length());
System.out.println("字符串长度为:" + optionalLength.orElse(-1)); // 使用orElse()方法提供默认值

五、扩展流处理

除里以上常用的流处理之外,Java8还新增了一些专门用来处理基本类型的流,例如IntStream、LongStream、DoubleStream等,其对应的Api接口基本与前面案例相似,读者可以自行研究。

最后,需要注意一点是,在流处理过程当中,尽量使用原始类型数据,避免装箱操作,因为装箱过程会有性能开销、内存占用等问题,例如,当原始数据int类型被装箱成Integer包装类型时,这个过程会涉及到对象的创建、初始化、垃圾回收等过程,需要额外的性能开销。

위 내용은 Java8에서 스트림 스트리밍 프로그래밍을 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 亿速云에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
Java의 플랫폼 독립성을 위협하거나 향상시키는 새로운 기술이 있습니까?Java의 플랫폼 독립성을 위협하거나 향상시키는 새로운 기술이 있습니까?Apr 24, 2025 am 12:11 AM

신흥 기술은 위협을 일으키고 Java의 플랫폼 독립성을 향상시킵니다. 1) Docker와 같은 클라우드 컴퓨팅 및 컨테이너화 기술은 Java의 플랫폼 독립성을 향상 시키지만 다양한 클라우드 환경에 적응하도록 최적화되어야합니다. 2) WebAssembly는 Graalvm을 통해 Java 코드를 컴파일하여 플랫폼 독립성을 확장하지만 성능을 위해 다른 언어와 경쟁해야합니다.

JVM의 다른 구현은 무엇이며, 모두 같은 수준의 플랫폼 독립성을 제공합니까?JVM의 다른 구현은 무엇이며, 모두 같은 수준의 플랫폼 독립성을 제공합니까?Apr 24, 2025 am 12:10 AM

다른 JVM 구현은 플랫폼 독립성을 제공 할 수 있지만 성능은 약간 다릅니다. 1. OracleHotspot 및 OpenJDKJVM 플랫폼 독립성에서 유사하게 수행되지만 OpenJDK에는 추가 구성이 필요할 수 있습니다. 2. IBMJ9JVM은 특정 운영 체제에서 최적화를 수행합니다. 3. Graalvm은 여러 언어를 지원하며 추가 구성이 필요합니다. 4. AzulzingJVM에는 특정 플랫폼 조정이 필요합니다.

플랫폼 독립성은 개발 비용과 시간을 어떻게 줄입니까?플랫폼 독립성은 개발 비용과 시간을 어떻게 줄입니까?Apr 24, 2025 am 12:08 AM

플랫폼 독립성은 여러 운영 체제에서 동일한 코드 세트를 실행하여 개발 비용을 줄이고 개발 시간을 단축시킵니다. 구체적으로, 그것은 다음과 같이 나타납니다. 1. 개발 시간을 줄이면 하나의 코드 세트 만 필요합니다. 2. 유지 보수 비용을 줄이고 테스트 프로세스를 통합합니다. 3. 배포 프로세스를 단순화하기위한 빠른 반복 및 팀 협업.

Java의 플랫폼 독립성은 코드 재사용을 어떻게 촉진합니까?Java의 플랫폼 독립성은 코드 재사용을 어떻게 촉진합니까?Apr 24, 2025 am 12:05 AM

Java'SplatformIndenceFacilitatesCodereScoderEByWatHeAveringByTeCodetOrunonAnyPlatformwitHajvm.1) DevelopersCanwriteCodeOnceforConsentEStentBehaviorAcRossPlatforms.2) MAINTENDUCEDSCODEDOES.3) LIBRRIESASHSCORAREDERSCRAPERAREDERSPROJ

Java 응용 프로그램에서 플랫폼 별 문제를 어떻게 해결합니까?Java 응용 프로그램에서 플랫폼 별 문제를 어떻게 해결합니까?Apr 24, 2025 am 12:04 AM

Java 응용 프로그램의 플랫폼 별 문제를 해결하려면 다음 단계를 수행 할 수 있습니다. 1. Java의 시스템 클래스를 사용하여 시스템 속성을보고 실행중인 환경을 이해합니다. 2. 파일 클래스 또는 java.nio.file 패키지를 사용하여 파일 경로를 처리하십시오. 3. 운영 체제 조건에 따라 로컬 라이브러리를로드하십시오. 4. visualVM 또는 JProfiler를 사용하여 크로스 플랫폼 성능을 최적화하십시오. 5. 테스트 환경이 Docker Containerization을 통해 생산 환경과 일치하는지 확인하십시오. 6. githubactions를 사용하여 여러 플랫폼에서 자동 테스트를 수행하십시오. 이러한 방법은 Java 응용 프로그램에서 플랫폼 별 문제를 효과적으로 해결하는 데 도움이됩니다.

JVM의 클래스 로더 서브 시스템은 플랫폼 독립성에 어떻게 기여합니까?JVM의 클래스 로더 서브 시스템은 플랫폼 독립성에 어떻게 기여합니까?Apr 23, 2025 am 12:14 AM

클래스 로더는 통합 클래스 파일 형식, 동적로드, 부모 위임 모델 및 플랫폼 독립적 인 바이트 코드를 통해 다른 플랫폼에서 Java 프로그램의 일관성과 호환성을 보장하고 플랫폼 독립성을 달성합니다.

Java 컴파일러는 플랫폼 별 코드를 생성합니까? 설명하다.Java 컴파일러는 플랫폼 별 코드를 생성합니까? 설명하다.Apr 23, 2025 am 12:09 AM

Java 컴파일러가 생성 한 코드는 플랫폼 독립적이지만 궁극적으로 실행되는 코드는 플랫폼 별입니다. 1. Java 소스 코드는 플랫폼 독립적 인 바이트 코드로 컴파일됩니다. 2. JVM은 바이트 코드를 특정 플랫폼의 기계 코드로 변환하여 크로스 플랫폼 작동을 보장하지만 성능이 다를 수 있습니다.

JVM은 다른 운영 체제에서 멀티 스레딩을 어떻게 처리합니까?JVM은 다른 운영 체제에서 멀티 스레딩을 어떻게 처리합니까?Apr 23, 2025 am 12:07 AM

멀티 스레딩은 프로그램 대응 성과 리소스 활용을 향상시키고 복잡한 동시 작업을 처리 할 수 ​​있기 때문에 현대 프로그래밍에서 중요합니다. JVM은 스레드 매핑, 스케줄링 메커니즘 및 동기화 잠금 메커니즘을 통해 다양한 운영 체제에서 멀티 스레드의 일관성과 효율성을 보장합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

VSCode Windows 64비트 다운로드

VSCode Windows 64비트 다운로드

Microsoft에서 출시한 강력한 무료 IDE 편집기

Atom Editor Mac 버전 다운로드

Atom Editor Mac 버전 다운로드

가장 인기 있는 오픈 소스 편집기

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 영어 버전

SublimeText3 영어 버전

권장 사항: Win 버전, 코드 프롬프트 지원!