How System.out.println() really works

本文深入探讨了Java中System.out.println()方法的工作原理,从System.out的初始化过程开始,逐步剖析了println()方法如何通过一系列类和方法调用最终将字符串输出到控制台的过程。

How System.out.println() really works

A few days ago I came across an interesting article, Where the printf() Rubber Meets the Road, describing how the printf function ‘works’ on the low level.

Commonly asked by Java beginners is the question, “How does System.out.println() work?”; the above blog post inspired me to do some research into this question. In this blog post I’ll attempt to provide an explanation of what System.out.println() does behind the scenes.

Most of the relevant code can be found on OpenJDK, which is the primary implementation of Java itself. System.out.println() may be implemented completely differently on other Java platforms.

I will warn you now that this article is very long and not for the easily bored.

First steps

Our first step in figuring out how System.out.println works is by first understanding what System.out is and how it came to be.

Let’s take a look through the OpenJDK’s Mercurial online repository. Digging around a bit, we find System.java. In this file System.out is declared:

public  final  static  PrintStream out = nullPrintStream();

But when we find the code for nullPrintStream():

private  static  PrintStream nullPrintStream() throws  NullPointerException {
     if  (currentTimeMillis() >  0 ) {
         return  null ;
     }
     throw  new  NullPointerException();
}

So nullPrintStream() simply returns null or throws an exception. This can’t be it. What’s going on here?

The answer can be found in the function initializeSystemClass(), also in System.java:

FileOutputStream fdOut =  new FileOutputStream(FileDescriptor.out);
setOut0( new  PrintStream( new BufferedOutputStream(fdOut,  128 ),  true ));

There’s a lot of stuff going on in this code. I’m going to refer back to this two lines of code later, but setOut0() is what actually initializes System.out.

The function setOut0() is a native function. We can find its implementation in System.c:

JNIEXPORT  void  JNICALL
Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
{
     jfieldID fid =
         (*env)->GetStaticFieldID(env,cla, "out" , "Ljava/io/PrintStream;" );
     if  (fid ==  0 )
         return ;
     (*env)->SetStaticObjectField(env,cla,fid,stream);
}

This is pretty standard JNI code that sets System.out to the argument passed to it.

At first all this deal with setting System.out to nullPrintStream() and later setting it with JNI seems entirely unnecessary. But this is actually justified.

In Java, static fields are initialized first, and everything else comes after. So even before the JVM and the System class is fully initialized, the JVM tries to initialize System.out.

Unfortunately at this point the rest of the JVM isn’t properly initialized so it’s impossible to reasonably set System.out at this point. The best that could be done would be to set it to null.

The System class, along with System.out is properly initialized in initializeSystemClass() which is called by the JVM after static and thread initialization.

There is a problem, however. System.out is final, meaning we cannot simply set it to something else in initializeSystemClass(). There’s a way around that, however. Using native code, it is possible to modify a final variable.

Wait, what’s a FileDescriptor?

Notice this line of code:

FileOutputStream fdOut =  new FileOutputStream(FileDescriptor.out);

A FileOutputStream object is created from something referred to as FileDescriptor.out.

The FileDescriptor class, though part of java.io, is rather elusive. It can’t be found in the java.io directory in OpenJDK.

This is because FileDescriptor is much lower level than most of the Java standard library. While most .java files are platform independent, there are actually different implementations of FileDescriptor for different platforms.

We’ll be using the Linux/Solaris version of FileDescriptor.java.

A FileDescriptor object is very simple. Essentially all it really holds is an integer. It holds some other data too, which aren’t really important. The constructor of FileDescriptor takes an integer and creates a FileDescriptor containing that integer.

The only use of a FileDescriptor object is to initialize a FileOutputStream object.

Let’s see how FileDescriptor.out is defined:

public  static  final  FileDescriptor out =  new FileDescriptor( 1 );

FileDescriptor.out is defined as 1, in as 0, and err as 2. The basis of these definitions are from a very low level somewhere in Unix.

We now know how System.out is initialized. For now, we’re going to leave behind the FileDescriptor; we only need to know what it does.

A tour through java.io

Now we redirect our attentions to the println() function of PrintStream.

PrintStream is a comparably higher level class, capable of writing many different kinds of data, flushing and handling errors for you without much effort.

Let’s see how println() is defined in PrintStream.java:

public  void  println(String x) {
     synchronized  ( this ) {
         print(x);
         newLine();
     }
}

Following the call stack to print():

public  void  print(String s) {
     if  (s ==  null ) {
         s =  "null" ;
     }
     write(s);
}

Going deeper, and looking at write():

private  void  write(String s) {
     try  {
         synchronized  ( this ) {
             ensureOpen();
             textOut.write(s);
             textOut.flushBuffer();
             charOut.flushBuffer();
             if  (autoFlush && (s.indexOf( '\n' ) >= 0 ))
                 out.flush();
         }
     }
     catch  (InterruptedIOException x) {
         Thread.currentThread().interrupt();
     }
     catch  (IOException x) {
         trouble =  true ;
     }
}

Internally, the PrintStream object (System.out) contains three different objects to do its work:

  • The OutputStreamWriter object (charOut), writing character arrays into a stream
  • The BufferedWriter object (textOut), writing not only character arrays but also strings and text
  • A BufferedOutputStream object (out), passed all the way down the call stack and used much lower then at the PrintStream level

We can see that PrintStream.write() calls BufferedWriter.write() and flushes both buffers. I’m not sure why it’s necessary to flush the charOut buffer, so I’m going to ignore that.

Delving deeper, let’s find the implementation of write() inBufferedWriter.java.. wait it’s not here. The function write(String) is actually defined in the abstract class Writer.java:

public  void  write(String str)  throws  IOException {
     write(str,  0 , str.length());
}

Moving back to BufferedWriter:

public  void  write(String s,  int  off,  int  len) throws  IOException {
     synchronized  (lock) {
         ensureOpen();
 
         int  b = off, t = off + len;
         while  (b < t) {
             int  d = min(nChars - nextChar, t - b);
             s.getChars(b, b + d, cb, nextChar);
             b += d;
             nextChar += d;
             if  (nextChar >= nChars)
                 flushBuffer();
         }
     }
}

As its name suggests, BufferedWriter is buffered. Data is stored in a data buffer until it’s written all at once, or flushed. Buffered IO is much faster than simply writing to the hardware one byte at a time.

The function BufferedWriter.write() doesn’t actually write anything. It only stores something in an internal buffer. The flushing is not done here, but back at PrintStream.write().

Let’s go to flushBuffer(), in the same file:

void  flushBuffer()  throws  IOException {
     synchronized  (lock) {
         ensureOpen();
         if  (nextChar ==  0 )
             return ;
         out.write(cb,  0 , nextChar);
         nextChar =  0 ;
     }
}

We find yet another write() call, on a Writer object (out). The out object here is the charOut object of PrintStream, and has the type OutputStreamWriter. This object is also the same object as charOut in PrintStream.

Let’s look at OutputStreamWriter.write() in OutputStreamWriter.java:

public  void  write( char  cbuf[],  int  off,  int  len) throws  IOException {
     se.write(cbuf, off, len);
}

This now transfers the job to another object, se. This object is of type sun.nio.cs.StreamEncoder. We’re going to leave the java.io directory for a while.

Let’s see the implementation of StreamEncoder.write() inStreamEncoder.java:

