스트림 (stream)
중간연산
sorted()
정렬sorted(Comparator)
문자열스트림에만 있다. 사용법) 역순 -Comparator.reverseOrder()
distinct()
중복제거filter(predicate)
조건에 안 맞는 요소 제외. 예)filter(i -> i > 3)
3 보다 큰 요소 반환limit(long)
스트림의 일부를 잘라낸다. 예)limit(4)
일 경우 110 중 요소의 개수를 네개로 제한해 14 가 반환skip(long)
스트림의 일부를 건너뛴다. 예)skip(3)
일 경우 110 중 3까지를 건너뛰고 410 이 반환peek(Consumer)
요소에 작업수행map(mapper)
flatMap(mapper)
empty()
빈 스트림을 반환한다.concat(Stream a, Stream b)
스트림 a 와 b 를 연결한다.
최종연산
forEach(action)
forEachOrdered(action)
count()
long 스트림의 요소 반환max(comparator)
min(comparator)
findAny()
아무거나 하나findFirst()
첫 번째 요소allMatch(p)
불린반환. 모두 만족하는지anyMatch(p)
불린반환. 하나라도 만족하는지nonMatch(p)
불린반환. 모두 만족하지 않는지toArray()
toArray(generator)
배열로 반환reduce(accumulator)
요소를 하나씩 줄여가며 계산reduce(identity, accumulator)
reduce(identity, accumulator, combiner)
collect(collector)
스트림 요소 수집collect()supplier, accumulator, combiner)
IntStream
range(begin, end)
end 를 포함하지 않는다.rangeClosed(begin, end)
end 를 포함한다.sum()
최종연산이다.average()
최종연산이다.max()
최종연산이다.min()
최종연산이다.
출력 후 프린트
Arrays.stream(arr).sorted().forEach(System.out::print);
- 스트림은 데이터소스를 변경하지 않고 오직 읽기만 한다.
- 스트림은 일회용이다.
- Stream<Integer> 보다는 IntStream 이 더 효율적이고 유용한 메서드들이 많다.
스트림의 생성
Stream.of()
IntStream.of()
로 생성할 수 있다.
Random
ints()
ints(size)
크기지정 생성ints(begin, end)
난수범위지정 생성ints(size, begin, end)
크기와 범위지정 생성longs()
doubles()
limit(size)
무한스트림이므로 생성할 때 ints(size)
혹은 limit(size)
로 유한스트림으로 만들어야 한다.
문자열 배열을 정렬
Stream.of(str).sorted(Comparator.reverseOrder()).forEach(System.out::print);
최대값 반환
IntStream -> max() -> getAsInt()
배열
int max = Arrays.stream(arr).max().getAsInt();
리스트
int max = list.stream().mapToInt(i -> i).max().getAsInt();
int max = list.stream().max(Comparator.comparingInt(i -> i)).get();
인덱스 반환
List -> indexOf()
배열에서는 값을 찾아 인덱스를 반환하는 메서드가 없으므로 리스트로 변환 asList()
한다.
Arrays.asList(arr).indexOf(max);
println 에서 문자열이 하나라도 있으면 숫자끼리 더할 때 괄호에 넣어야 한다!!
2차원 배열
정렬
Arrays.sort(T[ ], Comparator)
Comparator.
comparingInt(ToIntFunction)
한값으로 정렬
Arrays.sort(sizes, Comparator.comparingInt(i -> i[0]));
두값으로 정렬
Arrays.sort(sizes, (a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) :
Integer.compare(a[0], b[0]));
출력
배열출력
for - each
for (int[] i : arr) System.out.println(Arrays.toString(i));
stream
Arrays.stream(sizes).forEach(i -> System.out.println(Arrays.toString(i)));
리스트출력
for - each
for (Integer i : list) System.out.println(i);
함수
list.forEach(System.out::println);
배열출력은 for - each 가 더 짧고 리스트출력은 함수가 더 짧다.
람다식과 함수
선언방법
(매개변수 선언) -> {문장들}
반환값이 있는경우 식으로 작성할 수 있고 연산결과가 자동적으로 반환값이 된다. 이때는 세미콜론 ( ; ) 을 붙이지 않는다.
(int a, int b) -> a > b ? a : b
return 과 세미콜론 ( ; ) 이 사라진 것을 볼 수 있다.
람다식에서 매개변수의 타입은 추론이 가능한 경우 생략이 가능하다.
매개변수가 하나뿐이라면 괄호를 생략할 수 있지만 타입이 있으면 생략할 수 없다.
괄호안이 return 일 경우 중괄호 { } 를 생략할 수 없다.
매개변수가 없거나 하나
인터페이스 | 매개변수 | 반환값 |
---|---|---|
Runnable | X | X |
Supplier | X | O |
Consumer | O | X |
Function | O | O |
Predicate | O | boolean |
메게변수가 두개
인터페이스 | 매개변수 | 반환값 |
---|---|---|
BiConsumer | 2 | X |
BiPredicate | 2 | boolean |
BiFunction | 2 | O |
Operator
인터페이스 | 매개변수 | 반환값 |
---|---|---|
UnaryOperator | O | O |
BinaryOperator | 2 | O |
Operator 들은 매개변수타입과 반환타입이 같다는 점을 제외하고는 Function 과 같다.
Collection Framework
인터페이스 | 메서드 | 설명 |
---|---|---|
Collection | removeIf(Predicate) | 조건에 맞는요소 삭제 |
List | replaceAll(UnaryOperator) | 모든요소를 변환하여 대체 |
Iterable | forEach(Consumer) | 모든요소에 작업 action 수행 |
Map | compute(key, BiFunction) | 지정된 키의 값에 작업수행 |
computeIfAbsent(key, Function) | 키가 없으면 작업수행 후 추가 | |
computeIfPresent(key, BiFunction) | 지정된 키가 있을 때 작업수행 | |
merge(key, value, BiFunction) | 모든 요소에 병합작업 수행 | |
forEach(BiConsumer) | 모든 요소에 작업 action 수행 | |
replaceAll(BiFunction) | 모든 요소에 치환작업 수행 |
기본형을 사용하는 함수형 인터페이스
인터페이스 | 입력 | 출력 |
---|---|---|
A To B Function | A | B |
To B Function | T | B |
A Function | A | T |
obj A Consumer | T, A | X |
프로그래머스 강의
작성날짜: 10/4
내부클래스
printCar(cars, new CheckCarForBigAndNotExpensive());
static class CheckCarForBigAndNotExpensive implements CheckCar{
public boolean test(Car car){
return car.capacity >= 4 && car.price < 2500;
}
}
익명클래스
printCar(cars, new CheckCar(){
public boolean test(Car car){
return car.capacity >= 4 && car.price < 2500;
}
});
람다
carExam.printCar(cars, car -> car.capacity >= 4 && car.price < 2500);
람다식을 사용하면 이렇게 코드가 간단해집니다.
전체코드
출력
봉고차
중간차
코드
public class CarExam{
public static void main(String[] args){
//Car객체를 만들어서 cars에 넣습니다.
List<Car> cars = new ArrayList<>();
cars.add( new Car("작은차",2,800,3) );
cars.add( new Car("봉고차",12,1500,8) );
cars.add( new Car("중간차",5,2200,0) );
cars.add( new Car("비싼차",5,3500,1) );
CarExam carExam = new CarExam();
carExam.printCar(cars, car -> car.capacity >= 4 && car.price < 2500);
}
public void printCar(List<Car> cars, CheckCar tester){
for(Car car : cars){
if (tester.test(car)) {
System.out.println(car);
}
}
}
interface CheckCar{
boolean test(Car car);
}
}
정렬
작성날짜: 9/29
Arrays.sort() 메서드에서 자료형이
T[ ]
가 아니라면 Comparator 를 사용해 내림차순 정렬을 할 수 없다.기본형은 Comparator 를 사용할 수 없는 모양이다.
int[] arr = {3, 2, 5, 1, 4};
// Arrays.sort(arr, Comparator.comparingInt(i -> i)); 에러
Integer[] arr = {3, 2, 5, 1, 4};
Arrays.sort(arr, Comparator.comparingInt(i -> i));
Arrays.stream(arr)
메서드에는char[ ]
short[ ]
float[ ]
배열을 넣을 수 없다.
char[] charArr = new char[5];
short[] shortArr = new short[5];
float[] floatArr = new float[5];
// Arrays.stream(charArr); 에러
// Arrays.stream(shortArr); 에러
// Arrays.stream(floatArr); 에러
- String 을 글자단위로 나누려면
split()
메서드로 String 배열로 혹은chars()
메서드로 IntStream 으로 만든다. - CharSequence 의 자손으로는 String, StringBuilder, StringBuffer, CharBuffer 등이 있다.
new String()
생성자에는 String, StringBuilder, StringBuffer,char[ ]
배열이 들어올 수 있다.int[ ]
배열에는 char 를 넣을 수 있다.- 하지만
str.toCharArray()
는int[ ]
배열에도 ArrayList 에도 담을 수 없다.
정렬이 있는 모든 자료구조는 Comparable 인터페이스를 상속받고 있으므로 Arrays.sort(배열)
로 정렬이 가능하고
객체는 Comparable 인터페이스를 상속받아 compareTo 메서드를 오버라이딩해서 정렬할 수 있다.
int 형 2차원 배열
내림차순
Arrays.sort(arr, (o1, o2) -> o2[1] - o1[1]);
오름차순
Arrays.sort(arr, (o1, o2) -> o1[1] - o2[1]);
Arrays.sort(arr, Comparator.comparingInt(i -> i[1]));
Integer 형 배열
내림차순
[5, 4, 3, 2, 1]
Integer[] arr = { 3, 1, 2, 5, 4 };
Arrays.sort(arr, Comparator.reverseOrder());
Integer 형 리스트
내림차순
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(new Integer[] {3, 1, 2, 5, 4}));
list.sort(Comparator.reverseOrder());
객체배열 정렬
main
Point[] arr = {
new Point(2, 4)
, new Point(1, 3)
, new Point(2, 5)
, new Point(4, 1)
, new Point(2, 2)
, new Point(3, 6)
};
Arrays.sort(arr);
오름차순
[1,3]
[2,4]
[2,5]
[2,2]
[3,6]
[4,1]
@Override
public int compareTo(Point o) {
return x - o.x;
}
내림차순
[4,1]
[3,6]
[2,4]
[2,5]
[2,2]
[1,3]
@Override
public int compareTo(Point o) {
return o.x - x;
}
전체코드
public class Main {
public static void main(String[] args) {
Point[] arr = {
new Point(2, 4)
, new Point(1, 3)
, new Point(2, 5)
, new Point(4, 1)
, new Point(2, 2)
, new Point(3, 6)
};
Arrays.sort(arr);
for (Point p : arr) System.out.println(p);
}
}
class Point implements Comparable<Point> {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return String.format("[%d,%d]", x, y);
}
@Override
public int compareTo(Point o) {
return x - o.x;
}
}
x 오름차순 후 y 오름차순
[1,3]
[2,2]
[2,4]
[2,5]
[3,6]
[4,1]
@Override
public int compareTo(Point o) {
return x != o.x ? x - o.x : y - o.y;
}
문자열인 경우
입력
Point[] arr = {
new Point("a", "b")
, new Point("a", "f")
, new Point("a", "c")
, new Point("d", "e")
, new Point("f", "a")
, new Point("d", "a") };
출력
[a,b]
[a,c]
[a,f]
[d,a]
[d,e]
[f,a]
코드
@Override
public int compareTo(Point o) {
return !x.equals(o.x) ? x.compareTo(o.x) : y.compareTo(o.y);
}
long 형 숫자 정렬
내림차순으로 정렬한다.
입력
long n = 554372812;
출력: long 형으로 반환할 것
875543221
오름차순 정렬 후 for 문
char[ ] 배열에서 오름차순 정렬 후 for 문으로 뒤집는다.
char[] arr = String.valueOf(n).toCharArray();
Arrays.sort(arr);
int len = arr.length;
for (int i = 0; i < len/2; i++) {
char temp = arr[i];
arr[i] = arr[len -1 -i];
arr[len -1 -i] = temp;
}
long answer = Long.parseLong(new String(arr));
스트림
IntStream 에 담아 내림차순 정렬 후 int[ ]
배열에 담아 char[ ]
배열로 옮겨담아 출력한다.
int[] intArr = String.valueOf(n).chars().boxed().sorted((i1, i2) -> i2 - i1).mapToInt(it -> it).toArray();
char[] charArr = new char[intArr.length];
for (int i = 0; i < intArr.length; i++)
charArr[i] = (char) intArr[i];
long answer = Long.parseLong(new String(charArr));
오름차순 정렬 후 StringBuilder 의 reverse() 메서드
char[ ] 배열을 StringBuilder 의 reverse() 메서드로 뒤집고 출력한다.
char[] arr = String.valueOf(n).toCharArray();
Arrays.sort(arr);
String str = new StringBuilder(new String(arr)).reverse().toString();
long answer = Long.parseLong(str);
자료구조
StringBuffer
한글자씩 더하기 좋다.
List
순서가 있다.
Stack
가장 먼저넣은 것을 가장 늦게 꺼낸다.
Queue
가장 먼저넣은 것을 가장 먼저 꺼낸다.
Deque
양쪽에서 넣고 뺄 수 있다.
PriorityQueue
숫자가 작거나 큰 순서대로 꺼낸다. Heap ?
Set
중복이 없다.
TreeSet
정렬에 좋은 Set
LinkedHashSet
순서가 있는 Set
Map
key 는 중복이 없고 value 는 중복이 있다.
성능비교
String split vs substring, indexOf
split
56.484092 sec
String path = "C:\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29";
long start = System.nanoTime();
for (int i = 0; i < 100000000; i++)
String name = path.split("\\\\")[20];
long end = System.nanoTime();
System.out.printf("%f sec\n", (end - start) / pow(10, 9));
substring, indexOf
1.085399 sec
String path = "C:\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29\\class\\javaClass\\javaPro\\src\\days29";
long start = System.nanoTime();
for (int i = 0; i < 100000000; i++) {
String name = path.substring(path.lastIndexOf("\\"));
}
long end = System.nanoTime();
System.out.printf("%f sec\n", (end - start) / pow(10, 9));
압도적으로 substring, indexOf 가 split 보다 성능이 좋다.
타입변환
작성날짜: 10/11
int[ ] -> List<Integer>
map
Arrays.stream(arr).mapToObj(i -> i).toList();
collect
Arrays.stream(arr).boxed().collect(Collectors.toList());
List<Integer> -> int[ ]
amp
list.stream().mapToInt(i -> i).toArray();
BigInteger
생성자
(String)
(String, radix)
ex) ("FFFF", 16) -> 16진수를 10진수로 변환
radix: n 진수
혹은
BigInteger.valueOf(long)
으로 생성할 수도 있다.
DFS
한번씩 방문
public class Main {
private static int N = 5;
static boolean[] visited = new boolean[6];
public static void main(String[] args) {
dfs(1);
}
private static void dfs(int i) {
if (!visited[i]) {
visited[i] = true;
if (i < N) dfs(i + 1);
visited[i] = false;
}
}
}
디버그 해보면 이해하기 쉽다.