Cohe
15. Operator, Stream 본문
728x90
반응형
- Operator : 매개 변수 0, 리턴0 (연산 결과)
- 연산하는 것
- Function의 하위 인터페이스로 보통 매개변수값을 연산하고 그 결과를 리턴하는 경우 사용
BinaryOperator<T> T apply(T t1, T t2) UnaryOperator<T> T apply(T t) xxxBinaryOperator xxx applyAsXXX(xxx,xxx) xxxUnaryOperator xxx applyAsXXX(xxx) - predicate : 매개 변수 0, 리턴0 (boolean), 추상 메서드를 test라는 이름으로 가지고 있따.인터페이스 리턴(boolean)
Predicate<T> boolean test(T t) BiPredicate boolean test(T t, U u) xxxPredicate boolean test(xxxx)
Stream
- 스트림 : 여러 값들을 가지고 있는 배열이나 컬렉션등을 for문이 아닌 함수형 인터페이스를 이용해서 반복 처리할 수 있는 기능
- 필수는 아니지만 가독성 좋은 코드를 생성하기 위해서 알아둬야 함.
- 스트림 객체 생성 : build() 메서드 이용하기
- builder()메서드로 Builder 객체 생성 이후에 add() 메서드로 리턴타입이 Builder 객체이므로 메서드 체이닝 가능
- 스트림 사용 : 배열, 컬렉션, 빌더를 사용할 수 있다.
- generate()메서드 이용하기
- 람다에서 Supplier<T> 인터페이스를 이용하여 값을 추가 생성합니다.
- 스트림은 람다(함수형 인터페이스)를 활용하여 내부 반복자를 이용 시간과 코드의 양을 줄임, 또한 스트림을 통해서 간단하게 병렬 처리가 가능
스트림의 처리 단계!
- 생성 : 스트림 인스턴스 생성
- 가공 : 필터링과 맵핑 등 원하는 결과를 만들어가는 중간 작업
- 결과 : 최종적으로 결과를 얻어내는 작업
- 외부 반복자 vs 내부 반복자
- 외부 반복자 : 컬렉션 내의 요소를 반복문을 통해 하나씩 읽어 처리하는 방식 (for문)
- 내부 반복자 : 스트림의 for-each 메서드를 람다식을 사용해서 기술하는 방식을 의미 (stream)
- 외부 파일에서 스트림 생성하기
- Files.find(Path, int BiPredicatem FileVisitOption) , Files.list(Path)
- 반환타입 : Stream<Path>
- Files.lines(Path, Charset), BufferedReader.lines()
- 반환타입 : Stream<String>
- Files.find(Path, int BiPredicatem FileVisitOption) , Files.list(Path)
package G_java;
import java.util.stream.Stream;
import java.util.Arrays;
import java.util.List;
public class G08_StreamEx {
public static void main(String[] args) {
//배열을 이용한 스트림 생성
String[] arr = new String[]{
"a", "b", "c", "d","e","f"
};
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(s->System.out.print(s+" "));
System.out.println();
Stream<String> stream2 = Arrays.stream(arr, 2, 5); //배열의 일부를 추출해서 객체 생성
stream2.forEach(s->System.out.print(s+" "));
System.out.println();
//문자열 배열을 컬렉션 프레임워크로 만들어서 스트림 만들기
List<String> list = Arrays.asList(arr);
//List 객체를 stream()를 이용. Stream 객체 생성
Stream<String> stream3 = list.stream();
stream3.forEach(s->System.out.print(s));
//스트림 객체 생성 : build() 메서드 이용하기
Stream stream4 = Stream.builder() //집어넣는 개수에 따라서 달라짐!! 따로 limit이 필요치 않다!
.add("무궁화")
.add("삼천리")
.add("화려강산")
.add("대한사람")
.add("현영이")
.build();
stream4.forEach(s->System.out.println(s+" "));
System.out.println();
//스트림 객체 생성 : 2.generate()메서드 이용하기
//람다에서 Supplier<T> 인터페이스를 이용하여 값을 추가 생성합니다.
Stream<String> Stream5 = Stream.generate(()->"애국가").limit(10); //limit이 없으면 끝이 안난다.
Stream5.forEach(s->System.out.println(s+" "));
//스트림 객체 생성 : 3. iterate() 메서드 이용하기
Stream<Integer> stream6 = Stream.iterate(1, n->n+1).limit(10); //시작 값 1->10까지
stream6.forEach(s-> System.out.println(s+" "));
}
}
가공단계
- 가공 중간 처리 단계
- 필터링 : filtering
- Stream 내의 요소를 걸러내는 기능을 말함
- 메소드
- distinct() : 중복 제거
- filter() : 조건에 맞는 요소를 선택(boolean 결과에 따른 검출)
- Stream
- Steam
- IntStream
- LongStream
- DoubleStream
package G_java;
import java.util.Arrays;
import java.util.List;
public class G11_FilteringEx {
public static void main(String[] args) {
//list 객체 생성하기
List<String> list = Arrays.asList("홍길동", "김유신","홍길동", "이순신 ","홍길동", "유관순","홍길동", "김유신" );
//distinct() 메소드로 중복 제거 후 내부 반복자로 출력
System.out.println("distinct()");
list.stream().distinct().forEach(s->System.out.println(s+" "));
System.out.println();
//"홍으로 시작하는 문자열로 필터링 후 내부 반복자로 출력
System.out.println("filter()");
list.stream().filter(n->n.startsWith("홍"))
.forEach(e->System.out.println(e+" "));
//distinct()와 filter()를 동시에 사용
System.out.println("distinct()+filter()");
list.stream().distinct().filter(n->n.startsWith("홍")).forEach(e->System.out.println(e+" "));
}
}
- 매핑 : mapping 연결해줌
- 컬렉션 프레임워크에 맵과 유사한 기능을 한다. 즉, key: value와 같이 묶어주는 것을 맵핑이라고 한다.
- 맵핑은 스트림의 데이터를 매개변수로 받아서 가공처리 후 새로운 스트림을 만들어 리턴한다.
- 데이터 변환을 위한 기능
- 메서드
- flatMapXXX() 메서드
- 다른 타입의 요소를 가진 스트림을 생성 및 반환
- 리턴 타입
- Stream <R>
- DoubleStream
- IntStream
- LongStream
- mapXXX()
- asDoubleStream()
- asLongStream()
- box()
- flatMapXXX() 메서드
package G_java;
import java.util.Arrays;
import java.util.List;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
public class G12_mappingEx {
public static void main(String[] args) {
//flatMapXXX() 메서드
//문자열을 공백으로 분리해서 매핑
List<String> list1 = Arrays.asList("동백물과", "백두산이", "마르고 닳도록");
list1.stream().flatMap(data -> Arrays.stream(data.split(" "))).forEach(word->System.out.println(word));
//문자열을 , 로 분리해서 double 자료형으로 반환하여 맵핑
List<String> list2 = Arrays.asList("1.1,2.2,3.3","4.4,5.5,6.6"); //이걸 더블 스트링으로 바꿀거에용
DoubleStream dsr = list2.stream().flatMapToDouble(data->{
String[] strArr = data.split(",");
double[] dArr = new double[strArr.length];
for (int i = 0;i<dArr.length;i++){
dArr[i] = Double.parseDouble(strArr[i].trim());
}
return Arrays.stream(dArr);
});
dsr.forEach(n-> System.out.println(n));
System.out.println();
//---------------------여기부터 공부 다시 하기------------------
//문자열을 , 로 분리해서 int 자료형으로 변화해서 매핑
List<String> list3 = Arrays.asList("1, 2, 3","4, 5, 6");
IntStream isr = list3.stream().flatMapToInt(data -> {
String[] strArr = data.split(",");
int[] intArr = new int[strArr.length];
for(int i = 0; i< strArr.length; i++) {
intArr[i] = Integer.parseInt(strArr[i].trim());
}
return Arrays.stream(intArr);
});
isr.forEach(s -> System.out.println(s));
//mapXXX() 메서드 : 요소를 새로 구성해서 새로운 스트림을 리턴
List<String> list4 = Arrays.asList("동해물과", "백두산이","마르고 닳도록");
System.out.println("함수적 인터페이스 방식");
list4.stream().mapToInt(String::length)
.forEach(len -> System.out.println(len));
// - asDoubleStream, asLongStream, boxed
// asDoubleStream : IntStream, LongStream을 DoubleStream으로 형변환
// asLongStream : IntStream을 LongStream으로 형변환
// boxed : IntStream, LongStream, DoubleStream을 각가 Stream<Integer>
// , Stream<Long>, Stream<Double>로 형변환
int intArr[] = {10, 20, 30, 40, 50, 60};
// double타입의 요소를 갖는 DoubleStream으로 형변환
Arrays.stream(intArr).asDoubleStream()
.forEach(d -> System.out.println(d));
System.out.println();
//int타입의 요소를 갖는 Stream<Integer>으로 형변환
Arrays.stream(intArr).boxed()
.forEach(i -> System.out.println(i.getClass()));
}
}
- 정렬 : sorting
package G_java;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class G13_SortingEx {
public static void main(String[] args) {
/*
* Stream의 중간 단계에서 sorted메서드를 사용하여 순서를 변경할 수 있음.
* 일반적인 객체를 정렬하기 위해서는 Comparable 인터페이스를 구현한 클래스 객체만 정렬
* 가능합니다.
*
*/
List<String> list = Arrays.asList("홍길동", "김유신","이순신","유관순");
System.out.println("기본 정렬");
list.stream().sorted().forEach(System.out::println); // 메서드 참조 방식
System.out.println();
System.out.println("역순 정렬");
list.stream().sorted(Comparator.reverseOrder())
.forEach(System.out::println); // 메서드 참조 방식
System.out.println();
//일반 객체 정렬 테스트
Shape s1 = new Rectangle(10, 3);
Shape s2 = new Circle(10);
Shape s3 = new Rectangle(20, 2);
Shape s4 = new Circle(11);
List<Shape> list2 = Arrays.asList(s1, s2, s3, s4);
System.out.println("오름차순 정렬");
list2.stream().sorted().forEach(System.out::println);
System.out.println("내림차순 정렬");
list2.stream().sorted((a, b) -> b.compareTo(a) - a.compareTo(b))
.forEach(System.out::println);
System.out.println("내림차순 정렬2");
list2.stream().sorted(Comparator.reverseOrder())
.forEach(System.out::println);
// 둘레를 기준으로 정렬
System.out.println("정렬하지 않고 출력");
list2.stream().forEach(System.out::println);
System.out.println("둘레(length()) 순으로 정렬");
System.out.println("함수적 인터페이스로 구현");
list2.stream().sorted(new Comparator<Shape>() {
public int compare(Shape o1, Shape o2) {
return (int)(o1.length() - o2.length());
};
}).forEach(System.out::println);
System.out.println("람다표현식을 이용해서 둘레순으로 정렬");
list2.stream().sorted((a,b) -> (int)(b.length() - a.length()))
.forEach(System.out::println);
}
}
abstract class Shape implements Comparable<Shape> {
//필드
int x, y;
//생성자
Shape() {
this(0, 0);
}
Shape(int x, int y) {
this.x = x;
this.y = y;
}
//추상 메서드
abstract double area();
abstract double length();
//일반 메서드
public String getLocation() {
return "x: "+x+", y: "+y;
}
@Override
public int compareTo(Shape o) {
return (int)(this.area() - o.area());
}
}
class Rectangle extends Shape {
// 필드
int w, h;
//생성자
public Rectangle() {
this(1, 1);
}
public Rectangle(int w, int h) {
this.w = w;
this.h = h;
}
@Override
double area() {
return (w*h);
}
@Override
double length() {
return (w+h) * 2;
}
@Override
public String toString() {
return "넓이 : "+this.area();
}
}
class Circle extends Shape {
//필드
double r;
//생성자
public Circle() {
this(1);
}
public Circle(double r) {
this.r = r;
}
@Override
double area() {
return (r * r) * Math.PI;
}
@Override
double length() {
return (r * 2) * Math.PI;
}
@Override
public String toString() {
return "넓이는 : "+this.area();
}
}
- 그룹핑 : grouping
package G_java;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class G17_collect_groupBy {
// collect() 메서드는 스트림의 요소들을 필터링하거 매핑한 후에 새로운 객체로 생성
// groupingBy() 메서드는 Map객체를 생성할 수 있습니다.
public static void main(String[] args) {
Shape s1 = new Rectangle(10, 3);
Shape s2 = new Circle(10);
Shape s3 = new Rectangle(20, 2);
Shape s4 = new Circle(11);
List<Shape> list = Arrays.asList(s1, s2, s3, s4);
//요소가 Rectangle 객체인 경우 collect 메서드로 List로 변환
List<Shape> rectList = list.stream()
.filter(s -> s instanceof Rectangle).collect(Collectors.toList());
rectList.stream().forEach(f -> System.out.println(f));
System.out.println();
// 요소가 Rectangle 객체인 경우 collect 메서드로 Set으로 변환
Set<Shape> rectSet = list.stream()
.filter(s -> s instanceof Rectangle).collect(Collectors.toSet());
rectSet.stream().forEach(System.out::println); //메소드 접근 방법 -> 하나의 값을 넘겼을 때 그 함수 값을 실행시키세요!
//groupingBy() Map 객체 생성
//key-value 값으로 정의
try {
// 객체 타입으로 그룹핑 (Rectangle, Circle)
Map<Object, List<Shape>> map = list.stream() //obj -> 객체
.collect(Collectors.groupingBy(f -> f.getClass()));
System.out.println("사각형 출력");
map.get(Class.forName("Rectangle")).stream()
.forEach(f -> System.out.println(f));
map.get(Class.forName("Circle")).stream()
.forEach(f -> System.out.println(f));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
728x90
반응형
'개발 언어 > JAVA' 카테고리의 다른 글
17. Network, 서버 만들기! (0) | 2024.03.28 |
---|---|
16. ParallelStream, Thread (0) | 2024.03.27 |
14 람다식 (0) | 2024.03.25 |
13 객체 정렬을 위한 객체 간 크기 비교, 제너릭 , File 입출력 (0) | 2024.03.21 |
12 JAVA API (0) | 2024.03.20 |