public  void  write( char  cbuf[],  int  off,  int  len) throws  IOException {
     synchronized  (lock) {
         ensureOpen();
         if  ((off <  0 ) || (off > cbuf.length) || (len <  0 ) ||
                 ((off + len) > cbuf.length) || ((off + len) <  0 )) {
             throw  new  IndexOutOfBoundsException();
         else  if  (len ==  0 ) {
             return ;
         }
         implWrite(cbuf, off, len);
     }
}

Moving on to StreamEncoder.implWrite():

void  implWrite( char  cbuf[],  int  off,  int  len)
     throws  IOException
{
     CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
 
     if  (haveLeftoverChar)
         flushLeftoverChar(cb,  false );
 
     while  (cb.hasRemaining()) {
         CoderResult cr = encoder.encode(cb, bb, false );
         if  (cr.isUnderflow()) {
             assert  (cb.remaining() <=  1 ) : cb.remaining();
             if  (cb.remaining() ==  1 ) {
                 haveLeftoverChar =  true ;
                 leftoverChar = cb.get();
             }
             break ;
         }
         if  (cr.isOverflow()) {
             assert  bb.position() >  0 ;
             writeBytes();
             continue ;
         }
         cr.throwException();
     }
}

Again this calls another function, writeBytes(). Here’s the implementation:

private  void  writeBytes()  throws  IOException {
     bb.flip();
     int  lim = bb.limit();
     int  pos = bb.position();
     assert  (pos <= lim);
     int  rem = (pos <= lim ? lim - pos :  0 );
 
     if  (rem >  0 ) {
         if  (ch !=  null ) {
             if  (ch.write(bb) != rem)
                 assert  false  : rem;
         else  {
             out.write(bb.array(), bb.arrayOffset() + pos, rem);
         }
     }
     bb.clear();
}

We’re done with StreamEncoder. This class essentially processes or encodes character streams, but ultimately delegates the task of writing the bytes back to BufferedOutputStream.

Let’s take a look at the code for write() in BufferedOutputStream.java:

public  synchronized  void  write( byte  b[],  int  off, int  len)  throws  IOException {
     if  (len >= buf.length) {
         /* If the request length exceeds the size of the output buffer,
            flush the output buffer and then write the data directly.
            In this way buffered streams will cascade harmlessly. */
         flushBuffer();
         out.write(b, off, len);
         return ;
     }
     if  (len > buf.length - count) {
         flushBuffer();
     }
     System.arraycopy(b, off, buf, count, len);
     count += len;
}

And BufferedOutputStream passes the baton again, this time to FileOutputStream. Remember when we instantiated fdOut as a FileOutputStream? Well, this is it, passed down through dozens of system calls.

Believe it or not, FileOutputStream is the final layer before JNI. We see the function write() in FileOutputStream.java:

public  void  write( byte  b[],  int  off,  int  len) throws  IOException {
     writeBytes(b, off, len);
}

And writeBytes():

private  native  void  writeBytes( byte  b[],  int  off, int  len)  throws  IOException;

We’ve reached the end of the Java part. But we’re not quite finished.

A Review of the java.io call stack

This is a ‘contains’ chart:

Also here’s the entire call stack:

Stepping into the JNI

After FileOutputStream, the writing of bytes to the console is handled natively. Much of this native code is platform dependent: there are different versions of the code for Windows and Linux. We’re going to deal with the Linux versions first.

The native implementation of writeBytes() is defined inFileOutputStream_md.c.

JNIEXPORT  void  JNICALL
Java_java_io_FileOutputStream_writeBytes(JNIEnv *env,
     jobject  this , jbyteArray bytes, jint off, jint len) {
     writeBytes(env,  this , bytes, off, len, fos_fd);
}

The field fos_fd is the integer stored in the FileDescriptor object that we’ve visited so long ago. So for the out stream, fos_fd should be 1.

We’re just calling a method, writeBytes, with the additional argument of fos_id. The implementation of writeBytes() is defined in io_util.c:

void
writeBytes(JNIEnv *env, jobject  this , jbyteArray bytes,
            jint off, jint len, jfieldID fid)
{
     jint n;
     char  stackBuf[BUF_SIZE];
     char  *buf = NULL;
     FD fd;
 
     if  (IS_NULL(bytes)) {
         JNU_ThrowNullPointerException(env, NULL);
         return ;
     }
 
     if  (outOfBounds(env, off, len, bytes)) {
         JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException" , NULL);
         return ;
     }
 
     if  (len == 0) {
         return ;
     else  if  (len > BUF_SIZE) {
         buf =  malloc (len);
         if  (buf == NULL) {
             JNU_ThrowOutOfMemoryError(env, NULL);
             return ;
         }
     else  {
         buf = stackBuf;
     }
 
     (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf);
 
     if  (!(*env)->ExceptionOccurred(env)) {
         off = 0;
         while  (len > 0) {
             fd = GET_FD( this , fid);
             if  (fd == -1) {
                 JNU_ThrowIOException(env,  "Stream Closed" );
                 break ;
             }
             n = IO_Write(fd, buf+off, len);
             if  (n == JVM_IO_ERR) {
                 JNU_ThrowIOExceptionWithLastError(env, "Write error" );
                 break ;
             else  if  (n == JVM_IO_INTR) {
                 JNU_ThrowByName(env, "java/io/InterruptedIOException" , NULL);
                 break ;
             }
             off += n;
             len -= n;
         }
     }
     if  (buf != stackBuf) {
         free (buf);
     }
}

The writing here is done by a method called IO_Write. At this point, what happens next becomes platform dependent, as IO_Write is defined differently for Windows and Linux.

The Linux Way

The linux way of handling IO uses the HPI (Hardware Platform Interface). Thus, the method is defined as JVM_Write in io_util_md.h:

#define IO_Write JVM_Write

The code form JVM_Write is defined in the JVM itself. The code is not Java, nor C, but it’s C++. The method can be found in jvm.cpp:

JVM_LEAF(jint, JVM_Write(jint fd,  char  *buf, jint nbytes))
   JVMWrapper2( "JVM_Write (0x%x)" , fd);
 
   //%note jvm_r6
   return  (jint)hpi::write(fd, buf, nbytes);
JVM_END

The writing is now done by various HPI methods. Although you could go further, I’m going to stop here, since we’re now so far from where we started.

The Way of Windows

In Windows, the method IO_Write is routed away from the HPI layer. Instead, it’s redefined as handleWrite in io_util_md.h.

The implementation for handleWrite() is defined in io_util_md.c:

JNIEXPORT
size_t
handleWrite(jlong fd,  const  void  *buf, jint len)
{
     BOOL  result = 0;
     DWORD  written = 0;
     HANDLE  h = ( HANDLE )fd;
     if  (h != INVALID_HANDLE_VALUE) {
         result = WriteFile(h,            /* File handle to write */
                       buf,               /* pointers to the buffers */
                       len,               /* number of bytes to write */
                       &written,          /* receives number of bytes written */
                       NULL);             /* no overlapped struct */
     }
     if  ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
         return  -1;
     }
     return  written;
}

The WriteFile function is in the Windows API. The Windows API is not open source, so we would have to stop here.

Conclusion

We’ve taken a tour through the entire call stack of System.out.println(), from the instantiation of System.out to the path through java.io, all the way down to JNI and HPI level IO handling.

We haven’t even reached the end. No doubt there’s dozens more levels underneath the HPI layer and the WriteFile API call.

Perhaps the better answer to the question, “how does System.out.println() work” would be “it’s magic”.

"foreach(system.out::println)" 的意思是对于某个集合中的每一个元素,都执行一次 "system.out::println" 操作,其中 "system.out::println" 表示将括号中的内容打印到控制台上。 例如,在 Java 中,可以使用以下代码对一个整数数组进行遍历,并将每个元素打印到控制台上: ```java int[] arr = {1, 2, 3, 4, 5}; for (int num : arr) { System.out.println(num); } ``` 输出结果为: ``` 1 2 3 4 5 ``` 以上代码中,"foreach" 循环使用了冒号 ":" 来遍历整个数组,将每个元素都赋值给变量 "num",然后将其打印到控制台上。"foreach(system.out::println)" 是一个伪代码,它并没有明确的含义。但是,从语法上来看,它似乎是用于循环迭代某个集合并将其中的元素输出到控制台。 在Java编程语言中,如果想要使用foreach语句来迭代一个集合并将其中的元素输出到控制台,可以使用以下代码: ``` for (Object obj : collection) { System.out.println(obj); } ``` 其中,`collection`表示要迭代的集合对象,`Object`是集合中元素的类型。在循环的每一次迭代中,都会将集合中的一个元素赋值给`obj`变量,然后将该变量的值输出到控制台。"foreach(system.out::println)" 这个语句是一个伪代码,但是可以猜测它的意思是遍历一个集合(collection)中的元素,并且对于每个元素,使用 "system.out::println" 方法将其打印输出到控制台。在Java中,这个语句可以用类似以下的代码实现: ``` List<String> list = Arrays.asList("foo", "bar", "baz"); list.forEach(System.out::println); ``` 这个例子中,我们创建了一个包含三个字符串的列表,并且使用 `forEach` 方法遍历了这个列表中的每个元素。在 `forEach` 方法中,我们使用 `System.out::println` 方法将每个元素打印输出到控制台。"foreach(system.out::println)" 的意思是使用 Java 语言中的 foreach 循环遍历某个集合或数组,并将每个元素作为参数传递给 System.out.println() 方法进行输出。 例如,以下代码片段使用 foreach 循环遍历一个整型数组,并将每个元素输出到控制台: ``` int[] nums = {1, 2, 3, 4, 5}; for (int num : nums) { System.out.println(num); } ``` 输出结果为: ``` 1 2 3 4 5 ``` 这里的 `System.out.println(num)` 将每个元素依次输出到控制台,其中 `System.out` 是 Java 中用于输出的标准输出流,`println` 是输出一个字符串并换行的方法。foreach(system.out::println) 是一段伪代码,它的意思是对于集合中的每个元素,都执行 system.out.println 方法,也就是将每个元素打印到控制台上。在实际的编程语言中,具体的语法和用法可能会有所不同,需要根据具体的语言来确定。foreach(system.out::println) 这段代码看起来像是Java语言中的Lambda表达式,它的作用是将一个集合中的每个元素都输出到控制台。其中,system.out::println表示调用System.out对象的println方法。通常情况下,需要在foreach前面指定要遍历的集合对象,例如: List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); list.forEach(System.out::println); 以上代码会将集合中的每个元素依次输出到控制台。"foreach(system.out::println)" 是一个Java语言中的代码片段,意思是对于集合中的每一个元素,使用 System.out.println() 方法打印输出。"foreach(system.out::println)" 的意思是使用 Java 编程语言中的 foreach 循环来遍历某个集合,并对集合中的每个元素执行 "system.out::println" 操作,即将元素输出到控制台。其中的 "system.out" 表示标准输出流,"println" 表示将元素作为字符串输出并自动换行。"foreach(system.out::println)" 的意思是使用一个循环遍历某个集合,对集合中的每个元素都执行 "system.out::println" 的操作,即在控制台上输出该元素。这是一种Java语言中的写法,可以用来遍历数组或集合等容器。这段代码是Java语言中用于循环遍历集合中每个元素,并将其输出到控制台上的语法。 具体来说,"foreach"是Java中的增强型for循环语句,可以简化遍历集合或数组的代码编写。在这段代码中,"system.out::println"是Java 8中引入的方法引用语法,表示调用"System.out.println()"方法将元素输出到控制台上。因此,这段代码的作用是将集合中的每个元素都输出到控制台上,以便于调试或观察程序运行时的状态。 您好,很高兴能在这里为您服务。foreach(system.out::println) 是一个伪代码,它可能表示使用 foreach 循环遍历某个集合(collection),并对集合中的每个元素调用 system.out.println 方法进行输出。在 Java 中,这个伪代码可以表示为以下代码: ``` for (Object obj : collection) { System.out.println(obj); } ``` 其中,collection 是一个集合对象,Object 是集合中元素的类型。这段代码会遍历集合中的每个元素,并对每个元素调用 System.out.println 方法,将其输出到控制台。 您好,我是ChatGPT,很高兴能在这里为您服务。 你好!我是ChatGPT,一个由OpenAI训练的大型语言模型。这是一行Java代码,意思是对某个集合(例如一个数组)中的每个元素执行一个操作,这里的操作是输出到控制台。其中system.out是Java的标准输出流对象,println是输出并换行的方法。因此,这段代码的作用是遍历集合中的每个元素,并输出到控制台上。foreach(system.out::println) 是一个伪代码,可以理解为“对于列表中的每个元素,执行system.out.println操作”。 在Java中,可以使用foreach循环来实现这个操作,示例如下: ``` List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); for (String str : list) { System.out.println(str); } ``` 这段代码的输出结果为: ``` hello world ``` 其中,for (String str : list) 表示遍历list中的每个元素,并将元素赋值给str变量;System.out.println(str) 表示输出str变量的值。 你好!我可以为你提供帮助吗?"foreach(system.out::println)" 这个语句看起来像是 Java 语言中的语法,它的作用是遍历某个集合(比如数组、列表等)中的元素,并将每个元素都打印输出到控制台。 更具体地说,"system.out::println" 表示调用 Java 标准库中 System 类的 out 静态成员变量,该成员变量代表标准输出流,然后再调用该对象的 println 方法,将传入的参数打印输出到控制台。 因此,"foreach(system.out::println)" 的含义就是遍历某个集合,对于集合中的每个元素,都调用 System 类的 out 变量的 println 方法将其打印输出到控制台。 欢迎使用ChatGPT!我能够理解不同的语言,无论是中文还是其他语言。 欢迎来到ChatGPT!我可以为您提供关于各种主题的帮助,请问您想要了解什么?"foreach(system.out::println)" 的意思是使用foreach循环遍历某个集合(如数组、列表等),并对每个元素执行System.out.println()方法,将其输出到控制台。换句话说,这行代码可以用于输出集合中所有元素的值到控制台。这段代码是Java编程语言中的语法。它表示对一个集合中的每一个元素执行一段操作,其中system.out::println表示输出每一个元素到控制台。可以将它翻译成“对于集合中的每个元素,输出它到控制台”。"foreach(system.out::println)" 是一个类似于Java代码的语句,它的意思是对某个集合中的每个元素执行一次"system.out::println"方法,即在控制台打印出该元素的值。这个代码片段是一个Java语言中的循环语句,它可以用来遍历一个集合(例如一个数组或者列表)中的所有元素,并且对每个元素执行指定的操作,这里是使用系统输出函数 System.out.println() 打印出来。因此,这行代码的意思是:对于集合中的每个元素,都执行一次 System.out.println() 函数来将其打印出来。"foreach(system.out::println)" 是一个代码片段,使用 Java 语言编写。它的作用是将一个列表中的元素逐个输出到控制台。具体实现可以参考下面的示例代码: ``` List<String> list = Arrays.asList("apple", "banana", "orange"); list.forEach(System.out::println); ``` 以上代码中,首先创建了一个包含三个字符串的列表,然后调用 `forEach` 方法,将 `System.out::println` 作为参数传入。这个方法会遍历列表中的每个元素,并将其作为参数传递给 `System.out::println` 方法,实现逐个输出到控制台的效果。"foreach(system.out::println)" 是一段伪代码,大概的意思是对一个集合中的每个元素,都执行一次"system.out::println"操作,即输出该元素。在Java语言中,可以使用以下方式实现该功能: ``` List<String> list = Arrays.asList("apple", "banana", "orange"); list.forEach(System.out::println); ``` 以上代码会输出集合中的每个元素。"foreach(system.out::println)" 是一个伪代码,通常用于描述一个循环迭代的过程,其中对于每个元素,都会执行 "system.out::println" 这个动作。 "system.out::println" 是Java编程语言中输出文本到控制台的语法,可以将括号内的内容输出到屏幕上。因此,"foreach(system.out::println)" 可以被理解为对于迭代的每个元素,都将其输出到控制台上。"foreach(system.out::println)" 是一个Java语言中的语句,它的作用是遍历一个集合中的元素,并对每个元素执行 "system.out::println" 操作,也就是将该元素输出到控制台。这个操作可以用Lambda表达式来实现,例如: ``` List<String> list = Arrays.asList("a", "b", "c"); list.forEach(System.out::println); ``` 这段代码会遍历列表中的每个元素,然后依次输出到控制台。foreach(system.out::println) 是一个伪代码,它的意思是对于集合中的每个元素,都执行一次 system.out.println() 方法,即将该元素打印到控制台上。这是一种常见的在编程语言中遍历集合并输出其中元素的方法。"foreach(system.out::println)" 是一段代码,它的作用是对一个集合中的每个元素执行一次system.out::println操作,即将每个元素打印输出到控制台。"foreach(system.out::println)" 是一个代码片段,使用的是 Java 编程语言。它的作用是遍历一个集合(如数组或列表),并将集合中的每个元素打印到控制台上。其中 "system.out::println" 是一个方法引用,表示调用 System 类的 out 静态成员变量的 println 方法。"foreach(system.out::println)" 这段代码是Java中的语法,意思是对于一个集合中的每一个元素,都执行一遍system.out::println方法。其中,system.out::println是Java中的标准输出方法,可以将括号中的内容输出到控制台。"foreach(system.out::println)" 是一个Java语言中的语法结构,用于遍历某个集合并对其中的每个元素执行一些操作,这里的操作是将元素输出到控制台。 具体而言,这行代码的意思是将一个集合(或数组)中的所有元素都输出到控制台,使用System.out.println方法实现输出操作。"foreach(system.out::println)" 这段代码看起来像是Java中的语句,意思是将一个数组或者集合中的每个元素都输出到控制台(即标准输出),可以理解为一个循环语句。其中,"system.out::println" 表示输出语句,用于将括号内的内容输出到控制台。这段代码看起来像是Java语言的语法,其中: - foreach是一个关键字,表示对集合中的每个元素执行某个操作; - system.out是一个静态属性,表示标准输出流,通常用来在控制台输出信息; - println是一个方法,表示输出字符串并换行。 因此,这段代码的意思是将集合中的每个元素输出到控制台并换行。这段代码是Java语言的语法,用于遍历一个集合中的元素并输出到控制台。 其中,"foreach"是Java 8引入的一种新的遍历方式,可以用来遍历集合中的元素。"system.out::println"是一个Lambda表达式,表示输出当前元素到控制台。 完整的代码示例如下: ``` List<String> list = Arrays.asList("apple", "banana", "orange"); list.forEach(System.out::println); ``` 以上代码将遍历集合中的元素,并输出到控制台,输出结果如下: ``` apple banana orange ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值