简体   繁体   English

如何将java.lang.Appendable包装到java.io.Writer中?

[英]How to wrap a java.lang.Appendable into a java.io.Writer?

UPDATE2: My own version of the adapter class, that only calls instanceof in the constructor and uses a (Java 1.5) delta in the flush() and close() functions (avoiding the need for any reflection or logic after object construction), is included at the bottom of this post. UPDATE2:我自己的适配器版本,它只在构造函数中调用instanceof并在flush()close()函数中使用(Java 1.5)delta(避免在构造对象后需要任何反射或逻辑),包含在这篇文章的底部。 UPDATE1: Marc Baumbach wrote a simple Adapter that is exactly what I need. UPDATE1:Marc Baumbach编写了一个简单的适配器,这正是我需要的。 Included below. 包括在下面。 Original question follows. 原始问题如下。


A function that requires a java.lang.Appendable can accept a java.io.Writer , because Writer implements Appendable . 需要java.lang.Appendable函数可以接受java.io.Writer ,因为Writer实现了Appendable

What about the other way around? 反过来呢? I am using a function that requires a writer, and I am trying to create another function that calls it, which accepts an appendable and passes it to the original writer-function. 我正在使用一个需要编写器的函数,我正在尝试创建另一个调用它的函数,它接受一个appendable并将其传递给原始的writer函数。

I see that you can extend Writer , which is abstract, and redirect all write(...) functions to their corresponding append(...) -s. 我看到你可以扩展Writer ,它是抽象的,并将所有的write(...)函数重定向到它们对应的append(...) s。 But you also have to implement flush() and close() , and I'm clear on how to write those cleanly so this wrapper-class can accept any Appendable. 但是你还必须实现flush()close() ,我很清楚如何干净地编写它们,所以这个包装类可以接受任何 Appendable。

I'm surprised there isn't anything already out there, either on the web or stackoverflow, or in an existing library, that addresses this. 令我感到惊讶的是,在网络或stackoverflow上,或者在现有的库中,没有任何东西可以解决这个问题。 At least not that I could find. 至少不是我能找到的。

I'd appreciate a little guidance here. 我很感激这里的一点指导。 Thank you. 谢谢。


Adapter code that answers this question. 回答此问题的适配器代码。 Written by Marc Baumbach (my own version is below): 由Marc Baumbach撰写(我自己的版本如下):

import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.Writer;

public class AppendableWriterAdapter extends Writer {

      private Appendable appendable;

      public AppendableWriterAdapter(Appendable appendable) {
            this.appendable = appendable;
      }

      @Override
      public void write(char[] cbuf, int off, int len) throws IOException {
            appendable.append(String.valueOf(cbuf), off, len);
      }

      @Override
      public void flush() throws IOException {
            if (appendable instanceof Flushable) {
                  ((Flushable) appendable).flush();
            }
      }

      @Override
      public void close() throws IOException {
            flush();
            if (appendable instanceof Closeable) {
                  ((Closeable) appendable).close();
            }
      }

}

Here is my own version, based on Marc's, that only uses instanceof only in the constructor, and a (Java 1.5) delta in flush() and close() . 这是我自己的版本,基于Marc,只在构造函数中使用instanceof ,在flush()close()使用(Java 1.5)delta。 This is to avoid having to use any logic or reflection after object construction. 这是为了避免在对象构造之后使用任何逻辑或反射。 This is also released as a gist : https://gist.github.com/aliteralmind/8494917 这也是一个要点https//gist.github.com/aliteralmind/8494917

This class contains a demo, followed by two do-nothing deltas (one Flushable , one Closeable ), the main function ( newWriterForAppendable(apbl) ), and then the adapter class itself. 这个类包含一个demo,后跟两个do-nothing增量(一个是Flushable ,一个是Closeable ),main函数( newWriterForAppendable(apbl) ),然后是适配器类本身。

   import  java.io.Closeable;
   import  java.io.Flushable;
   import  java.io.IOException;
   import  java.io.Writer;
/**
   <P>{@code java NewWriterForAppendable}.</P>
 **/
