If I have understood correctly, you have asked for a way to take outside of the condition? Well, it's not that hard:
while (!links.isEmpty()) {
try {
String link = links.take();
// Do stuff.
} catch (InterruptedException e) {
// Exception handling.
}
}
Your current condition !(link = links.take()).isEmpty() checks if the return value—a string—is empty (length equals 0), not the queue.
Anyhow, please bear in mind that the code above is not atomic, so there's no guarantee that nothing else happens between links.isEmpty() and links.take().
EDIT: You can handle race conditions during the startup with a flag:
BlockingQueue<Integer> numbers = new ArrayBlockingQueue<>(10);
AtomicBoolean flag = new AtomicBoolean(true);
// Producer.
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
numbers.put(i);
} catch (InterruptedException e) { /* NOP */ }
}
flag.set(false);
}).start();
// Consumer.
while (flag.get() || !numbers.isEmpty()) {
try {
System.out.println(numbers.take());
} catch (InterruptedException e) { /* NOP */ }
}
The AtomicBoolean is not necessary here, but it might become handy if you have multiple producers and/or consumers. It's also part of java.util.concurrent which you definitely should checkout.