StackOverflow Weekly - Are you going to have all these high-profile questions?

Keywords: Java JDK less Programming

I found some high-profile and high-profile questions from Stack Overflow.These questions may not normally be encountered, but since the highly focused questions and highly praised answers are generally accepted, they will be more handled in the future, whether at work or in interviews, if we learn in advance.This article is the first week's content with a total of five topics.I will post a public number every day. If you think this series is valuable to you, you are welcome to pay attention to my public number at the end of this article.

 

DAY1. Casts in compound operators

The issue discussed today is "Coercion in Compliance Operators".With +=as an example, I've written the following code, so you can think about why this happens first.

int i = 5;
long j = 10;

i += j; //normal
i = i+j; //Report errors, Incompatible types.

The answer to this question can be found in the Java Language Manual, which reads as follows:

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

A compound assignment expression such as E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2), where T is the type of E1.So, back in this case, the result of i+j is cast to int and assigned to I.

Verification is actually easier, so we can see what happens when we look at the compiled.class file.

As you can see from the.class file, there are two casts.The first is when i+j, since J is a long type, I is promoted to long, which is a familiar process.The second is what we are discussing today, and the result of i+j is strongly converted to the int type.
In this case, we can think a little bit more about it, because in this case, overflowing calculations can be caused by a strong turn, so why don't Java design let it fail?
My guess is that if we get this wrong, let's see what happens.For example, use the += operator in byte or short types.

byte b = 1;
b += 1;

As we assume, there will be an error here because i+1 returns the int type.However, this kind of code is common in practical application scenarios, so if it is true, it will seriously affect the scope of application of composite assignment operators, and the final design may be a comparison of chicken ribs.Therefore, for the sake of universality, only the user can be given the judgment to ensure that no overflow occurs using the composite assignment operator.We should always be aware of this potential risk when applying it.

Original Address

 

DAY2. Are you right about generating random numbers

How do I generate a random number in Java?If your answer is the Random class, it's necessary to keep looking down.Java 7 used Random classes to generate random numbers before. The standard practice after Java 7 is to use the ThreadLocalRandom class with the following code:

ThreadLocalRandom.current().nextInt();

Now that Java 7 is introducing a new class to replace the previous Random class, there are some problems with the way random numbers were generated. Here's a brief description of the differences between the two classes in conjunction with the source code.
The Random class is thread-safe. If multiple threads use a Random instance to generate random numbers at the same time, they will share the same random seed, which can cause concurrency problems and degrade performance. Here's the source code for the next(int bits) method:

protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
}

Seeing that the code is not complex, where random seed seed is of AtomicLong type and uses CAS to update the seed.
Next, look at the ThreadLocalRandom class, where a multithreaded call to ThreadLocalRandom.current() returns the same ThreadLocalRandom instance, but it does not have a multithreaded synchronization problem.See how it updates the code for the seed:

final long nextSeed() {
    Thread t; long r; // read and update per-thread seed
    UNSAFE.putLong(t = Thread.currentThread(), SEED,
                   r = UNSAFE.getLong(t, SEED) + GAMMA);
    return r;
}

You can see that there is no thread synchronization code in it.Thread.currentThread() is used in the guess code for ThreadLocal purposes, so there is no thread security issue.Another advantage of using ThreadLocalRandom is that you don't need your own new object and it's easier to use.If your project is Java 7+ and you are still using Random to generate random numbers, it is recommended that you switch to ThreadLocalRandom.Since it inherits the Random class, it will not have a significant impact on your existing code.

Original Address

 

DAY3. How many ways do InputStream convert to String

How many ways can you think of converting InputStream to String in Java?

String str = "test";
InputStream inputStream = new ByteArrayInputStream(str.getBytes());

1. Read using a ByteArrayOutputStream loop

/** 1. Read using ByteArrayOutputStream loop */
BufferedInputStream bis = new BufferedInputStream(inputStream);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int tmpRes = bis.read();
while(tmpRes != -1) {
    buf.write((byte) tmpRes);
    tmpRes = bis.read();
}
System.out.println(buf.toString());

2. Bulk read using InputStreamReader

/** 2. Bulk read using InputStreamReader */
final char[] buffer = new char[1024];
final StringBuilder out = new StringBuilder();
Reader in = new InputStreamReader(inputStream);
for (; ; ) {
    int rsz = in.read(buffer, 0, buffer.length);
    if (rsz < 0) {
        break;
    }
    out.append(buffer, 0, rsz);
}
System.out.println(out.toString());

3. Use JDK Scanner

/** 3. Using JDK Scanner */
Scanner s = new Scanner(inputStream).useDelimiter("\\A");
String result = s.hasNext() ? s.next() : "";
System.out.println(result);

4. Using the Java 8 Stream API

/** 4. Using the Java 8 Stream API */
result = new BufferedReader(new InputStreamReader(inputStream))
        .lines().collect(Collectors.joining("\n"));
System.out.println(result);

5. Use IOUtils StringWriter

/** 5. Using IOUtils StringWriter */
StringWriter stringWriter = new StringWriter();
IOUtils.copy(inputStream, stringWriter);
System.out.println(stringWriter.toString());

6. Use IOUtils.toString in one step

/** 6. Use IOUtils.toString in one step */
System.out.println(IOUtils.toString(inputStream));

There are six ways to do this, but there are actually more.Summarize these methods briefly.
The first and second methods use the original round-robin reading, which results in a larger amount of code.The third and fourth methods use JDK-encapsulated APIs to significantly reduce the amount of code, while the Stream API allows us to write code in one line, making it easier to write.Finally, using the IOUtils tool class (commons-io library), you know by name that it is dedicated to IO. It also provides two ways. The fifth framework provides a more open and flexible way called the copy method, which means you can copy elsewhere in addition to copying to String.The sixth is full customization, which is designed to turn String. Of course, the result of customization is not flexible, but it is the most convenient and effortless for the need to simply turn String.In fact, our usual programming is the same. Sometimes there is no need to expose too many open choices for a product demand. Providing a simple and rough implementation for the demand may be the best choice.
Finally, add one more sentence, we can usually pay more attention to the framework, when used, take it directly to save time and effort, reduce the amount of code.Of course, if you are interested, we can also learn more about the design and implementation of the internal framework.

Original Address

 

DAY4. Interviewer: Write an example of a memory leak

We all know that Java comes with its own garbage collection mechanism, and memory leaks seem to have little to do with Java programmers.Therefore, writing Java programs is generally easier than C/C++ programs.Remember what the former leader said when he wrote C++ code, "Writing C++ programs is bound to leak, it's just discoverable."So it seems that C/C++ programmers are more bitter, although they often despise Java programmers.
Although Java programs are less likely to have memory leaks, this does not mean they will not.If you go for an interview one day and the interviewer asks you to write an example of a memory leak in Java, do you have any ideas?Let me give you an example of a memory leak.

public final class ClassLoaderLeakExample {
    static volatile boolean running = true;
    /**
     * 1. main Function, logical simplicity simply creates a LongRunningThread thread and accepts the stop instruction
     */
    public static void main(String[] args) throws Exception {
        Thread thread = new LongRunningThread();
        try {
            thread.start();
            System.out.println("Running, press any key to stop.");
            System.in.read();
        } finally {
            running = false;
            thread.join();
        }
    }

    /**
     * 2. Define the LongRunningThread thread, which does relatively simple things by calling the loadAndDiscard method every 100ms
     */
    static final class LongRunningThread extends Thread {
        @Override public void run() {
            while(running) {
                try {
                    loadAndDiscard();
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    System.out.println("Caught InterruptedException, shutting down.");
                    running = false;
                }
            }
        }
    }

    /**
     * 3. Define a class loader - ChildOnlyClassLoader, which is critical in our example.
     * ChildOnlyClassLoader Specially designed to load LoadedInChildClassLoader classes,
     * The logic is simple. Read the.Class file of the LoadedInChildClassLoader class and return the class object.
     */
    static final class ChildOnlyClassLoader extends ClassLoader {
        ChildOnlyClassLoader() {
            super(ClassLoaderLeakExample.class.getClassLoader());
        }

        @Override protected Class<?> loadClass(String name, boolean resolve)
                throws ClassNotFoundException {
            if (!LoadedInChildClassLoader.class.getName().equals(name)) {
                return super.loadClass(name, resolve);
            }
            try {
                Path path = Paths.get(LoadedInChildClassLoader.class.getName()
                        + ".class");
                byte[] classBytes = Files.readAllBytes(path);
                Class<?> c = defineClass(name, classBytes, 0, classBytes.length);
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            } catch (IOException ex) {
                throw new ClassNotFoundException("Could not load " + name, ex);
            }
        }
    }

    /**
     * 4. Write code for the loadAndDiscard method, which is the method called in the LongRunningThread thread.
     * This method creates a ChildOnlyClassLoader object to load the LoadedInChildClassLoader class and assign the result to the child Class variable.
     * childClass Call the newInstance method to create the LoadedInChildClassLoader object.
     * Each time the loadAndDiscard method is called, the LoadedInChildClassLoader class is loaded once and its objects are created.
     */
    static void loadAndDiscard() throws Exception {
        ClassLoader childClassLoader = new ChildOnlyClassLoader();
        Class<?> childClass = Class.forName(
                LoadedInChildClassLoader.class.getName(), true, childClassLoader);
        childClass.newInstance();
    }

    /**
     * 5. Define LoadedInChildClassLoader class
     * A more BytesToLeak byte array is defined in this class, and the initial size is large to simulate the result of a memory leak as soon as possible.
     * Call threadLocal's set method in the class's construction method to store a reference to the object itself.
     */
    public static final class LoadedInChildClassLoader {
        static final byte[] moreBytesToLeak = new byte[1024 * 1024 * 10];

        private static final ThreadLocal<LoadedInChildClassLoader> threadLocal
                = new ThreadLocal<>();

        public LoadedInChildClassLoader() {
            threadLocal.set(this);
        }
    }
}

This is a complete example where you can read the code in the order of the number in the comment.Finally, run the code to execute the following command in the directory where the ClassLoaderLeakExample class is located

javac ClassLoaderLeakExample.java
java -cp . ClassLoaderLeakExample

After running, the error "java.lang.OutOfMemoryError: Java heap space" will be reported in about a minute, such as "Running, press any key to stop."
Briefly comb through the logic, the loadAndDiscard method is constantly called, and each time it is called, the LoadedInChildClassLoader class is loaded once, creating a new threadLocal and moreBytesToLeak attributes for each class load.Although the LoadeedInChildClassLoader object created is a local variable, it will not be recycled after exiting the loadAndDiscard method because threadLocal saves a reference to the object, the object saves a reference to the class, the class saves a reference to the class loader, which in turn saves a reference to the class it has loaded.So while exiting the loadAndDiscard method, the object is invisible to us, but it will never be recycled.As more classes are loaded each time, more and more moreBytesToLeaks are created and memory is not cleaned up, resulting in OutOfMemory errors.

To compare how you can remove the parameter Custom Class Loader, the code in the loadAndDiscard method is modified as follows:

Class<?> childClass = Class.forName(
                LoadedInChildClassLoader.class.getName(), true, childClassLoader);
//Change to:
Class<?> childClass = Class.forName(
                LoadedInChildClassLoader.class.getName());

No more OOM errors will occur.After modification, the LoadedInChildClassLoader class is only loaded once, no matter how many times the loadAndDiscard method is called, that is, there is only one threadLocal and more BytesToLeak attribute.When the LoadedInChildClassLoader object is created again, threadLocal is set to the current object, and no variable references it for the previously set object, so the previous object is recycled.

Original Address

 

DAY5. Why passwords are stored with char[] instead of String

Friday, relax.Let's take a look at the question of why Java programs use char[] to save passwords without String.Now that the password is mentioned, we use our toes to think about it and know it must be for security reasons.Why exactly?Here are two answers for your reference.

First, and most importantly.String stores strings that are immutable, meaning that once you use it to store passwords, this memory cannot be changed artificially.And can only wait for GC to clear it.Passwords may be compromised if other processes maliciously dump down memory.
However, using char [] to store passwords is controllable for us, and we can set the contents of char [] to null or other meaningless characters at any time to ensure that passwords do not reside in memory for a long time.More secure than using String to store passwords.

Secondly, suppose we inadvertently print the password to the log in our program.If String is used to store the password, it will be output in clear text, whereas char[] is used to store the password only to output the address without disclosing the password.
Both of these are security considerations.

The first point focuses more on preventing passwords from residing in memory insecurity, and the second on preventing passwords from residing in external memory.Although the second point is less likely to occur, it also gives us a new perspective.

This is Stack Overflow's first weekly report. I hope it will be useful to you. It will be updated later. If you want to see more of the day, please follow the Public Number.

Welcome to the public number Ferry to share more high quality content

Origin: https://www.cnblogs.com/duma/p/11432736.html

Posted by sandrob57 on Thu, 16 Apr 2020 23:01:11 -0700