연속적인 데이터의 흐름 또는 데이터를 전송하는 소프트웨어 모듈을 가리키며, 연속된 데이터의 단방향 흐름을 추상화한 것이다.
스트림은 자료의 입출력을 도와주는 중간 매개 역할을 하며 메모리의 원시 데이터를 프로그래머가 사용할 수 있는 데이터로 바꾸어주는 역할도 수행한다.
어느 한 쪽에서 다른 쪽으로 데이터를 전달하려면, 두 대상을 연결하고 데이터를 전송할 수 있게 하는 무언가가 필요한데 그 역할을 하는 것이 스트림이다.
예를 들어, 표준 입출력(System.out, System.in)은 키보드와 모니터를 대상으로 데이터를 읽고 쓰는 가장 기본적인 스트림이다. 프로그램과 외부 장치 및 파일 사이의 데이터 흐름도 스트림이다.
Java의 스트림은 바이트 스트림과 문자 스트림으로 구분된다.

① 선입선출
순차적으로 흘러가고 순차적으로 접근하기 때문에 스트림에 포함된 데이터의 순서는 변하지 않는다.
② 단방향
따라서 하나의 스트림으로 읽기와 쓰기가 동시 수행할 수 없다.
③ 메서드 제공
객체이므로 여러 유용한 메서드들이 제공된다.
④ 연결
// 키보드로부터 문자를 입력받기 위해 표준 입력 스트림인 System.in과 InputStreamReader를 연결
InputStreamReader rd = new InputStreamReader(System.in);
(ex) 출력 스트림의 출력을 입력 스트림의 입력으로 연결하여 파이프라인을 구성할 수 있다. 파이프라인으로 구성되면 스트림에 포함된 데이터를 다양한 방식으로 처리해 최종 스트림에 공급할 수 있다.
⑤ 지연가능성
(ex) 프로그램에 연결한 출력스트림에 데이터가 가득 차면 빈 공간이 생길 때까지 출력을 중단하고 지연된다, 데이터소스에 연결한 스트림이 가득 차면 프로그램이 데이터를 처리해서 빈 공간이 생길 때까지 지연된다.
Java의 스트림은 크게 바이트 스트림과 문자 스트림으로 나뉜다. 결론적으로 두 유형의 스트림은 데이터를 가공하는 방식만 다를 뿐 자료의 입출력을 byte단위로 처리하며 데이터 전송에 있어 중간 매개 역할을 수행한다.
바이트 단위로 데이터를 다루는 스트림.
스트림에 들어오고 나가는 정보를 단순 바이너리로 다루기 때문에 문자, 오디오, 이미지에 상관 없이 흘려 보낼 수 있다.
2바이트의 유니코드 문자 단위로 입출력하는 스트림
문자는 메모리에 byte단위로 저장되므로, 문자 입출력 시 byte 변환이 필요하다. 따라서 메모리 상의 바이트를 유니코드 문자로 변환해주는 역할을 문자 스트림이 수행한다.
문자 스트림은 바이트들을 전달받고 이 바이트들을 문자 집합에 있는 문자인지 비교한 뒤 문자로 변환한다.
데이터를 일시적으로 저장하는 임시 메모리 공간으로 주로 입출력 스트림 또는 네트워크 통신에서 데이터를 읽거나 쓸 때 사용된다.
크게 입력 버퍼와 출력 버퍼로 나뉜다.
BufferedReader, BufferedWriterBufferedInputStream, BufferedOutputStream 입출력 장치는 주 기억장치와는 다르게 매우 느리기 때문에 입출력 장치가 자주 동작할수록 효율이 떨어지고, 입출력 실행 속도가 떨어지게 된다(지연). 따라서 좀 더 효율적으로 수행을 위해 버퍼를 사용한다.