public class NewWriterForAppendable  {
   /**
      <P>Demonstrates {@code newWriterForAppendable(apbl)} for creating a new {@code Writer} that wraps around {@code System.out} (writes to the console).</P>
    **/
   public static final void main(String[] igno_red)  {
      try  {
         NewWriterForAppendable.newWriterForAppendable(System.out).write("hello");
      }  catch(IOException iox)  {
         throw  new RuntimeException("WriterForAppendableXmpl", iox);
      }
   }
   /**
      <P>A {@code Flushable} whose {@code flush()} function does nothing. This is used by {@link #newWriterForAppendable(Appendable ap_bl) newWriterForAppendable}{@code (apbl)} as a (Java 1.5) delta.</P>

      @see  #newWriterForAppendable(Appendable) newWriterForAppendable(apbl)
    **/
   public static final Flushable FLUSHABLE_DO_NOTHING = new Flushable()  {
      public void flush()  {
      }
   };
   /**
      <P>A {@code Closeable} whose {@code close()} function does nothing. This is used by {@link #newWriterForAppendable(Appendable ap_bl) newWriterForAppendable}{@code (apbl)} as a (Java 1.5) delta.</P>

      @see  #newWriterForAppendable(Appendable) newWriterForAppendable(apbl)
    **/
   public static final Closeable CLOSEABLE_DO_NOTHING = new Closeable()  {
      public void close()  {
      }
   };
   /**
      <P>Creates a new {@code java.io.Writer} that wraps around a {@code java.lang.Appendable}. It properly {@link java.io.Writer#flush() flush}es and {@link java.io.Writer#close() close}s appendables that happened to also be {@link java.io.Flushable}s and/or {@link java.io.Closeable Closeable}s. This uses {@code instanceof} only in the constructor, and a delta in {@code flush()} and {@code close()}, which avoids having to use any logic or reflection after object construction.</P>

      <P>This function is released as a <A HREF="https://gist.github.com/aliteralmind/8494917">gist</A>, and is an example of the <A HREF="http://en.wikipedia.org/wiki/Adapter_pattern#Object_Adapter_pattern">Object Adapter pattern</A>. Thanks to <A HREF="http://stackoverflow.com/users/1211906/marc-baumbach">Marc Baumbach</A> on <A HREF="http://stackoverflow.com">{@code stackoverflow}</A> for the assistance. See (viewed 1/18/2014)
      <BR> &nbsp; &nbsp; <CODE><A HREF="http://stackoverflow.com/questions/21200421/how-to-wrap-a-java-lang-appendable-into-a-java-io-writer">http://stackoverflow.com/questions/21200421/how-to-wrap-a-java-lang-appendable-into-a-java-io-writer</A></CODE></P>

      @return  A new writer that uses an appendable to do its output.
      @see  #FLUSHABLE_DO_NOTHING
      @see  #CLOSEABLE_DO_NOTHING
    **/
   public static final Writer newWriterForAppendable(Appendable ap_bl)  {
      return  (new WFA(ap_bl));
   }
   private NewWriterForAppendable()  {
      throw  new IllegalStateException("constructor: Do not instantiate.");
   }
}
class WFA extends Writer  {
   private final Appendable apbl;
   private final Flushable  flbl;
   private final Closeable  clbl;
   public WFA(Appendable ap_bl)  {
      if(ap_bl == null)  {
         throw  new NullPointerException("ap_bl");
      }
      apbl = ap_bl;

      //Avoids instanceof at every call to flush() and close()
      flbl = (Flushable)((ap_bl instanceof Flushable) ? ap_bl
         :  NewWriterForAppendable.FLUSHABLE_DO_NOTHING);
      clbl = (Closeable)((ap_bl instanceof Closeable) ? ap_bl
         :  NewWriterForAppendable.CLOSEABLE_DO_NOTHING);
   }
   @Override
   public void write(char[] a_c, int i_ndexStart, int i_ndexEndX) throws IOException {
      apbl.append(String.valueOf(a_c), i_ndexStart, i_ndexEndX);
   }
   @Override
   public Writer append(char c_c) throws IOException {
      apbl.append(c_c);
      return  this;
   }
   @Override
   public Writer append(CharSequence c_q) throws IOException {
      apbl.append(c_q);
      return  this;
   }
   @Override
   public Writer append(CharSequence c_q, int i_ndexStart, int i_ndexEndX) throws IOException  {
      apbl.append(c_q, i_ndexStart, i_ndexEndX);
      return  this;
   }
   @Override
   public void flush() throws IOException {
      flbl.flush();
   }
   @Override
   public void close() throws IOException {
      flush();
      clbl.close();
   }

}

Typically in a Writer , the flush() and close() are there to cleanup any additional writes that may not have been committed or sent to the stream. 通常在Writerflush()close()用于清除可能尚未提交或发送到流的任何其他写入。 By simply redirecting all of the write methods directly to the append methods in the Appendable you won't have to worry about flush() and close() unless your Appendable implements Closeable and/or Flushable . 通过简单地将所有write方法直接重定向到Appendableappend方法,除非你的Appendable实现了Closeable和/或Flushable否则你不必担心flush()close()

A good example is something like BufferedWriter . 一个很好的例子就像BufferedWriter When you are calling write() on that, it may not be sending all of the bytes to the final output/stream immediately. 当你在它上面调用write()时,它可能不会立即将所有字节发送到最终输出/流。 Some bytes may not be sent until you flush() or close() it. flush()close()之前,可能不会发送一些字节。 To be absolutely safe, I would test the wrapped Appendable if it is Closeable or Flushable in the corresponding method and cast it and perform the action as well. 为了绝对安全,我会测试包装的Appendable如果它在相应的方法中是CloseableFlushable并且转换它并执行操作。

This is a pretty standard design pattern called the Adapter pattern . 这是一个非常标准的设计模式,称为适配器模式

Here is what is likely a good implementation for this adapter: http://pastebin.com/GcsxqQxj 以下是适配器的良好实现: http//pastebin.com/GcsxqQxj

You can accept any Appendable and then check if it is a Writer through instanceof . 您可以接受任何Appendable ,然后通过instanceof检查它是否是Writer Then do a downcast and call that function that accepts only Writer . 然后做一个向下转换并调用只接受Writer函数。

example: 例:

public void myMethod(Appendable app) throws InvalidAppendableException {

   if (app instanceof Writer) {
      someObj.thatMethod((Writer) app);
   } else {
      throw new InvalidAppendableException();
   }
}

Google's Guava has a simple utility to do this: CharStreams.asWriter 谷歌的Guava有一个简单的实用程序: CharStreams.asWriter

The implementation is not the fastest ( see ), if you want the best performance, you might want to look at spf4j Streams.asWriter 实现不是最快的( 参见参考资料),如果你想获得最佳性能,你可能想看一下spf4j Streams.asWriter

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM